init pfs-invoices
This commit is contained in:
parent
07a97e1b2c
commit
344477881f
3
.gitignore
vendored
3
.gitignore
vendored
@ -19,3 +19,6 @@ drivers/
|
||||
# Error screenshots generated by TestBench for failed integration tests
|
||||
error-screenshots/
|
||||
webpack.generated.js
|
||||
|
||||
utils/
|
||||
src/main/bundles/
|
||||
|
8
DOC.md
Normal file
8
DOC.md
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
# QR
|
||||
|
||||
For example, can link to the URL:
|
||||
|
||||
https://siat.impuestos.gob.bo/consulta/QR?nit=289026029&cuf=13C6A589EDF26619EB3675A08B8CF1BDF154F3BB
|
||||
|
24
LICENSE.md
24
LICENSE.md
@ -1,24 +0,0 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
@ -1,4 +1,4 @@
|
||||
# Flow CRM Tutorial
|
||||
# PFS invoices
|
||||
|
||||
This project can be used as a starting point to create your own Vaadin application with Spring Boot.
|
||||
It contains all the necessary configuration and some placeholder files to get you started.
|
||||
@ -20,7 +20,7 @@ This will build a JAR file with all the dependencies and front-end resources,
|
||||
ready to be deployed. The file can be found in the `target` folder after the build completes.
|
||||
|
||||
Once the JAR file is built, you can run it using
|
||||
`java -jar target/flowcrmtutorial-1.0-SNAPSHOT.jar`
|
||||
`java -jar target/pfs-invoices-1.0-SNAPSHOT.jar`
|
||||
|
||||
## Project structure
|
||||
|
||||
@ -51,11 +51,11 @@ To build the Dockerized version of the project, run
|
||||
|
||||
```
|
||||
mvn clean package -Pproduction
|
||||
docker build . -t flowcrmtutorial:latest
|
||||
docker build . -t pfs-invoices:latest
|
||||
```
|
||||
|
||||
Once the Docker image is correctly built, you can test it locally using
|
||||
|
||||
```
|
||||
docker run -p 8080:8080 flowcrmtutorial:latest
|
||||
docker run -p 8080:8080 pfs-invoices:latest
|
||||
```
|
||||
|
23
frontend/index.html
Normal file
23
frontend/index.html
Normal file
@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
This file is auto-generated by Vaadin.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style>
|
||||
body, #outlet {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<!-- index.ts is included here automatically (either by the dev server or during the build) -->
|
||||
</head>
|
||||
<body>
|
||||
<!-- This outlet div is where the views are rendered -->
|
||||
<div id="outlet"></div>
|
||||
</body>
|
||||
</html>
|
16070
package-lock.json
generated
Normal file
16070
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
257
package.json
Normal file
257
package.json
Normal file
@ -0,0 +1,257 @@
|
||||
{
|
||||
"name": "no-name",
|
||||
"license": "UNLICENSED",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@polymer/polymer": "3.5.1",
|
||||
"@vaadin-component-factory/vcf-pdf-viewer": "2.0.1",
|
||||
"@vaadin/a11y-base": "24.3.10",
|
||||
"@vaadin/accordion": "24.3.10",
|
||||
"@vaadin/app-layout": "24.3.10",
|
||||
"@vaadin/avatar": "24.3.10",
|
||||
"@vaadin/avatar-group": "24.3.10",
|
||||
"@vaadin/bundles": "24.3.10",
|
||||
"@vaadin/button": "24.3.10",
|
||||
"@vaadin/checkbox": "24.3.10",
|
||||
"@vaadin/checkbox-group": "24.3.10",
|
||||
"@vaadin/combo-box": "24.3.10",
|
||||
"@vaadin/common-frontend": "0.0.19",
|
||||
"@vaadin/component-base": "24.3.10",
|
||||
"@vaadin/confirm-dialog": "24.3.10",
|
||||
"@vaadin/context-menu": "24.3.10",
|
||||
"@vaadin/custom-field": "24.3.10",
|
||||
"@vaadin/date-picker": "24.3.10",
|
||||
"@vaadin/date-time-picker": "24.3.10",
|
||||
"@vaadin/details": "24.3.10",
|
||||
"@vaadin/dialog": "24.3.10",
|
||||
"@vaadin/email-field": "24.3.10",
|
||||
"@vaadin/field-base": "24.3.10",
|
||||
"@vaadin/field-highlighter": "24.3.10",
|
||||
"@vaadin/form-layout": "24.3.10",
|
||||
"@vaadin/grid": "24.3.10",
|
||||
"@vaadin/horizontal-layout": "24.3.10",
|
||||
"@vaadin/icon": "24.3.10",
|
||||
"@vaadin/icons": "24.3.10",
|
||||
"@vaadin/input-container": "24.3.10",
|
||||
"@vaadin/integer-field": "24.3.10",
|
||||
"@vaadin/item": "24.3.10",
|
||||
"@vaadin/list-box": "24.3.10",
|
||||
"@vaadin/lit-renderer": "24.3.10",
|
||||
"@vaadin/login": "24.3.10",
|
||||
"@vaadin/menu-bar": "24.3.10",
|
||||
"@vaadin/message-input": "24.3.10",
|
||||
"@vaadin/message-list": "24.3.10",
|
||||
"@vaadin/multi-select-combo-box": "24.3.10",
|
||||
"@vaadin/notification": "24.3.10",
|
||||
"@vaadin/number-field": "24.3.10",
|
||||
"@vaadin/overlay": "24.3.10",
|
||||
"@vaadin/password-field": "24.3.10",
|
||||
"@vaadin/polymer-legacy-adapter": "24.3.10",
|
||||
"@vaadin/progress-bar": "24.3.10",
|
||||
"@vaadin/radio-group": "24.3.10",
|
||||
"@vaadin/router": "1.7.5",
|
||||
"@vaadin/scroller": "24.3.10",
|
||||
"@vaadin/select": "24.3.10",
|
||||
"@vaadin/side-nav": "24.3.10",
|
||||
"@vaadin/split-layout": "24.3.10",
|
||||
"@vaadin/tabs": "24.3.10",
|
||||
"@vaadin/tabsheet": "24.3.10",
|
||||
"@vaadin/text-area": "24.3.10",
|
||||
"@vaadin/text-field": "24.3.10",
|
||||
"@vaadin/time-picker": "24.3.10",
|
||||
"@vaadin/tooltip": "24.3.10",
|
||||
"@vaadin/upload": "24.3.10",
|
||||
"@vaadin/vaadin-development-mode-detector": "2.0.6",
|
||||
"@vaadin/vaadin-lumo-styles": "24.3.10",
|
||||
"@vaadin/vaadin-material-styles": "24.3.10",
|
||||
"@vaadin/vaadin-themable-mixin": "24.3.10",
|
||||
"@vaadin/vaadin-usage-statistics": "2.1.2",
|
||||
"@vaadin/vertical-layout": "24.3.10",
|
||||
"@vaadin/virtual-list": "24.3.10",
|
||||
"construct-style-sheets-polyfill": "3.1.0",
|
||||
"date-fns": "2.29.3",
|
||||
"lit": "3.1.2",
|
||||
"print-js": "1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-replace": "5.0.5",
|
||||
"@rollup/pluginutils": "5.1.0",
|
||||
"@vitejs/plugin-react": "4.2.1",
|
||||
"@vitejs/plugin-react-swc": "3.5.0",
|
||||
"async": "3.2.4",
|
||||
"glob": "10.3.3",
|
||||
"rollup-plugin-brotli": "3.1.0",
|
||||
"rollup-plugin-visualizer": "5.12.0",
|
||||
"strip-css-comments": "5.0.0",
|
||||
"transform-ast": "2.4.4",
|
||||
"typescript": "5.3.3",
|
||||
"vite": "5.1.7",
|
||||
"vite-plugin-checker": "0.6.4",
|
||||
"workbox-build": "7.0.0",
|
||||
"workbox-core": "7.0.0",
|
||||
"workbox-precaching": "7.0.0"
|
||||
},
|
||||
"vaadin": {
|
||||
"dependencies": {
|
||||
"@polymer/polymer": "3.5.1",
|
||||
"@vaadin-component-factory/vcf-pdf-viewer": "2.0.1",
|
||||
"@vaadin/a11y-base": "24.3.10",
|
||||
"@vaadin/accordion": "24.3.10",
|
||||
"@vaadin/app-layout": "24.3.10",
|
||||
"@vaadin/avatar": "24.3.10",
|
||||
"@vaadin/avatar-group": "24.3.10",
|
||||
"@vaadin/bundles": "24.3.10",
|
||||
"@vaadin/button": "24.3.10",
|
||||
"@vaadin/checkbox": "24.3.10",
|
||||
"@vaadin/checkbox-group": "24.3.10",
|
||||
"@vaadin/combo-box": "24.3.10",
|
||||
"@vaadin/common-frontend": "0.0.19",
|
||||
"@vaadin/component-base": "24.3.10",
|
||||
"@vaadin/confirm-dialog": "24.3.10",
|
||||
"@vaadin/context-menu": "24.3.10",
|
||||
"@vaadin/custom-field": "24.3.10",
|
||||
"@vaadin/date-picker": "24.3.10",
|
||||
"@vaadin/date-time-picker": "24.3.10",
|
||||
"@vaadin/details": "24.3.10",
|
||||
"@vaadin/dialog": "24.3.10",
|
||||
"@vaadin/email-field": "24.3.10",
|
||||
"@vaadin/field-base": "24.3.10",
|
||||
"@vaadin/field-highlighter": "24.3.10",
|
||||
"@vaadin/form-layout": "24.3.10",
|
||||
"@vaadin/grid": "24.3.10",
|
||||
"@vaadin/horizontal-layout": "24.3.10",
|
||||
"@vaadin/icon": "24.3.10",
|
||||
"@vaadin/icons": "24.3.10",
|
||||
"@vaadin/input-container": "24.3.10",
|
||||
"@vaadin/integer-field": "24.3.10",
|
||||
"@vaadin/item": "24.3.10",
|
||||
"@vaadin/list-box": "24.3.10",
|
||||
"@vaadin/lit-renderer": "24.3.10",
|
||||
"@vaadin/login": "24.3.10",
|
||||
"@vaadin/menu-bar": "24.3.10",
|
||||
"@vaadin/message-input": "24.3.10",
|
||||
"@vaadin/message-list": "24.3.10",
|
||||
"@vaadin/multi-select-combo-box": "24.3.10",
|
||||
"@vaadin/notification": "24.3.10",
|
||||
"@vaadin/number-field": "24.3.10",
|
||||
"@vaadin/overlay": "24.3.10",
|
||||
"@vaadin/password-field": "24.3.10",
|
||||
"@vaadin/polymer-legacy-adapter": "24.3.10",
|
||||
"@vaadin/progress-bar": "24.3.10",
|
||||
"@vaadin/radio-group": "24.3.10",
|
||||
"@vaadin/router": "1.7.5",
|
||||
"@vaadin/scroller": "24.3.10",
|
||||
"@vaadin/select": "24.3.10",
|
||||
"@vaadin/side-nav": "24.3.10",
|
||||
"@vaadin/split-layout": "24.3.10",
|
||||
"@vaadin/tabs": "24.3.10",
|
||||
"@vaadin/tabsheet": "24.3.10",
|
||||
"@vaadin/text-area": "24.3.10",
|
||||
"@vaadin/text-field": "24.3.10",
|
||||
"@vaadin/time-picker": "24.3.10",
|
||||
"@vaadin/tooltip": "24.3.10",
|
||||
"@vaadin/upload": "24.3.10",
|
||||
"@vaadin/vaadin-development-mode-detector": "2.0.6",
|
||||
"@vaadin/vaadin-lumo-styles": "24.3.10",
|
||||
"@vaadin/vaadin-material-styles": "24.3.10",
|
||||
"@vaadin/vaadin-themable-mixin": "24.3.10",
|
||||
"@vaadin/vaadin-usage-statistics": "2.1.2",
|
||||
"@vaadin/vertical-layout": "24.3.10",
|
||||
"@vaadin/virtual-list": "24.3.10",
|
||||
"construct-style-sheets-polyfill": "3.1.0",
|
||||
"date-fns": "2.29.3",
|
||||
"lit": "3.1.2",
|
||||
"print-js": "1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-replace": "5.0.5",
|
||||
"@rollup/pluginutils": "5.1.0",
|
||||
"@vitejs/plugin-react": "4.2.1",
|
||||
"@vitejs/plugin-react-swc": "3.5.0",
|
||||
"async": "3.2.4",
|
||||
"glob": "10.3.3",
|
||||
"rollup-plugin-brotli": "3.1.0",
|
||||
"rollup-plugin-visualizer": "5.12.0",
|
||||
"strip-css-comments": "5.0.0",
|
||||
"transform-ast": "2.4.4",
|
||||
"typescript": "5.3.3",
|
||||
"vite": "5.1.7",
|
||||
"vite-plugin-checker": "0.6.4",
|
||||
"workbox-build": "7.0.0",
|
||||
"workbox-core": "7.0.0",
|
||||
"workbox-precaching": "7.0.0"
|
||||
},
|
||||
"hash": "22fa4a03f17449183ffb85c85d2c29db3d0fbd83e7221ee76d18b0a76cffa06f"
|
||||
},
|
||||
"overrides": {
|
||||
"@vaadin/bundles": "$@vaadin/bundles",
|
||||
"@vaadin/a11y-base": "$@vaadin/a11y-base",
|
||||
"@vaadin/accordion": "$@vaadin/accordion",
|
||||
"@vaadin/app-layout": "$@vaadin/app-layout",
|
||||
"@vaadin/avatar": "$@vaadin/avatar",
|
||||
"@vaadin/avatar-group": "$@vaadin/avatar-group",
|
||||
"@vaadin/button": "$@vaadin/button",
|
||||
"@vaadin/checkbox": "$@vaadin/checkbox",
|
||||
"@vaadin/checkbox-group": "$@vaadin/checkbox-group",
|
||||
"@vaadin/combo-box": "$@vaadin/combo-box",
|
||||
"@vaadin/component-base": "$@vaadin/component-base",
|
||||
"@vaadin/confirm-dialog": "$@vaadin/confirm-dialog",
|
||||
"@vaadin/context-menu": "$@vaadin/context-menu",
|
||||
"@vaadin/custom-field": "$@vaadin/custom-field",
|
||||
"@vaadin/date-picker": "$@vaadin/date-picker",
|
||||
"@vaadin/date-time-picker": "$@vaadin/date-time-picker",
|
||||
"@vaadin/details": "$@vaadin/details",
|
||||
"@vaadin/dialog": "$@vaadin/dialog",
|
||||
"@vaadin/email-field": "$@vaadin/email-field",
|
||||
"@vaadin/field-base": "$@vaadin/field-base",
|
||||
"@vaadin/field-highlighter": "$@vaadin/field-highlighter",
|
||||
"@vaadin/form-layout": "$@vaadin/form-layout",
|
||||
"@vaadin/grid": "$@vaadin/grid",
|
||||
"@vaadin/horizontal-layout": "$@vaadin/horizontal-layout",
|
||||
"@vaadin/icon": "$@vaadin/icon",
|
||||
"@vaadin/icons": "$@vaadin/icons",
|
||||
"@vaadin/input-container": "$@vaadin/input-container",
|
||||
"@vaadin/integer-field": "$@vaadin/integer-field",
|
||||
"@vaadin/item": "$@vaadin/item",
|
||||
"@vaadin/list-box": "$@vaadin/list-box",
|
||||
"@vaadin/lit-renderer": "$@vaadin/lit-renderer",
|
||||
"@vaadin/login": "$@vaadin/login",
|
||||
"@vaadin/menu-bar": "$@vaadin/menu-bar",
|
||||
"@vaadin/message-input": "$@vaadin/message-input",
|
||||
"@vaadin/message-list": "$@vaadin/message-list",
|
||||
"@vaadin/multi-select-combo-box": "$@vaadin/multi-select-combo-box",
|
||||
"@vaadin/notification": "$@vaadin/notification",
|
||||
"@vaadin/number-field": "$@vaadin/number-field",
|
||||
"@vaadin/overlay": "$@vaadin/overlay",
|
||||
"@vaadin/password-field": "$@vaadin/password-field",
|
||||
"@vaadin/polymer-legacy-adapter": "$@vaadin/polymer-legacy-adapter",
|
||||
"@vaadin/progress-bar": "$@vaadin/progress-bar",
|
||||
"@vaadin/radio-group": "$@vaadin/radio-group",
|
||||
"@vaadin/scroller": "$@vaadin/scroller",
|
||||
"@vaadin/select": "$@vaadin/select",
|
||||
"@vaadin/side-nav": "$@vaadin/side-nav",
|
||||
"@vaadin/split-layout": "$@vaadin/split-layout",
|
||||
"@vaadin/tabs": "$@vaadin/tabs",
|
||||
"@vaadin/tabsheet": "$@vaadin/tabsheet",
|
||||
"@vaadin/text-area": "$@vaadin/text-area",
|
||||
"@vaadin/text-field": "$@vaadin/text-field",
|
||||
"@vaadin/time-picker": "$@vaadin/time-picker",
|
||||
"@vaadin/tooltip": "$@vaadin/tooltip",
|
||||
"@vaadin/upload": "$@vaadin/upload",
|
||||
"@vaadin/vaadin-development-mode-detector": "$@vaadin/vaadin-development-mode-detector",
|
||||
"@vaadin/vaadin-lumo-styles": "$@vaadin/vaadin-lumo-styles",
|
||||
"@vaadin/vaadin-material-styles": "$@vaadin/vaadin-material-styles",
|
||||
"@vaadin/router": "$@vaadin/router",
|
||||
"@vaadin/vaadin-usage-statistics": "$@vaadin/vaadin-usage-statistics",
|
||||
"@vaadin/vertical-layout": "$@vaadin/vertical-layout",
|
||||
"@vaadin/virtual-list": "$@vaadin/virtual-list",
|
||||
"@vaadin/common-frontend": "$@vaadin/common-frontend",
|
||||
"construct-style-sheets-polyfill": "$construct-style-sheets-polyfill",
|
||||
"lit": "$lit",
|
||||
"@polymer/polymer": "$@polymer/polymer",
|
||||
"@vaadin/vaadin-themable-mixin": "$@vaadin/vaadin-themable-mixin",
|
||||
"date-fns": "$date-fns",
|
||||
"@vaadin-component-factory/vcf-pdf-viewer": "$@vaadin-component-factory/vcf-pdf-viewer",
|
||||
"print-js": "$print-js"
|
||||
}
|
||||
}
|
256
pom.xml
256
pom.xml
@ -2,10 +2,9 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<!-- Project from https://start.vaadin.com/project/746e647f-eaf8-4114-8c75-65de698e1e76 -->
|
||||
<groupId>com.example.application</groupId>
|
||||
<artifactId>flowcrmtutorial</artifactId>
|
||||
<name>flowcrmtutorial</name>
|
||||
<groupId>com.primefactorsolutions</groupId>
|
||||
<artifactId>pfs-invoices</artifactId>
|
||||
<name>pfs-invoices</name>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@ -21,6 +20,15 @@
|
||||
</parent>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<name>Maven Central</name>
|
||||
<layout>default</layout>
|
||||
<url>https://repo1.maven.org/maven2</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>Vaadin Directory</id>
|
||||
<url>https://maven.vaadin.com/vaadin-addons</url>
|
||||
@ -45,8 +53,7 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.vaadin</groupId>
|
||||
<!-- Replace artifactId with vaadin-core to use only free components -->
|
||||
<artifactId>vaadin</artifactId>
|
||||
<artifactId>vaadin-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.vaadin</groupId>
|
||||
@ -68,11 +75,32 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web-services</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
@ -83,11 +111,119 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>8.0.1.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.search</groupId>
|
||||
<artifactId>hibernate-search-mapper-orm</artifactId>
|
||||
<version>7.1.1.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.search</groupId>
|
||||
<artifactId>hibernate-search-backend-lucene</artifactId>
|
||||
<version>7.1.1.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.vaadin</groupId>
|
||||
<artifactId>vaadin-testbench-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.25.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>in.virit</groupId>
|
||||
<artifactId>viritin</artifactId>
|
||||
<version>2.8.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.hypersistence</groupId>
|
||||
<artifactId>hypersistence-utils-hibernate-63</artifactId>
|
||||
<version>3.7.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.vaadin.addons.componentfactory</groupId>
|
||||
<artifactId>vcf-pdf-viewer</artifactId>
|
||||
<version>2.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.openhtmltopdf</groupId>
|
||||
<artifactId>openhtmltopdf-pdfbox</artifactId>
|
||||
<version>1.0.10</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.freemarker</groupId>
|
||||
<artifactId>freemarker</artifactId>
|
||||
<version>2.3.32</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct</artifactId>
|
||||
<version>1.5.5.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-processor</artifactId>
|
||||
<version>1.5.5.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-core</artifactId>
|
||||
<version>9.10.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-queryparser</artifactId>
|
||||
<version>9.10.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>33.1.0-jre</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.14.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jvnet.jaxb</groupId>
|
||||
<artifactId>jaxb-maven-plugin</artifactId>
|
||||
<version>4.0.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jvnet.jaxb</groupId>
|
||||
<artifactId>jaxb-plugins</artifactId>
|
||||
<version>4.0.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.32</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fillumina</groupId>
|
||||
<artifactId>krasa-jaxb-tools</artifactId>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.module</groupId>
|
||||
<artifactId>jackson-module-jakarta-xmlbind-annotations</artifactId>
|
||||
<version>2.17.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<version>4.0.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@ -97,7 +233,109 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-processor</artifactId>
|
||||
<version>1.5.5.final</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.32</version>
|
||||
</path>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok-mapstruct-binding</artifactId>
|
||||
<version>0.2.0</version>
|
||||
</dependency>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jvnet.jaxb</groupId>
|
||||
<artifactId>jaxb-maven-plugin</artifactId>
|
||||
<version>4.0.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate</id>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<args>
|
||||
<arg>-XJsr303Annotations</arg>
|
||||
<arg>-XJsr303Annotations:JSR_349=true</arg>
|
||||
<arg>-XJsr303Annotations:verbose=false</arg>
|
||||
<arg>-XJsr303Annotations:validationAnnotations=jakarta</arg>
|
||||
<arg>-Xsetters</arg>
|
||||
<arg>-Xsetters-mode=direct</arg>
|
||||
</args>
|
||||
<schemaDirectory>src/main/resources/schemas</schemaDirectory>
|
||||
<bindingDirectory>src/main/resources/bindings</bindingDirectory>
|
||||
<generatePackage>com.primefactorsolutions.invoices.xsd</generatePackage>
|
||||
<plugins>
|
||||
<dependency>
|
||||
<groupId>org.jvnet.jaxb</groupId>
|
||||
<artifactId>jaxb-plugins</artifactId>
|
||||
<version>4.0.3</version>
|
||||
</dependency>
|
||||
<plugin>
|
||||
<groupId>com.fillumina</groupId>
|
||||
<artifactId>krasa-jaxb-tools</artifactId>
|
||||
<version>2.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.sun.xml.ws</groupId>
|
||||
<artifactId>jaxws-maven-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>wsimport</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<packageName>com.primefactorsolutions.invoices.wsdl</packageName>
|
||||
<wsdlUrls>
|
||||
<wsdlUrl>https://pilotosiatservicios.impuestos.gob.bo/v2/ServicioFacturacionComputarizada?wsdl</wsdlUrl>
|
||||
</wsdlUrls>
|
||||
<sourceDestDir>${sourcesDir}</sourceDestDir>
|
||||
<destDir>${classesDir}</destDir>
|
||||
<extension>true</extension>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>target/generated-sources/xjc</source>
|
||||
<source>target/generated-sources/wsimport</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.vaadin</groupId>
|
||||
<artifactId>vaadin-maven-plugin</artifactId>
|
||||
@ -139,6 +377,7 @@
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>prepare-frontend</goal>
|
||||
<goal>build-frontend</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
@ -191,6 +430,7 @@
|
||||
<enableAssertions>true</enableAssertions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
32
src/main/bundles/README.md
Normal file
32
src/main/bundles/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
This directory is automatically generated by Vaadin and contains the pre-compiled
|
||||
frontend files/resources for your project (frontend development bundle).
|
||||
|
||||
It should be added to Version Control System and committed, so that other developers
|
||||
do not have to compile it again.
|
||||
|
||||
Frontend development bundle is automatically updated when needed:
|
||||
- an npm/pnpm package is added with @NpmPackage or directly into package.json
|
||||
- CSS, JavaScript or TypeScript files are added with @CssImport, @JsModule or @JavaScript
|
||||
- Vaadin add-on with front-end customizations is added
|
||||
- Custom theme imports/assets added into 'theme.json' file
|
||||
- Exported web component is added.
|
||||
|
||||
If your project development needs a hot deployment of the frontend changes,
|
||||
you can switch Flow to use Vite development server (default in Vaadin 23.3 and earlier versions):
|
||||
- set `vaadin.frontend.hotdeploy=true` in `application.properties`
|
||||
- configure `vaadin-maven-plugin`:
|
||||
```
|
||||
<configuration>
|
||||
<frontendHotdeploy>true</frontendHotdeploy>
|
||||
</configuration>
|
||||
```
|
||||
- configure `jetty-maven-plugin`:
|
||||
```
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<vaadin.frontend.hotdeploy>true</vaadin.frontend.hotdeploy>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
```
|
||||
|
||||
Read more [about Vaadin development mode](https://vaadin.com/docs/next/configuration/development-mode/#pre-compiled-front-end-bundle-for-faster-start-up).
|
BIN
src/main/bundles/dev.bundle
Normal file
BIN
src/main/bundles/dev.bundle
Normal file
Binary file not shown.
@ -1,34 +0,0 @@
|
||||
package com.example.application.data;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class Company extends AbstractEntity {
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "company")
|
||||
@Nullable
|
||||
private List<Contact> employees = new LinkedList<>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<Contact> getEmployees() {
|
||||
return employees;
|
||||
}
|
||||
|
||||
public void setEmployees(List<Contact> employees) {
|
||||
this.employees = employees;
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package com.example.application.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
@Entity
|
||||
public class Contact extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String firstName = "";
|
||||
|
||||
@NotEmpty
|
||||
private String lastName = "";
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "company_id")
|
||||
@NotNull
|
||||
@JsonIgnoreProperties({"employees"})
|
||||
private Company company;
|
||||
|
||||
@NotNull
|
||||
@ManyToOne
|
||||
private Status status;
|
||||
|
||||
@Email
|
||||
@NotEmpty
|
||||
private String email = "";
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return firstName + " " + lastName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Company getCompany() {
|
||||
return company;
|
||||
}
|
||||
|
||||
public void setCompany(Company company) {
|
||||
this.company = company;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package com.example.application.data;
|
||||
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ContactRepository extends JpaRepository<Contact, Long> {
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package com.example.application.data;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class Status extends AbstractEntity {
|
||||
private String name;
|
||||
|
||||
public Status() {
|
||||
|
||||
}
|
||||
|
||||
public Status(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package com.example.application.data;
|
||||
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface StatusRepository extends JpaRepository<Status, Long> {
|
||||
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package com.example.application.views.list;
|
||||
|
||||
import com.vaadin.flow.component.html.H2;
|
||||
import com.vaadin.flow.component.html.Image;
|
||||
import com.vaadin.flow.component.html.Paragraph;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.theme.lumo.LumoUtility.Margin;
|
||||
|
||||
@PageTitle("list")
|
||||
@Route(value = "")
|
||||
public class ListView extends VerticalLayout {
|
||||
|
||||
public ListView() {
|
||||
setSpacing(false);
|
||||
|
||||
Image img = new Image("images/empty-plant.png", "placeholder plant");
|
||||
img.setWidth("200px");
|
||||
add(img);
|
||||
|
||||
H2 header = new H2("This place intentionally left empty");
|
||||
header.addClassNames(Margin.Top.XLARGE, Margin.Bottom.MEDIUM);
|
||||
add(header);
|
||||
add(new Paragraph("It’s a place where you can grow your own UI 🤗"));
|
||||
|
||||
setSizeFull();
|
||||
setJustifyContentMode(JustifyContentMode.CENTER);
|
||||
setDefaultHorizontalComponentAlignment(Alignment.CENTER);
|
||||
getStyle().set("text-align", "center");
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.example.application;
|
||||
package com.primefactorsolutions.invoices;
|
||||
|
||||
import com.vaadin.flow.component.page.AppShellConfigurator;
|
||||
import com.vaadin.flow.theme.Theme;
|
||||
@ -13,7 +13,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
*
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@Theme(value = "flowcrmtutorial")
|
||||
@Theme(value = "pfs")
|
||||
public class Application implements AppShellConfigurator {
|
||||
|
||||
public static void main(String[] args) {
|
@ -0,0 +1,61 @@
|
||||
package com.primefactorsolutions.invoices.beans;
|
||||
|
||||
import com.primefactorsolutions.invoices.xml.adapters.DateTimeXmlAdapter;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlSchemaType;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class CabeceraDTO {
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "9999999999999", inclusive = true)
|
||||
protected long nitEmisor;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 200)
|
||||
protected String razonSocialEmisor;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 25)
|
||||
protected String municipio;
|
||||
@XmlElement(required = true, nillable = true)
|
||||
@Size(min = 1, max = 25)
|
||||
protected String telefono;
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "9999999999", inclusive = true)
|
||||
protected long numeroFactura;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 100)
|
||||
protected String cuf;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 100)
|
||||
protected String cufd;
|
||||
@NotNull
|
||||
@DecimalMin(value = "0", inclusive = true)
|
||||
@DecimalMax(value = "9999", inclusive = true)
|
||||
protected int codigoSucursal;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 500)
|
||||
protected String direccion;
|
||||
@XmlElement(required = true, type = Integer.class, nillable = true)
|
||||
@DecimalMin(value = "0", inclusive = true)
|
||||
@DecimalMax(value = "9999", inclusive = true)
|
||||
protected Integer codigoPuntoVenta;
|
||||
@XmlElement(required = true, type = String.class)
|
||||
@XmlJavaTypeAdapter(DateTimeXmlAdapter.class)
|
||||
@XmlSchemaType(name = "dateTime")
|
||||
@NotNull
|
||||
protected LocalDateTime fechaEmision;
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.primefactorsolutions.invoices.beans;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ClientDTO {
|
||||
@XmlElement(required = true, nillable = true)
|
||||
@Size(min = 1, max = 500)
|
||||
protected String nombreRazonSocial;
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "5", inclusive = true)
|
||||
protected int codigoTipoDocumentoIdentidad;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 20)
|
||||
protected String numeroDocumento;
|
||||
@XmlElement(required = true, nillable = true)
|
||||
@Size(max = 5)
|
||||
protected String complemento;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 500)
|
||||
protected String direccionComprador;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 100)
|
||||
protected String codigoCliente;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 500)
|
||||
protected String lugarDestino;
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "212", inclusive = true)
|
||||
protected int codigoPais;
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "308", inclusive = true)
|
||||
protected int codigoMetodoPago;
|
||||
@XmlElement(required = true, type = Long.class, nillable = true)
|
||||
@DecimalMin(value = "0", inclusive = true)
|
||||
@DecimalMax(value = "9999999999999999", inclusive = true)
|
||||
protected Long numeroTarjeta;
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.primefactorsolutions.invoices.beans;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
@Data
|
||||
public class DetalleDTO {
|
||||
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 10)
|
||||
protected String actividadEconomica;
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "99999999", inclusive = true)
|
||||
protected int codigoProductoSin;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 50)
|
||||
protected String codigoProducto;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 500)
|
||||
protected String descripcion;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
protected BigInteger cantidad;
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "200", inclusive = true)
|
||||
protected int unidadMedida;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@DecimalMin(value = "0", inclusive = false)
|
||||
@Digits(integer = 20, fraction = 5)
|
||||
protected BigDecimal precioUnitario;
|
||||
@XmlElement(required = true, nillable = true)
|
||||
@DecimalMin(value = "0", inclusive = true)
|
||||
@Digits(integer = 20, fraction = 5)
|
||||
protected BigDecimal montoDescuento;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@DecimalMin(value = "0", inclusive = false)
|
||||
@Digits(integer = 20, fraction = 5)
|
||||
protected BigDecimal subTotal;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.primefactorsolutions.invoices.beans;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class TotalesDTO {
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@DecimalMin(value = "0", inclusive = false)
|
||||
@Digits(integer = 17, fraction = 2)
|
||||
protected BigDecimal montoTotal;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
protected BigDecimal montoTotalSujetoIva;
|
||||
@XmlElement(required = true)
|
||||
@NotNull
|
||||
@DecimalMin(value = "0", inclusive = false)
|
||||
@Digits(integer = 17, fraction = 2)
|
||||
protected BigDecimal montoTotalMoneda;
|
||||
@XmlElement(required = true, nillable = true)
|
||||
@Size(min = 1, max = 10000)
|
||||
protected String informacionAdicional;
|
||||
@XmlElement(required = true, nillable = true)
|
||||
@DecimalMin(value = "0", inclusive = true)
|
||||
@Digits(integer = 17, fraction = 2)
|
||||
protected BigDecimal descuentoAdicional;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.primefactorsolutions.invoices.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.io.Resources;
|
||||
import com.primefactorsolutions.invoices.model.Help;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Configuration
|
||||
public class ApplicationConfig {
|
||||
@Bean
|
||||
public Help getHelp() throws IOException {
|
||||
var url = Resources.getResource("help/ComercialExportacionServicio.json");
|
||||
var objectMapper = new ObjectMapper();
|
||||
return objectMapper.readValue(url, Help.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.primefactorsolutions.invoices.config;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Client;
|
||||
import com.primefactorsolutions.invoices.model.Product;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.Data;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.hibernate.search.mapper.orm.Search;
|
||||
import org.hibernate.search.mapper.orm.massindexing.MassIndexer;
|
||||
import org.hibernate.search.mapper.orm.session.SearchSession;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Component
|
||||
@Data
|
||||
@Log4j2
|
||||
public class ApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {
|
||||
private final EntityManager entityManager;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
var indexed = new Class[]{Client.class, Product.class};
|
||||
log.info("Indexing tables {}", Arrays.stream(indexed).toList());
|
||||
SearchSession searchSession = Search.session(entityManager);
|
||||
MassIndexer indexer = searchSession.massIndexer(indexed)
|
||||
.threadsToLoadObjects(4);
|
||||
|
||||
try {
|
||||
indexer.startAndWait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.primefactorsolutions.invoices.config;
|
||||
|
||||
import com.primefactorsolutions.invoices.views.LoginView;
|
||||
import com.vaadin.flow.spring.security.VaadinWebSecurity;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.ldap.LdapBindAuthenticationManagerFactory;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
public class SecurityConfig extends VaadinWebSecurity {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(auth ->
|
||||
auth.requestMatchers(
|
||||
AntPathRequestMatcher.antMatcher(HttpMethod.GET, "/images/*.png")).permitAll());
|
||||
super.configure(http);
|
||||
setLoginView(http, LoginView.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() {
|
||||
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://ldap.primefactorsolutions.com:389/dc=primefactorsolutions,dc=com");
|
||||
contextSource.setCacheEnvironmentProperties(false);
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserDnPatterns("uid={0},ou=users");
|
||||
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.primefactorsolutions.invoices.data;
|
||||
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Client;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ClientRepository extends JpaRepository<Client, UUID> {
|
||||
List<Client> findByCorreoElectronicoLike(String correoElectronico);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.example.application.data;
|
||||
package com.primefactorsolutions.invoices.data;
|
||||
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Company;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface CompanyRepository extends JpaRepository<Company, Long> {
|
@ -0,0 +1,9 @@
|
||||
package com.primefactorsolutions.invoices.data;
|
||||
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Invoice;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.primefactorsolutions.invoices.data;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Media;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MediaRepository extends JpaRepository<Media, Long> {
|
||||
|
||||
List<Media> findByNameLike(String name);
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.primefactorsolutions.invoices.data;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Product;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ProductRepository extends JpaRepository<Product, UUID> {
|
||||
|
||||
List<Product> findByDescripcionLike(String descripcion);
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.primefactorsolutions.invoices.data;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, UUID> {
|
||||
}
|
@ -1,29 +1,28 @@
|
||||
package com.example.application.data;
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.Version;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@MappedSuperclass
|
||||
public abstract class AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idgenerator")
|
||||
// The initial value is to account for data.sql demo data ids
|
||||
@SequenceGenerator(name = "idgenerator", initialValue = 1000)
|
||||
private Long id;
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
public Long getId() {
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Entity
|
||||
public class Branch extends AbstractEntity {
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "company_id")
|
||||
@NotNull
|
||||
private Company company;
|
||||
|
||||
@NotNull
|
||||
@DecimalMin(value = "0", inclusive = true)
|
||||
@DecimalMax(value = "9999", inclusive = true)
|
||||
protected int codigoSucursal;
|
||||
|
||||
protected String cuis;
|
||||
|
||||
protected String description;
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.*;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Entity
|
||||
@Indexed
|
||||
public class Client extends AbstractEntity {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "company_id")
|
||||
@NotNull
|
||||
private Company company;
|
||||
|
||||
@NotNull
|
||||
@FullTextField
|
||||
private Status status;
|
||||
|
||||
@Email
|
||||
@NotEmpty
|
||||
@FullTextField
|
||||
private String correoElectronico;
|
||||
|
||||
@DecimalMin(value = "0", inclusive = true)
|
||||
@DecimalMax(value = "999999999999", inclusive = true)
|
||||
private Long telefono;
|
||||
|
||||
@XmlElement(required = true, nillable = true)
|
||||
@Size(min = 1, max = 500)
|
||||
@FullTextField
|
||||
protected String nombreRazonSocial;
|
||||
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "5", inclusive = true)
|
||||
protected int codigoTipoDocumentoIdentidad;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1, max = 20)
|
||||
protected String numeroDocumento;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1, max = 500)
|
||||
protected String direccionComprador;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1, max = 100)
|
||||
protected String codigoCliente;
|
||||
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "212", inclusive = true)
|
||||
protected int codigoPais;
|
||||
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "308", inclusive = true)
|
||||
protected int codigoMetodoPago;
|
||||
|
||||
@DecimalMin(value = "0", inclusive = true)
|
||||
@DecimalMax(value = "9999999999999999", inclusive = true)
|
||||
protected Long numeroTarjeta;
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import io.hypersistence.utils.hibernate.type.json.JsonType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Entity
|
||||
public class Company extends AbstractEntity {
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "9999999999999", inclusive = true)
|
||||
protected long nitEmisor;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1, max = 200)
|
||||
protected String razonSocialEmisor;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1, max = 25)
|
||||
protected String municipio;
|
||||
|
||||
@Size(min = 1, max = 25)
|
||||
protected String telefono;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1, max = 500)
|
||||
protected String direccion;
|
||||
|
||||
@Type(JsonType.class)
|
||||
@Column(columnDefinition = "json")
|
||||
private Map<String, Object> properties;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class CurrencyPair {
|
||||
private CurrencyType base;
|
||||
private CurrencyType quote;
|
||||
|
||||
// the price that the forex broker will BUY the base currency from you
|
||||
private BigDecimal bid;
|
||||
|
||||
// the price that the broker will SELL you the base currency in exchange for the quote or counter currency
|
||||
private BigDecimal ask;
|
||||
|
||||
public enum CurrencyType {
|
||||
BOB,
|
||||
USD,
|
||||
EUR;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import io.hypersistence.utils.hibernate.type.json.JsonType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Setter
|
||||
@Getter
|
||||
public class Event extends AbstractEntity{
|
||||
private UUID userId;
|
||||
private UUID entityId;
|
||||
private Instant timestamp;
|
||||
|
||||
@Type(JsonType.class)
|
||||
@Column(columnDefinition = "json")
|
||||
private Map<String, Object> properties;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record Help(List<Section> sections) {
|
||||
public record Section(String name, List<Entry> entries) {
|
||||
}
|
||||
|
||||
public record Entry(String name, String text) {
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import io.hypersistence.utils.hibernate.type.json.JsonType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.*;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Entity
|
||||
public class Invoice extends AbstractEntity {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "company_id")
|
||||
@NotNull
|
||||
private Company company;
|
||||
|
||||
@NotNull
|
||||
private InvoiceStatus status;
|
||||
|
||||
@NotNull
|
||||
protected LocalDateTime fechaEmision;
|
||||
|
||||
@Size(min = 1, max = 500)
|
||||
protected String nombreRazonSocial;
|
||||
|
||||
@Type(JsonType.class)
|
||||
@Column(columnDefinition = "json")
|
||||
private Object payload;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
|
||||
public enum InvoiceStatus {
|
||||
DRAFT,
|
||||
PENDING,
|
||||
SUBMITTED,
|
||||
FAILED
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum InvoiceType {
|
||||
FACTURA_ELECTRONICA_COMPRA_VENTA_TASAS,
|
||||
FACTURA_ELECTRONICA_COMERCIAL_EXPORTACION_MINERA,
|
||||
FACTURA_ELECTRONICA_IMPORTACION_COMERCIALIZACION_LUBRICANTES_IEHD,
|
||||
NOTA_ELECTRONICA_CREDITO_DEBITO_DESCUENTO,
|
||||
FACTURA_ELECTRONICA_SERVICIO_TURISTICO_HOSPEDAJE,
|
||||
FACTURA_ELECTRONICA_DUTTY_FREE,
|
||||
FACTURA_ELECTRONICA_SECTOR_EDUCATIVO_Z_F,
|
||||
FACTURA_ELECTRONICA_COMERCIALIZACION_GN_GLP,
|
||||
FACTURA_ELECTRONICA_PREVALORADA_S_D,
|
||||
FACTURA_ELECTRONICA_PREVALORADA,
|
||||
FACTURA_ELECTRONICA_ALQUILER_BIEN_INMUEBLE,
|
||||
FACTURA_ELECTRONICA_HIDROCARBURO_ALCANZADA_IEHD,
|
||||
FACTURA_ELECTRONICA_ENTIDAD_FINANCIERA,
|
||||
FACTURA_ELECTRONICA_COMERCIALIZACION_GNV,
|
||||
FACTURA_ELECTRONICA_ZONA_FRANCA,
|
||||
FACTURA_ELECTRONICA_SERVICIO_BASICO,
|
||||
NOTA_COMPUTARIZADA_CREDITO_DEBITO,
|
||||
FACTURA_ELECTRONICA_BOLETO_AEREO,
|
||||
FACTURA_ELECTRONICA_VENTA_MINERAL,
|
||||
NOTA_ELECTRONICA_CREDITO_DEBITO_ICE,
|
||||
FACTURA_ELECTRONICA_HIDROCARBURO_NO_ALCANZADA_IEHD,
|
||||
FACTURA_ELECTRONICA_IMPORTACION_COMERCIALIZACION_LUBRICANTES,
|
||||
FACTURA_ELECTRONICA_SERVICIO_BASICO_ZF,
|
||||
FACTURA_ELECTRONICA_COMPRA_VENTA,
|
||||
NOTA_COMPUTARIZADA_CREDITO_DEBITO_ICE,
|
||||
FACTURA_ELECTRONICA_SEGUROS,
|
||||
FACTURA_ELECTRONICA_VENTA_MINERAL_B_C_B,
|
||||
FACTURA_ELECTRONICA_COMERCIAL_EXPORTACION,
|
||||
FACTURA_ELECTRONICA_HOSPITAL_CLINICA_Z_F,
|
||||
FACTURA_ELECTRONICA_TELECOMUNICACION_Z_F,
|
||||
FACTURA_ELECTRONICA_TELECOMUNICACION,
|
||||
FACTURA_ELECTRONICA_HOSPITAL_CLINICA,
|
||||
FACTURA_ELECTRONICA_SUMINISTRO_ENERGIA,
|
||||
FACTURA_ELECTRONICA_HOTEL,
|
||||
FACTURA_ELECTRONICA_ENGARRAFADORAS,
|
||||
FACTURA_ELECTRONICA_SEGURIDAD_ALIMENTARIA,
|
||||
NOTA_COMPUTARIZADA_CREDITO_DEBITO_DESCUENTO,
|
||||
FACTURA_ELECTRONICA_JUEGO_AZAR,
|
||||
FACTURA_ELECTRONICA_LIBRE_CONSIGNACION,
|
||||
FACTURA_ELECTRONICA_COMERCIALIZACION_HIDROCARBURO,
|
||||
FACTURA_ELECTRONICA_COMERCIAL_EXPORTACION_P_VENTA,
|
||||
FACTURA_ELECTRONICA_COMERCIAL_EXPORTACION_SERVICIO,
|
||||
FACTURA_ELECTRONICA_TASA_CERO,
|
||||
NOTA_COMPUTARIZADA_CONCILIACION,
|
||||
FACTURA_ELECTRONICA_MONEDA_EXTRANJERA,
|
||||
FACTURA_ELECTRONICA_SECTOR_EDUCATIVO,
|
||||
FACTURA_ELECTRONICA_COMERCIAL_EXPORTACION_HIDRO,
|
||||
FACTURA_ELECTRONICA_ALQUILER_Z_F,
|
||||
FACTURA_ELECTRONICA_ALCANZADA_ICE,
|
||||
NOTA_ELECTRONICA_CREDITO_DEBITO,
|
||||
FACTURA_ELECTRONICA_COMPRA_VENTA_BON,
|
||||
NOTA_ELECTRONICA_CONCILIACION;
|
||||
|
||||
public String getDisplayName() {
|
||||
return Arrays.stream(this.name().replace("FACTURA_ELECTRONICA", "")
|
||||
.replace("_", " ")
|
||||
.split(" "))
|
||||
.map(String::toLowerCase)
|
||||
.map(StringUtils::capitalize)
|
||||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import io.hypersistence.utils.hibernate.type.json.JsonType;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Entity
|
||||
@Setter
|
||||
@Getter
|
||||
public class Media extends AbstractEntity{
|
||||
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
@Lob
|
||||
private byte[] content;
|
||||
|
||||
@Type(JsonType.class)
|
||||
@Column(columnDefinition = "json")
|
||||
private Map<String, Object> properties;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "company_id")
|
||||
@NotNull
|
||||
private Company company;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
public enum POSType {
|
||||
COMISIONISTA,
|
||||
VENTANILLA_DE_COBRANZA,
|
||||
MOVILES,
|
||||
YPFB,
|
||||
CAJEROS,
|
||||
CONJUNTA;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.DecimalMax;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Entity
|
||||
public class PointOfSale extends AbstractEntity {
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "company_id")
|
||||
@NotNull
|
||||
private Company company;
|
||||
|
||||
@NotNull
|
||||
@DecimalMin(value = "0", inclusive = true)
|
||||
@DecimalMax(value = "9999", inclusive = true)
|
||||
protected int codigoSucursal;
|
||||
|
||||
@DecimalMin(value = "0", inclusive = true)
|
||||
@DecimalMax(value = "9999", inclusive = true)
|
||||
protected Integer codigoPuntoVenta;
|
||||
|
||||
protected POSType codigoTipoPuntoVenta;
|
||||
|
||||
protected String cuis;
|
||||
|
||||
protected String description;
|
||||
|
||||
protected String nombrePuntoVenta;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Entity
|
||||
@Indexed
|
||||
public class Product extends AbstractEntity {
|
||||
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "99999999", inclusive = true)
|
||||
protected int codigoProductoSin;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1, max = 50)
|
||||
protected String codigoProducto;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1, max = 500)
|
||||
protected String descripcion;
|
||||
|
||||
@NotNull
|
||||
@DecimalMin(value = "1", inclusive = true)
|
||||
@DecimalMax(value = "200", inclusive = true)
|
||||
protected int unidadMedida;
|
||||
|
||||
@NotNull
|
||||
@DecimalMin(value = "0", inclusive = false)
|
||||
@Digits(integer = 20, fraction = 5)
|
||||
protected BigDecimal precioUnitario;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "company_id")
|
||||
@NotNull
|
||||
private Company company;
|
||||
|
||||
@NotNull
|
||||
private Status status;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
public enum Role {
|
||||
ADMIN,
|
||||
REGULAR
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
public enum Status {
|
||||
ACTIVE,
|
||||
DISABLED
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import io.hypersistence.utils.hibernate.type.json.JsonType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity
|
||||
@Setter
|
||||
@Getter
|
||||
public class Task extends AbstractEntity{
|
||||
|
||||
@NotBlank
|
||||
private BigInteger nitEmisor;
|
||||
|
||||
@Type(JsonType.class)
|
||||
@Column(columnDefinition = "json")
|
||||
private Map<String, Object> properties;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.primefactorsolutions.invoices.model;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Entity
|
||||
@Table(name = "user_")
|
||||
@Data
|
||||
public class User extends AbstractEntity {
|
||||
@NotBlank
|
||||
private String email;
|
||||
@NotBlank
|
||||
private String fullName;
|
||||
|
||||
private Role role;
|
||||
|
||||
@NotNull
|
||||
private Status status;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "company_id")
|
||||
@NotNull
|
||||
private Company company;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.primefactorsolutions.invoices.model.mappers;
|
||||
|
||||
import com.primefactorsolutions.invoices.beans.CabeceraDTO;
|
||||
import com.primefactorsolutions.invoices.beans.ClientDTO;
|
||||
import com.primefactorsolutions.invoices.beans.TotalesDTO;
|
||||
import com.primefactorsolutions.invoices.model.Company;
|
||||
import com.primefactorsolutions.invoices.xsd.FacturaComputarizadaComercialExportacionServicio;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface CabeceraMapper {
|
||||
CabeceraMapper INSTANCE = Mappers.getMapper(CabeceraMapper.class);
|
||||
|
||||
FacturaComputarizadaComercialExportacionServicio.Cabecera cabeceraFromDtos(CabeceraDTO cabeceraDTO,
|
||||
ClientDTO clientDTO,
|
||||
TotalesDTO totalesDTO);
|
||||
|
||||
CabeceraDTO cabeceraDtoFromCompany(Company company);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.primefactorsolutions.invoices.model.mappers;
|
||||
|
||||
import com.primefactorsolutions.invoices.beans.ClientDTO;
|
||||
import com.primefactorsolutions.invoices.model.Client;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface ClientMapper {
|
||||
ClientMapper INSTANCE = Mappers.getMapper(ClientMapper.class);
|
||||
|
||||
ClientDTO clientDtoFromClient(Client client);
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.primefactorsolutions.invoices.model.mappers;
|
||||
|
||||
import com.primefactorsolutions.invoices.beans.DetalleDTO;
|
||||
import com.primefactorsolutions.invoices.xsd.FacturaComputarizadaComercialExportacionServicio;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface DetalleMapper {
|
||||
DetalleMapper INSTANCE = Mappers.getMapper(DetalleMapper.class);
|
||||
|
||||
FacturaComputarizadaComercialExportacionServicio.Detalle detalleFromDto(DetalleDTO detalleDTO);
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.primefactorsolutions.invoices.model.validators;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.primefactorsolutions.invoices.xsd.FacturaComputarizadaComercialExportacionServicio;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FacturaComputarizadaComercialExportacionServicioValidator implements InvoiceValidator<FacturaComputarizadaComercialExportacionServicio> {
|
||||
|
||||
@Override
|
||||
public List<ValidationError> validate(FacturaComputarizadaComercialExportacionServicio invoice) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.primefactorsolutions.invoices.model.validators;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface InvoiceValidator<T> {
|
||||
List<ValidationError> validate(T invoice);
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.primefactorsolutions.invoices.model.validators;
|
||||
|
||||
public record ValidationError(String field, String message) {
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.primefactorsolutions.invoices.security;
|
||||
|
||||
import com.vaadin.flow.spring.security.AuthenticationContext;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class SecurityService {
|
||||
|
||||
private final AuthenticationContext authenticationContext;
|
||||
|
||||
public SecurityService(AuthenticationContext authenticationContext) {
|
||||
this.authenticationContext = authenticationContext;
|
||||
}
|
||||
|
||||
public Optional<UserDetails> getAuthenticatedUser() {
|
||||
return authenticationContext.getAuthenticatedUser(UserDetails.class);
|
||||
}
|
||||
|
||||
public void logout() {
|
||||
authenticationContext.logout();
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.primefactorsolutions.invoices.services;
|
||||
|
||||
import com.primefactorsolutions.invoices.data.ClientRepository;
|
||||
import com.primefactorsolutions.invoices.model.Client;
|
||||
import com.primefactorsolutions.invoices.model.Status;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.Data;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.hibernate.search.engine.search.query.SearchResult;
|
||||
import org.hibernate.search.mapper.orm.Search;
|
||||
import org.hibernate.search.mapper.orm.session.SearchSession;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@Data
|
||||
@Log4j2
|
||||
public class ClientService {
|
||||
private final ClientRepository clientRepository;
|
||||
private final EntityManager entityManager;
|
||||
private final CompanyService companyService;
|
||||
|
||||
@Transactional
|
||||
public List<Client> findAllClients(String code) {
|
||||
return findAllClients(code, PageRequest.of(0, 25));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Client> findAllClients(String code, PageRequest of) {
|
||||
if (Strings.isBlank(code)) {
|
||||
return clientRepository.findAll();
|
||||
}
|
||||
|
||||
SearchSession searchSession = Search.session(entityManager);
|
||||
SearchResult<Client> result = searchSession.search(Client.class)
|
||||
.where(f -> f.match()
|
||||
.fields("nombreRazonSocial", "correoElectronico")
|
||||
.matching(code))
|
||||
.fetch(20);
|
||||
|
||||
long totalHitCount = result.total().hitCount();
|
||||
|
||||
log.info("Found {} results", totalHitCount);
|
||||
|
||||
return result.hits();
|
||||
}
|
||||
|
||||
public void saveOrUpdateClient(Client updatedClient) {
|
||||
updatedClient.setCompany(companyService.getCompany());
|
||||
updatedClient.setStatus(Status.ACTIVE);
|
||||
|
||||
clientRepository.save(updatedClient);
|
||||
}
|
||||
|
||||
public Client getClient(UUID uuid) {
|
||||
return clientRepository.findById(uuid)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Client not found"));
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.primefactorsolutions.invoices.services;
|
||||
|
||||
import com.primefactorsolutions.invoices.data.CompanyRepository;
|
||||
import com.primefactorsolutions.invoices.model.Company;
|
||||
import lombok.Data;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Data
|
||||
public class CompanyService {
|
||||
private final CompanyRepository companyRepository;
|
||||
|
||||
public Company getCompany() {
|
||||
return companyRepository.findAll().stream().findFirst().get();
|
||||
}
|
||||
|
||||
public void saveOrUpdateCompany(final Company company) {
|
||||
companyRepository.save(company);
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package com.primefactorsolutions.invoices.services;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.openhtmltopdf.pdfboxout.PdfBoxRenderer;
|
||||
import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
|
||||
import com.primefactorsolutions.invoices.data.InvoiceRepository;
|
||||
import com.primefactorsolutions.invoices.data.MediaRepository;
|
||||
import com.primefactorsolutions.invoices.model.Help;
|
||||
import com.primefactorsolutions.invoices.model.Invoice;
|
||||
import com.primefactorsolutions.invoices.model.InvoiceStatus;
|
||||
import com.primefactorsolutions.invoices.model.Media;
|
||||
import com.primefactorsolutions.invoices.xsd.FacturaComputarizadaComercialExportacionServicio;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.DefaultObjectWrapper;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateExceptionHandler;
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.Data;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.apache.pdfbox.io.MemoryUsageSetting;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@Service
|
||||
@Data
|
||||
@Log4j2
|
||||
public class InvoiceService {
|
||||
private final Help help;
|
||||
private final InvoiceRepository invoiceRepository;
|
||||
private final MediaRepository mediaRepository;
|
||||
private final CompanyService companyService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public List<Invoice> findAllInvoices() {
|
||||
return invoiceRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void sendInvoice(FacturaComputarizadaComercialExportacionServicio factura) {
|
||||
|
||||
try(var os = new ByteArrayOutputStream()) {
|
||||
writeAsPdf(factura, os);
|
||||
var media = new Media();
|
||||
media.setName("factura.pdf");
|
||||
media.setContent(os.toByteArray());
|
||||
|
||||
mediaRepository.save(media);
|
||||
} catch (IOException e) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
var invoice = new Invoice();
|
||||
invoice.setStatus(InvoiceStatus.DRAFT);
|
||||
invoice.setFechaEmision(LocalDateTime.ofInstant(Instant.now(), ZoneId.of("UTC")));
|
||||
invoice.setCompany(companyService.getCompany());
|
||||
invoice.setNombreRazonSocial(factura.getCabecera().getNombreRazonSocial());
|
||||
|
||||
try {
|
||||
invoice.setPayload(objectMapper.writeValueAsString(factura));
|
||||
} catch (JsonProcessingException e) {
|
||||
log.info("Error writing invoice JSON");
|
||||
}
|
||||
|
||||
invoiceRepository.save(invoice);
|
||||
}
|
||||
|
||||
|
||||
protected static InputStream getTemplate() {
|
||||
return getDefaultTemplate();
|
||||
}
|
||||
|
||||
public static InputStream getDefaultTemplate() {
|
||||
return Invoice.class.getResourceAsStream("/pfs-invoice.html");
|
||||
}
|
||||
|
||||
public void writeAsPdf(FacturaComputarizadaComercialExportacionServicio factura, OutputStream out) {
|
||||
|
||||
try {
|
||||
var in = getTemplate();
|
||||
Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
|
||||
// cfg.setDirectoryForTemplateLoading(new File("/where/you/store/templates"));
|
||||
// Recommended settings for new projects:
|
||||
cfg.setDefaultEncoding("UTF-8");
|
||||
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||
cfg.setLogTemplateExceptions(false);
|
||||
cfg.setWrapUncheckedExceptions(true);
|
||||
cfg.setFallbackOnNullLoopVariable(false);
|
||||
cfg.setSQLDateAndTimeTimeZone(TimeZone.getDefault());
|
||||
|
||||
Reader reader = new InputStreamReader(in);
|
||||
Template temp = new Template("pfs-invoice", reader, cfg);
|
||||
|
||||
DefaultObjectWrapper wrapper = new DefaultObjectWrapper();
|
||||
ByteArrayOutputStream oo = new ByteArrayOutputStream();
|
||||
Writer outTemplate = new OutputStreamWriter(oo);
|
||||
|
||||
temp.process(wrapper.wrap(factura), outTemplate);
|
||||
|
||||
PdfRendererBuilder builder = new PdfRendererBuilder();
|
||||
builder.usePDDocument(new PDDocument(MemoryUsageSetting.setupMixed(1000000)));
|
||||
builder.withHtmlContent(oo.toString(StandardCharsets.UTF_8), "/test");
|
||||
builder.toStream(out);
|
||||
|
||||
try (PdfBoxRenderer pdfBoxRenderer = builder.buildPdfRenderer()) {
|
||||
pdfBoxRenderer.layout();
|
||||
pdfBoxRenderer.createPDF();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Help getHelp() {
|
||||
return help;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.primefactorsolutions.invoices.services;
|
||||
|
||||
import com.primefactorsolutions.invoices.data.MediaRepository;
|
||||
import com.primefactorsolutions.invoices.model.Media;
|
||||
import lombok.Data;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Data
|
||||
public class MediaService {
|
||||
private final MediaRepository mediaRepository;
|
||||
|
||||
public Media findMedia(String name) {
|
||||
return mediaRepository.findAll().stream().findFirst().get();
|
||||
}
|
||||
|
||||
public List<Media> findAllMedia(String name) {
|
||||
return mediaRepository.findByNameLike(name);
|
||||
}
|
||||
|
||||
public void saveMedia(Media media) {
|
||||
mediaRepository.save(media);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.primefactorsolutions.invoices.services;
|
||||
|
||||
import com.primefactorsolutions.invoices.data.ProductRepository;
|
||||
import com.primefactorsolutions.invoices.model.Product;
|
||||
import com.primefactorsolutions.invoices.model.Status;
|
||||
import lombok.Data;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@Data
|
||||
public class ProductService {
|
||||
private final ProductRepository productRepository;
|
||||
private final CompanyService companyService;
|
||||
|
||||
public List<Product> findAllProducts(String name) {
|
||||
return productRepository.findAll();
|
||||
}
|
||||
|
||||
public void saveOrUpdateProduct(Product product) {
|
||||
var company = companyService.getCompany();
|
||||
product.setCompany(company);
|
||||
product.setStatus(Status.ACTIVE);
|
||||
productRepository.save(product);
|
||||
}
|
||||
|
||||
public Product getProduct(UUID uuid) {
|
||||
return productRepository.findById(uuid).get();
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.primefactorsolutions.invoices.services;
|
||||
|
||||
import com.primefactorsolutions.invoices.data.UserRepository;
|
||||
import com.primefactorsolutions.invoices.model.Role;
|
||||
import com.primefactorsolutions.invoices.model.Status;
|
||||
import com.primefactorsolutions.invoices.model.User;
|
||||
import lombok.Data;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@Data
|
||||
public class UserService {
|
||||
private final UserRepository userRepository;
|
||||
private final CompanyService companyService;
|
||||
|
||||
public List<User> findAllUsers(String code) {
|
||||
return userRepository.findAll();
|
||||
}
|
||||
|
||||
public User getUser(UUID id) {
|
||||
return userRepository.findById(id).get();
|
||||
}
|
||||
|
||||
public void saveOrUpdateUser(User updatedUser) {
|
||||
if (updatedUser.getId() == null) {
|
||||
var company = companyService.getCompany();
|
||||
updatedUser.setCompany(company);
|
||||
updatedUser.setRole(Role.REGULAR);
|
||||
updatedUser.setStatus(Status.ACTIVE);
|
||||
}
|
||||
|
||||
userRepository.save(updatedUser);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.primefactorsolutions.invoices.utils;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@UtilityClass
|
||||
public class TextUtils {
|
||||
private static final Pattern WORD_FINDER = Pattern.compile("(([A-Z]?[a-z]+)|([A-Z]))");
|
||||
|
||||
public static String makeLabel(final String text) {
|
||||
return findWordsInMixedCase(text).stream()
|
||||
.map(StringUtils::capitalize)
|
||||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
private static List<String> findWordsInMixedCase(final String text) {
|
||||
var matcher = WORD_FINDER.matcher(text);
|
||||
var words = new ArrayList<String>();
|
||||
while (matcher.find()) {
|
||||
words.add(matcher.group(0));
|
||||
}
|
||||
return words;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.primefactorsolutions.invoices.utils;
|
||||
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class UiUtils {
|
||||
public static void goTo(Component component, String location) {
|
||||
component.getUI().ifPresent(ui -> ui.navigate(location));
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
public interface Bindable<T> {
|
||||
|
||||
void setBean(Object bean);
|
||||
|
||||
T getBean();
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Client;
|
||||
import com.primefactorsolutions.invoices.services.ClientService;
|
||||
import com.primefactorsolutions.invoices.views.component.Breadcrumbs;
|
||||
import com.primefactorsolutions.invoices.views.component.GenericForm;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.i18n.I18NProvider;
|
||||
import com.vaadin.flow.router.BeforeEvent;
|
||||
import com.vaadin.flow.router.HasUrlParameter;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.primefactorsolutions.invoices.utils.UiUtils.goTo;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "clients", layout = MainLayout.class)
|
||||
@PageTitle("Client | PFS Facturacion")
|
||||
public class ClientEditView extends VerticalLayout implements HasUrlParameter<String> {
|
||||
|
||||
ClientService clientService;
|
||||
I18NProvider i18NProvider;
|
||||
|
||||
GenericForm<Client> clientGenericForm;
|
||||
|
||||
public ClientEditView(ClientService clientService, I18NProvider i18NProvider) {
|
||||
this.clientService = clientService;
|
||||
this.i18NProvider = i18NProvider;
|
||||
var client = new Client();
|
||||
|
||||
this.clientGenericForm = new GenericForm<>(Client.class);
|
||||
this.clientGenericForm.setBean(client);
|
||||
|
||||
String text = this.i18NProvider.getTranslation("action.save", Locale.of("es"));
|
||||
var saveButton = new Button(text);
|
||||
saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
saveButton.addClickListener(c -> {
|
||||
var updatedClient = clientGenericForm.getBean();
|
||||
clientService.saveOrUpdateClient(updatedClient);
|
||||
goTo(this, "clients");
|
||||
});
|
||||
var cancelButton = new Button("Cancel");
|
||||
cancelButton.addClickListener(c -> goTo(this, "clients"));
|
||||
|
||||
var breadcrumbs = new Breadcrumbs(List.of(Pair.of("Clientes", "clients"), Pair.of("Editar", null)));
|
||||
var buttonLayout = new HorizontalLayout(saveButton, cancelButton);
|
||||
|
||||
add(breadcrumbs, clientGenericForm, buttonLayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameter(BeforeEvent beforeEvent, String s) {
|
||||
if (StringUtils.isNotBlank(s) && !"new".equals(s)) {
|
||||
var product = clientService.getClient(UUID.fromString(s));
|
||||
clientGenericForm.setBean(product);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Client;
|
||||
import com.primefactorsolutions.invoices.model.InvoiceType;
|
||||
import com.primefactorsolutions.invoices.model.Status;
|
||||
import com.primefactorsolutions.invoices.services.ClientService;
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.html.Anchor;
|
||||
import com.vaadin.flow.component.html.H4;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.renderer.ComponentRenderer;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.vaadin.firitin.components.grid.PagingGrid;
|
||||
|
||||
import static com.primefactorsolutions.invoices.utils.UiUtils.goTo;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "clients", layout = MainLayout.class)
|
||||
@PageTitle("Facturas | PFS Facturacion")
|
||||
public class ClientListView extends VerticalLayout {
|
||||
PagingGrid<Client> grid = new PagingGrid<>(Client.class);
|
||||
TextField filterText = new TextField();
|
||||
ClientService clientService;
|
||||
|
||||
public ClientListView(ClientService clientService) {
|
||||
this.clientService = clientService;
|
||||
addClassName("pfs-list-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
|
||||
add(getTitle(), getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private Component getTitle() {
|
||||
return new H4("Clientes");
|
||||
}
|
||||
|
||||
private HorizontalLayout getContent() {
|
||||
HorizontalLayout content = new HorizontalLayout(grid);
|
||||
content.setFlexGrow(2, grid);
|
||||
// content.setFlexGrow(1, form);
|
||||
content.addClassNames("content");
|
||||
content.setSizeFull();
|
||||
return content;
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassNames("pfs-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("correoElectronico", "telefono");
|
||||
grid.addColumn(new ComponentRenderer<>(Anchor::new, (a, p) -> {
|
||||
a.setHref("clients/" + p.getId());
|
||||
a.setText(p.getNombreRazonSocial());
|
||||
})).setHeader("nombreRazonSocial");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.setPaginationBarMode(PagingGrid.PaginationBarMode.BOTTOM);
|
||||
grid.setPagingDataProvider((l, i) -> clientService.findAllClients(""));
|
||||
|
||||
var clients = clientService.findAllClients("");
|
||||
grid.setItems(clients);
|
||||
grid.setPageSize(25);
|
||||
}
|
||||
|
||||
private Component getToolbar() {
|
||||
filterText.setPlaceholder("Buscar ...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
var comboBox = new ComboBox<Status>();
|
||||
comboBox.setItems(Status.values());
|
||||
comboBox.setItemLabelGenerator(Status::name);
|
||||
comboBox.setValue(Status.ACTIVE);
|
||||
add(comboBox);
|
||||
|
||||
var addClientButton = new Button("Nuevo Cliente");
|
||||
addClientButton.addClickListener(click -> goTo(this, "clients/new"));
|
||||
|
||||
var addComponent = new HorizontalLayout(comboBox, addClientButton);
|
||||
var toolbar = new HorizontalLayout(filterText, addComponent);
|
||||
toolbar.addClassName("toolbar");
|
||||
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(clientService.findAllClients(filterText.getValue()));
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.primefactorsolutions.invoices.model.Company;
|
||||
import com.primefactorsolutions.invoices.model.CurrencyPair;
|
||||
import com.primefactorsolutions.invoices.services.CompanyService;
|
||||
import com.primefactorsolutions.invoices.views.component.GenericForm;
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.html.H4;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.textfield.BigDecimalField;
|
||||
import com.vaadin.flow.i18n.I18NProvider;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.checkerframework.checker.units.qual.C;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.vaadin.firitin.components.textfield.VBigDecimalField;
|
||||
import org.vaadin.firitin.fields.ElementCollectionField;
|
||||
import org.vaadin.firitin.fields.EnumSelect;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.primefactorsolutions.invoices.utils.UiUtils.goTo;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "company-config", layout = MainLayout.class)
|
||||
@PageTitle("Compania | PFS Facturacion")
|
||||
public class CompanyEditView extends VerticalLayout {
|
||||
|
||||
CompanyService companyService;
|
||||
|
||||
public CompanyEditView(CompanyService companyService, I18NProvider i18NProvider) {
|
||||
this.companyService = companyService;
|
||||
var company = this.companyService.getCompany();
|
||||
|
||||
var companyGenericForm = new GenericForm<>(Company.class);
|
||||
companyGenericForm.setBean(company);
|
||||
|
||||
String text = i18NProvider.getTranslation("action.save", Locale.of("es"));
|
||||
var saveButton = new Button(text);
|
||||
saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
saveButton.addClickListener(c -> {
|
||||
var updatedCompany = companyGenericForm.getBean();
|
||||
companyService.saveOrUpdateCompany(updatedCompany);
|
||||
});
|
||||
var cancelButton = new Button("Cancel");
|
||||
cancelButton.addClickListener(c -> goTo(this, ""));
|
||||
|
||||
var buttonLayout = new HorizontalLayout(saveButton, cancelButton);
|
||||
var propForm = getCurrencyForm();
|
||||
|
||||
add(getTitle(), companyGenericForm, propForm, buttonLayout);
|
||||
}
|
||||
|
||||
private Component getTitle() {
|
||||
return new H4("Configuracion");
|
||||
}
|
||||
|
||||
|
||||
private Component getCurrencyForm() {
|
||||
ElementCollectionField<CurrencyPair> field = new ElementCollectionField<>(CurrencyPair.class, CurrencyEditor.class)
|
||||
.withEditorInstantiator(CurrencyEditor::new);
|
||||
|
||||
var cp = new CurrencyPair(CurrencyPair.CurrencyType.BOB, CurrencyPair.CurrencyType.USD, BigDecimal.valueOf(7.0), BigDecimal.valueOf(6.97));
|
||||
field.setValue(Lists.newArrayList(cp));
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
public static class CurrencyEditor {
|
||||
EnumSelect<CurrencyPair.CurrencyType> base = new EnumSelect<>(CurrencyPair.CurrencyType.class);
|
||||
EnumSelect<CurrencyPair.CurrencyType> quote = new EnumSelect<>(CurrencyPair.CurrencyType.class);
|
||||
BigDecimalField bid = new BigDecimalField();
|
||||
BigDecimalField ask = new BigDecimalField();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
|
||||
import com.vaadin.flow.component.ScrollOptions;
|
||||
import com.vaadin.flow.component.Text;
|
||||
import com.vaadin.flow.component.UI;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.icon.Icon;
|
||||
import com.vaadin.flow.component.notification.Notification;
|
||||
import com.vaadin.flow.component.notification.NotificationVariant;
|
||||
import com.vaadin.flow.component.orderedlayout.FlexComponent;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.server.ErrorEvent;
|
||||
import com.vaadin.flow.server.ErrorHandler;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.aspectj.weaver.ast.Not;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Log4j2
|
||||
public class CustomErrorHandler implements ErrorHandler {
|
||||
@Override
|
||||
public void error(ErrorEvent errorEvent) {
|
||||
log.error("Something wrong happened", errorEvent.getThrowable());
|
||||
if(UI.getCurrent() != null) {
|
||||
UI.getCurrent().access(() -> {
|
||||
var notification = new Notification();
|
||||
notification.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
||||
notification.setPosition(Notification.Position.TOP_CENTER);
|
||||
notification.setDuration(0);
|
||||
var layout = new HorizontalLayout(new Text("An internal error has occurred." +
|
||||
"Contact support for assistance."), new CloseButton());
|
||||
layout.setAlignItems(FlexComponent.Alignment.CENTER);
|
||||
notification.add(layout);
|
||||
notification.open();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseButton extends Button {
|
||||
public CloseButton() {
|
||||
super(new Icon("lumo", "cross"));
|
||||
addThemeVariants(ButtonVariant.LUMO_TERTIARY_INLINE);
|
||||
setAriaLabel("Close");
|
||||
addClickListener(e -> findAncestor(Notification.class).close());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,266 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.primefactorsolutions.invoices.beans.CabeceraDTO;
|
||||
import com.primefactorsolutions.invoices.beans.ClientDTO;
|
||||
import com.primefactorsolutions.invoices.beans.DetalleDTO;
|
||||
import com.primefactorsolutions.invoices.beans.TotalesDTO;
|
||||
import com.primefactorsolutions.invoices.model.mappers.CabeceraMapper;
|
||||
import com.primefactorsolutions.invoices.model.mappers.ClientMapper;
|
||||
import com.primefactorsolutions.invoices.model.mappers.DetalleMapper;
|
||||
import com.primefactorsolutions.invoices.services.ClientService;
|
||||
import com.primefactorsolutions.invoices.services.CompanyService;
|
||||
import com.primefactorsolutions.invoices.services.InvoiceService;
|
||||
import com.primefactorsolutions.invoices.views.component.invoice.*;
|
||||
import com.primefactorsolutions.invoices.xsd.FacturaComputarizadaComercialExportacionServicio;
|
||||
import com.vaadin.flow.component.*;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.contextmenu.MenuItem;
|
||||
import com.vaadin.flow.component.details.Details;
|
||||
import com.vaadin.flow.component.dialog.Dialog;
|
||||
import com.vaadin.flow.component.html.*;
|
||||
import com.vaadin.flow.component.icon.Icon;
|
||||
import com.vaadin.flow.component.menubar.MenuBar;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.primefactorsolutions.invoices.utils.TextUtils.makeLabel;
|
||||
import static com.primefactorsolutions.invoices.utils.UiUtils.goTo;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "edit-invoice", layout = MainLayout.class)
|
||||
@PageTitle("Factura | Editar")
|
||||
public class FacturaComputarizadaComercialExportacionesServicioEditView extends VerticalLayout {
|
||||
private final CabeceraForm<CabeceraDTO> cabeceraForm;
|
||||
private final ClientForm<ClientDTO> clientForm;
|
||||
private final TotalesForm<TotalesDTO> totalesForm;
|
||||
private final DetallesForm<DetalleDTO> detalleForm;
|
||||
private final Button save = new Button("Crear");
|
||||
private final Button close = new Button("Cancelar");
|
||||
private final Dialog dialog = new Dialog();
|
||||
private final InvoiceService invoiceService;
|
||||
private final ClientService clientService;
|
||||
private final CompanyService companyService;
|
||||
|
||||
public FacturaComputarizadaComercialExportacionesServicioEditView(
|
||||
InvoiceService invoiceService,
|
||||
ClientService clientService,
|
||||
CompanyService companyService) {
|
||||
this.invoiceService = invoiceService;
|
||||
this.clientService = clientService;
|
||||
this.companyService = companyService;
|
||||
|
||||
var company = companyService.getCompany();
|
||||
var cabeceraDTO = CabeceraMapper.INSTANCE.cabeceraDtoFromCompany(company);
|
||||
this.cabeceraForm = new CabeceraForm<>(CabeceraDTO.class);
|
||||
this.cabeceraForm.binder.setBean(cabeceraDTO);
|
||||
|
||||
var clientDTO = new ClientDTO();
|
||||
|
||||
this.clientForm = new ClientForm<>(ClientDTO.class);
|
||||
this.clientForm.binder.setBean(clientDTO);
|
||||
|
||||
this.detalleForm = new DetallesForm<>(DetalleDTO.class, DetalleDTO::new);
|
||||
|
||||
var totalesDTO = new TotalesDTO();
|
||||
totalesDTO.setInformacionAdicional("Ninguno");
|
||||
totalesDTO.setDescuentoAdicional(BigDecimal.valueOf(0));
|
||||
this.totalesForm = new TotalesForm<>(TotalesDTO.class);
|
||||
this.totalesForm.binder.setBean(totalesDTO);
|
||||
|
||||
var emisorDetails = getEmisorDetails(cabeceraDTO);
|
||||
var clienteDetails = getClienteDetails();
|
||||
var detalleDetails = getDetalleDetails();
|
||||
|
||||
add(createMenu(), emisorDetails, clienteDetails, detalleDetails, createButtonsLayout());
|
||||
createHelp();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Details getDetalleDetails() {
|
||||
var detalleSummary = new HorizontalLayout();
|
||||
detalleSummary.setSpacing(false);
|
||||
detalleSummary.add(new Text("Detalle"));
|
||||
|
||||
var content = new VerticalLayout();
|
||||
|
||||
var detalleDetails = new Details(detalleSummary, content);
|
||||
var addButton = new Button("Agregar Detalle");
|
||||
addButton.addClickListener(e -> this.detalleForm.addDetalle());
|
||||
|
||||
content.add(this.detalleForm);
|
||||
content.add(addButton);
|
||||
content.add(new Text("Totales"));
|
||||
content.add(this.totalesForm);
|
||||
|
||||
detalleDetails.setOpened(true);
|
||||
|
||||
this.detalleForm.addChangeListener(c -> {
|
||||
var values = this.detalleForm.getValues();
|
||||
var currentTotales = this.totalesForm.binder.getBean();
|
||||
|
||||
var total = values.stream()
|
||||
.map(DetalleDTO::getSubTotal)
|
||||
.map(b -> b == null ? new BigDecimal(0) : b)
|
||||
.reduce(BigDecimal::add).orElse(new BigDecimal(0));
|
||||
|
||||
System.out.println(">>>>>>>>" + total);
|
||||
currentTotales.setMontoTotalMoneda(total);
|
||||
currentTotales.setMontoTotal((total.subtract(currentTotales.getDescuentoAdicional()))
|
||||
.multiply(BigDecimal.valueOf(7.0)));
|
||||
currentTotales.setMontoTotalSujetoIva(currentTotales.getMontoTotal().subtract(currentTotales.getDescuentoAdicional()));
|
||||
|
||||
this.totalesForm.binder.setBean(currentTotales);
|
||||
});
|
||||
|
||||
return detalleDetails;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Details getClienteDetails() {
|
||||
ClientInputForm clientInputForm = new ClientInputForm(clientService);
|
||||
clientInputForm.addListener(c -> {
|
||||
var selectedClientDTO = ClientMapper.INSTANCE.clientDtoFromClient(c);
|
||||
this.clientForm.binder.setBean(selectedClientDTO);
|
||||
this.clientForm.setVisible(true);
|
||||
});
|
||||
|
||||
var clienteText = new Text("Cliente");
|
||||
var clienteSummary = new HorizontalLayout();
|
||||
clienteSummary.setSpacing(false);
|
||||
clienteSummary.add(clienteText);
|
||||
|
||||
var clientPanel = new VerticalLayout();
|
||||
clientPanel.add(clientInputForm);
|
||||
clientPanel.add(this.clientForm);
|
||||
|
||||
var clienteDetails = new Details(clienteSummary, clientPanel);
|
||||
clienteDetails.setOpened(true);
|
||||
clienteDetails.addOpenedChangeListener(e -> {
|
||||
if (e.isOpened()) {
|
||||
clienteText.setText("Cliente");
|
||||
} else {
|
||||
var clienteDTO = clientForm.binder.getBean();
|
||||
clienteText.setText("Cliente (" + clienteDTO.getNombreRazonSocial() + ")");
|
||||
}
|
||||
});
|
||||
|
||||
var clienteButtons = new HorizontalLayout();
|
||||
var clienteOkButton = new Button("OK");
|
||||
clienteButtons.addClickListener(c -> clienteDetails.setOpened(false));
|
||||
clienteButtons.add(clienteOkButton);
|
||||
|
||||
clientPanel.add(clienteButtons);
|
||||
|
||||
|
||||
return clienteDetails;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Details getEmisorDetails(CabeceraDTO cabeceraDTO) {
|
||||
var emisorText = new Text("Emisor");
|
||||
var emisorSummary = new HorizontalLayout();
|
||||
emisorSummary.setSpacing(false);
|
||||
emisorSummary.add(emisorText);
|
||||
|
||||
var content = new VerticalLayout();
|
||||
var emisorDetails = new Details(emisorSummary, content);
|
||||
emisorDetails.setOpened(true);
|
||||
emisorDetails.addOpenedChangeListener(e -> {
|
||||
if (e.isOpened()) {
|
||||
emisorText.setText("Emisor");
|
||||
} else {
|
||||
emisorText.setText("Emisor (" + cabeceraDTO.getRazonSocialEmisor() + ")");
|
||||
}
|
||||
});
|
||||
|
||||
var emisorButtons = new HorizontalLayout();
|
||||
var emisorOkButton = new Button("OK");
|
||||
emisorButtons.addClickListener(c -> emisorDetails.setOpened(false));
|
||||
emisorButtons.add(emisorOkButton);
|
||||
|
||||
content.add(this.cabeceraForm, emisorButtons);
|
||||
|
||||
return emisorDetails;
|
||||
}
|
||||
|
||||
private Component createButtonsLayout() {
|
||||
this.save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
this.close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
|
||||
this.save.addClickListener(e -> {
|
||||
var factura = new FacturaComputarizadaComercialExportacionServicio();
|
||||
var cabecera = CabeceraMapper.INSTANCE.cabeceraFromDtos(this.cabeceraForm.binder.getBean(),
|
||||
this.clientForm.binder.getBean(),
|
||||
this.totalesForm.binder.getBean());
|
||||
var detalles = detalleForm.getValues().stream()
|
||||
.map(DetalleMapper.INSTANCE::detalleFromDto)
|
||||
.toList();
|
||||
|
||||
factura.setCabecera(cabecera);
|
||||
factura.setDetalle(detalles);
|
||||
|
||||
this.invoiceService.sendInvoice(factura);
|
||||
goTo(this, "invoice-pdf");
|
||||
});
|
||||
|
||||
this.close.addClickShortcut(Key.ESCAPE);
|
||||
this.close.addClickListener(click -> goTo(this, ""));
|
||||
|
||||
return new HorizontalLayout(this.save, this.close);
|
||||
}
|
||||
|
||||
private Component createMenu() {
|
||||
ComponentEventListener<ClickEvent<MenuItem>> listener = e -> {
|
||||
if (e.getSource().getText().equals("Atras")) {
|
||||
goTo(this, "");
|
||||
} else if (e.getSource().getText().equals("Ayuda")) {
|
||||
this.dialog.open();
|
||||
}
|
||||
};
|
||||
var menuBar = new MenuBar();
|
||||
menuBar.addItem("Atras", listener);
|
||||
menuBar.addItem("Ayuda", listener);
|
||||
|
||||
return menuBar;
|
||||
}
|
||||
|
||||
private void createHelp() {
|
||||
this.dialog.setHeaderTitle("Ayuda");
|
||||
var closeButton = new Button(new Icon("lumo", "cross"),
|
||||
(e) -> this.dialog.close());
|
||||
closeButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
this.dialog.getHeader().add(closeButton);
|
||||
|
||||
var help = this.invoiceService.getHelp();
|
||||
var ol = new Div();
|
||||
|
||||
help.sections().forEach(s -> {
|
||||
var section = new Section();
|
||||
var descriptionList = new DescriptionList();
|
||||
s.entries().forEach(e -> {
|
||||
descriptionList.add(new DescriptionList.Term(makeLabel(e.name())));
|
||||
descriptionList.add(new DescriptionList.Description(e.text()));
|
||||
});
|
||||
|
||||
section.add(new H4(makeLabel(s.name())));
|
||||
section.add(descriptionList);
|
||||
ol.add(section);
|
||||
});
|
||||
|
||||
this.dialog.add(ol);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
|
||||
import com.vaadin.flow.server.ServiceInitEvent;
|
||||
import com.vaadin.flow.server.VaadinServiceInitListener;
|
||||
import com.vaadin.flow.server.VaadinSession;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Log4j2
|
||||
public class InitListener implements VaadinServiceInitListener {
|
||||
|
||||
@Override
|
||||
public void serviceInit(ServiceInitEvent event) {
|
||||
event.getSource().addSessionInitListener(
|
||||
initEvent -> {
|
||||
log.info("A new Session has been initialized!");
|
||||
VaadinSession.getCurrent().setErrorHandler(new CustomErrorHandler());
|
||||
});
|
||||
|
||||
event.getSource().addUIInitListener(
|
||||
initEvent -> log.info("A new UI has been initialized!"));
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Invoice;
|
||||
import com.primefactorsolutions.invoices.model.InvoiceType;
|
||||
import com.primefactorsolutions.invoices.services.InvoiceService;
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.html.H4;
|
||||
import com.vaadin.flow.component.icon.Icon;
|
||||
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.renderer.ComponentRenderer;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.vaadin.firitin.components.grid.PagingGrid;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "", layout = MainLayout.class)
|
||||
@PageTitle("Facturas | PFS Facturacion")
|
||||
public class InvoiceListView extends VerticalLayout {
|
||||
PagingGrid<Invoice> grid = new PagingGrid<>(Invoice.class);
|
||||
|
||||
TextField filterText = new TextField();
|
||||
|
||||
InvoiceService invoiceService;
|
||||
|
||||
public InvoiceListView(InvoiceService invoiceService) {
|
||||
this.invoiceService = invoiceService;
|
||||
addClassName("list-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
|
||||
add(getTitle(), getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private Component getTitle() {
|
||||
return new H4("Facturas");
|
||||
}
|
||||
|
||||
private HorizontalLayout getContent() {
|
||||
HorizontalLayout content = new HorizontalLayout(grid);
|
||||
content.setFlexGrow(2, grid);
|
||||
// content.setFlexGrow(1, form);
|
||||
content.addClassNames("content");
|
||||
content.setSizeFull();
|
||||
return content;
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassNames("invoice-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("nombreRazonSocial", "fechaEmision");
|
||||
grid.addColumn(
|
||||
new ComponentRenderer<>(Button::new, (button, invoice) -> {
|
||||
button.addThemeVariants(ButtonVariant.LUMO_ICON, ButtonVariant.LUMO_TERTIARY);
|
||||
button.setIcon(new Icon(VaadinIcon.CHECK));
|
||||
})).setHeader("status");
|
||||
|
||||
//grid.addColumn(contact -> contact.getStatus().getName()).setHeader("Status");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.setPaginationBarMode(PagingGrid.PaginationBarMode.BOTTOM);
|
||||
grid.setPagingDataProvider((l, i) -> invoiceService.findAllInvoices());
|
||||
|
||||
List<Invoice> invoices = invoiceService.findAllInvoices();
|
||||
grid.setItems(invoices);
|
||||
grid.setPageSize(25);
|
||||
}
|
||||
|
||||
private Component getToolbar() {
|
||||
filterText.setPlaceholder("Buscar ...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
var comboBox = new ComboBox<InvoiceType>();
|
||||
comboBox.getStyle().set("--vaadin-combo-box-overlay-width", "350px");
|
||||
comboBox.setItems(InvoiceType.values());
|
||||
comboBox.setItemLabelGenerator(InvoiceType::getDisplayName);
|
||||
add(comboBox);
|
||||
|
||||
var addInvoiceButton = new Button("Nueva Factura");
|
||||
// addContactButton.addClickListener(click -> addContact());
|
||||
addInvoiceButton.addClickListener(click -> {
|
||||
this.getUI().ifPresent(ui -> ui.navigate("edit-invoice"));
|
||||
});
|
||||
|
||||
var addComponent = new HorizontalLayout(comboBox, addInvoiceButton);
|
||||
|
||||
var toolbar = new HorizontalLayout(filterText, addComponent);
|
||||
toolbar.addClassName("toolbar");
|
||||
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(invoiceService.findAllInvoices());
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.primefactorsolutions.invoices.services.MediaService;
|
||||
import com.vaadin.componentfactory.pdfviewer.PdfViewer;
|
||||
import com.vaadin.flow.component.html.Div;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.server.StreamResource;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "invoice-pdf", layout = MainLayout.class)
|
||||
@PageTitle("Vista | PFS Facturacion")
|
||||
public class InvoicePdfView extends Div {
|
||||
|
||||
public InvoicePdfView(MediaService mediaService) {
|
||||
var media = mediaService.findMedia("foo.pdf");
|
||||
var content = media.getContent();
|
||||
var pdfViewer = new PdfViewer();
|
||||
pdfViewer.setSizeFull();
|
||||
var resource = new StreamResource("factura.pdf",
|
||||
() -> new ByteArrayInputStream(content));
|
||||
pdfViewer.setSrc(resource);
|
||||
|
||||
getStyle().set("height", "100%");
|
||||
getStyle().set("overflow", "hidden");
|
||||
getStyle().set("display", "flex");
|
||||
getStyle().set("flex-direction", "column");
|
||||
|
||||
add(pdfViewer);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.vaadin.flow.component.html.H1;
|
||||
import com.vaadin.flow.component.login.LoginForm;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.router.BeforeEnterEvent;
|
||||
import com.vaadin.flow.router.BeforeEnterObserver;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.server.auth.AnonymousAllowed;
|
||||
|
||||
@Route("login")
|
||||
@PageTitle("Connexion | PFS Facturacion")
|
||||
@AnonymousAllowed
|
||||
public class LoginView extends VerticalLayout implements BeforeEnterObserver {
|
||||
|
||||
private final LoginForm login = new LoginForm();
|
||||
|
||||
public LoginView(){
|
||||
addClassName("login-view");
|
||||
setSizeFull();
|
||||
setAlignItems(Alignment.CENTER);
|
||||
setJustifyContentMode(JustifyContentMode.CENTER);
|
||||
|
||||
login.setAction("login");
|
||||
|
||||
add(new H1("PFS Facturacion"));
|
||||
add(login);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeEnter(final BeforeEnterEvent beforeEnterEvent) {
|
||||
// inform the user about an authentication error
|
||||
if(beforeEnterEvent.getLocation()
|
||||
.getQueryParameters()
|
||||
.getParameters()
|
||||
.containsKey("error")) {
|
||||
login.setError(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.primefactorsolutions.invoices.security.SecurityService;
|
||||
import com.vaadin.flow.component.applayout.AppLayout;
|
||||
import com.vaadin.flow.component.applayout.DrawerToggle;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.html.H1;
|
||||
import com.vaadin.flow.component.orderedlayout.FlexComponent;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.router.RouterLink;
|
||||
import com.vaadin.flow.theme.lumo.LumoUtility;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
public class MainLayout extends AppLayout {
|
||||
private final SecurityService securityService;
|
||||
|
||||
public MainLayout(SecurityService securityService) {
|
||||
this.securityService = securityService;
|
||||
createHeader();
|
||||
createDrawer();
|
||||
}
|
||||
|
||||
private void createHeader() {
|
||||
var logo = new H1("PFS Facturacion");
|
||||
logo.addClassNames(
|
||||
LumoUtility.FontSize.LARGE,
|
||||
LumoUtility.Margin.MEDIUM);
|
||||
|
||||
var u = securityService.getAuthenticatedUser().map(UserDetails::getUsername).orElse("");
|
||||
var logout = new Button("Desconectar " + u, e -> securityService.logout());
|
||||
var header = new HorizontalLayout(new DrawerToggle(), logo, logout);
|
||||
|
||||
header.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
|
||||
header.expand(logo);
|
||||
header.setWidthFull();
|
||||
header.addClassNames(
|
||||
LumoUtility.Padding.Vertical.NONE,
|
||||
LumoUtility.Padding.Horizontal.MEDIUM);
|
||||
|
||||
addToNavbar(header);
|
||||
}
|
||||
|
||||
private void createDrawer() {
|
||||
addToDrawer(new VerticalLayout(
|
||||
new RouterLink("Facturas", InvoiceListView.class),
|
||||
new RouterLink("Clientes", ClientListView.class),
|
||||
new RouterLink("Productos", ProductListView.class),
|
||||
new RouterLink("Configuracion", CompanyEditView.class),
|
||||
new RouterLink("Usuarios", UserListView.class)
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Product;
|
||||
import com.primefactorsolutions.invoices.services.ProductService;
|
||||
import com.primefactorsolutions.invoices.views.component.Breadcrumbs;
|
||||
import com.primefactorsolutions.invoices.views.component.GenericForm;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.i18n.I18NProvider;
|
||||
import com.vaadin.flow.router.BeforeEvent;
|
||||
import com.vaadin.flow.router.HasUrlParameter;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.primefactorsolutions.invoices.utils.UiUtils.goTo;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "product-edit", layout = MainLayout.class)
|
||||
@PageTitle("Product | PFS Facturacion")
|
||||
public class ProductEditView extends VerticalLayout implements HasUrlParameter<String> {
|
||||
|
||||
ProductService productService;
|
||||
I18NProvider i18NProvider;
|
||||
|
||||
GenericForm<Product> productGenericForm;
|
||||
|
||||
public ProductEditView(ProductService productService, I18NProvider i18NProvider) {
|
||||
this.productService = productService;
|
||||
this.i18NProvider = i18NProvider;
|
||||
var product = new Product();
|
||||
|
||||
this.productGenericForm = new GenericForm<>(Product.class);
|
||||
this.productGenericForm.setBean(product);
|
||||
|
||||
String text = this.i18NProvider.getTranslation("action.save", Locale.of("es"));
|
||||
var saveButton = new Button(text);
|
||||
saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
saveButton.addClickListener(c -> {
|
||||
var updatedProduct = productGenericForm.getBean();
|
||||
productService.saveOrUpdateProduct(updatedProduct);
|
||||
goTo(this, "products");
|
||||
});
|
||||
var cancelButton = new Button("Cancel");
|
||||
cancelButton.addClickListener(c -> {
|
||||
goTo(this, "products");
|
||||
});
|
||||
|
||||
var breadcrumbs = new Breadcrumbs(List.of(Pair.of("Products", "products"), Pair.of("Editar", null)));
|
||||
var buttonLayout = new HorizontalLayout(saveButton, cancelButton);
|
||||
|
||||
add(breadcrumbs, productGenericForm, buttonLayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameter(BeforeEvent beforeEvent, String s) {
|
||||
if (StringUtils.isNotBlank(s) && !"new".equals(s)) {
|
||||
var product = productService.getProduct(UUID.fromString(s));
|
||||
productGenericForm.setBean(product);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.InvoiceType;
|
||||
import com.primefactorsolutions.invoices.model.Product;
|
||||
import com.primefactorsolutions.invoices.model.Status;
|
||||
import com.primefactorsolutions.invoices.services.ProductService;
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.html.Anchor;
|
||||
import com.vaadin.flow.component.html.H4;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.renderer.ComponentRenderer;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.vaadin.firitin.components.grid.PagingGrid;
|
||||
|
||||
import static com.primefactorsolutions.invoices.utils.UiUtils.goTo;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "products", layout = MainLayout.class)
|
||||
@PageTitle("Facturas | PFS Facturacion")
|
||||
public class ProductListView extends VerticalLayout {
|
||||
PagingGrid<Product> grid = new PagingGrid<>(Product.class);
|
||||
TextField filterText = new TextField();
|
||||
ProductService productService;
|
||||
|
||||
public ProductListView(ProductService productService) {
|
||||
this.productService = productService;
|
||||
addClassName("list-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
|
||||
add(getTitle(), getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private Component getTitle() {
|
||||
return new H4("Productos");
|
||||
}
|
||||
|
||||
private HorizontalLayout getContent() {
|
||||
HorizontalLayout content = new HorizontalLayout(grid);
|
||||
content.setFlexGrow(2, grid);
|
||||
content.addClassNames("content");
|
||||
content.setSizeFull();
|
||||
return content;
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassNames("pfs-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("descripcion", "precioUnitario");
|
||||
grid.addColumn(new ComponentRenderer<>(Anchor::new, (a, p) -> {
|
||||
a.setHref("product-edit/" + p.getId());
|
||||
a.setText(p.getCodigoProducto());
|
||||
})).setHeader("codigoProducto");
|
||||
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.setPaginationBarMode(PagingGrid.PaginationBarMode.BOTTOM);
|
||||
grid.setPagingDataProvider((l, i) -> productService.findAllProducts(""));
|
||||
|
||||
var products = productService.findAllProducts("");
|
||||
grid.setItems(products);
|
||||
grid.setPageSize(25);
|
||||
}
|
||||
|
||||
private Component getToolbar() {
|
||||
filterText.setPlaceholder("input.search");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
var comboBox = new ComboBox<Status>();
|
||||
comboBox.setItems(Status.values());
|
||||
comboBox.setItemLabelGenerator(Status::name);
|
||||
comboBox.setValue(Status.ACTIVE);
|
||||
add(comboBox);
|
||||
|
||||
var addInvoiceButton = new Button("action.new");
|
||||
addInvoiceButton.addClickListener(click -> goTo(this, "product-edit/new"));
|
||||
|
||||
var addComponent = new HorizontalLayout(comboBox, addInvoiceButton);
|
||||
|
||||
var toolbar = new HorizontalLayout(filterText, addComponent);
|
||||
toolbar.addClassName("toolbar");
|
||||
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(productService.findAllProducts(""));
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.User;
|
||||
import com.primefactorsolutions.invoices.services.UserService;
|
||||
import com.primefactorsolutions.invoices.views.component.Breadcrumbs;
|
||||
import com.primefactorsolutions.invoices.views.component.GenericForm;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.html.Anchor;
|
||||
import com.vaadin.flow.component.html.Span;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.i18n.I18NProvider;
|
||||
import com.vaadin.flow.router.BeforeEvent;
|
||||
import com.vaadin.flow.router.HasUrlParameter;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.primefactorsolutions.invoices.utils.UiUtils.goTo;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "users", layout = MainLayout.class)
|
||||
@PageTitle("User | PFS Facturacion")
|
||||
public class UserEditView extends VerticalLayout implements HasUrlParameter<String> {
|
||||
|
||||
UserService userService;
|
||||
I18NProvider i18NProvider;
|
||||
GenericForm<User> userGenericForm;
|
||||
|
||||
public UserEditView(UserService userService, I18NProvider i18NProvider) {
|
||||
this.userService = userService;
|
||||
this.i18NProvider = i18NProvider;
|
||||
var user = new User();
|
||||
|
||||
this.userGenericForm = new GenericForm<>(User.class);
|
||||
this.userGenericForm.setBean(user);
|
||||
|
||||
String text = this.i18NProvider.getTranslation("action.save", Locale.of("es"));
|
||||
var saveButton = new Button(text);
|
||||
saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
saveButton.addClickListener(c -> {
|
||||
var updatedUser = userGenericForm.getBean();
|
||||
userService.saveOrUpdateUser(updatedUser);
|
||||
goTo(this, "users");
|
||||
});
|
||||
var cancelButton = new Button("Cancel");
|
||||
cancelButton.addClickListener(c -> {
|
||||
goTo(this, "users");
|
||||
});
|
||||
|
||||
var breadcrumbs = new Breadcrumbs(List.of(Pair.of("Usuarios", "users"), Pair.of("Editar", null)));
|
||||
var buttonLayout = new HorizontalLayout(saveButton, cancelButton);
|
||||
|
||||
add(breadcrumbs, userGenericForm, buttonLayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameter(BeforeEvent beforeEvent, String s) {
|
||||
if (StringUtils.isNotBlank(s) && !"new".equals(s)) {
|
||||
var user = userService.getUser(UUID.fromString(s));
|
||||
userGenericForm.setBean(user);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package com.primefactorsolutions.invoices.views;
|
||||
|
||||
import com.primefactorsolutions.invoices.model.Status;
|
||||
import com.primefactorsolutions.invoices.model.User;
|
||||
import com.primefactorsolutions.invoices.services.UserService;
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.html.Anchor;
|
||||
import com.vaadin.flow.component.html.H4;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.renderer.ComponentRenderer;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.vaadin.firitin.components.grid.PagingGrid;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "users", layout = MainLayout.class)
|
||||
@PageTitle("Facturas | PFS Facturacion")
|
||||
public class UserListView extends VerticalLayout {
|
||||
PagingGrid<User> grid = new PagingGrid<>(User.class);
|
||||
TextField filterText = new TextField();
|
||||
UserService userService;
|
||||
|
||||
public UserListView(UserService userService) {
|
||||
this.userService = userService;
|
||||
addClassName("list-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
|
||||
add(getTitle(), getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private Component getTitle() {
|
||||
return new H4("Users");
|
||||
}
|
||||
|
||||
private HorizontalLayout getContent() {
|
||||
HorizontalLayout content = new HorizontalLayout(grid);
|
||||
content.setFlexGrow(2, grid);
|
||||
// content.setFlexGrow(1, form);
|
||||
content.addClassNames("content");
|
||||
content.setSizeFull();
|
||||
return content;
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassNames("invoice-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("fullName", "email", "role", "status");
|
||||
grid.getColumnByKey("fullName").setRenderer(new ComponentRenderer<>(Anchor::new, (anchor, u) -> {
|
||||
anchor.setHref("users/" + u.getId());
|
||||
anchor.setText(u.getFullName());
|
||||
}));
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.setPaginationBarMode(PagingGrid.PaginationBarMode.BOTTOM);
|
||||
grid.setPagingDataProvider((l, i) -> userService.findAllUsers(""));
|
||||
|
||||
List<User> invoices = userService.findAllUsers("");
|
||||
grid.setItems(invoices);
|
||||
grid.setPageSize(25);
|
||||
}
|
||||
|
||||
private Component getToolbar() {
|
||||
filterText.setPlaceholder("Buscar ...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
var comboBox = new ComboBox<Status>();
|
||||
comboBox.setItems(Status.values());
|
||||
comboBox.setItemLabelGenerator(Status::name);
|
||||
comboBox.setValue(Status.ACTIVE);
|
||||
add(comboBox);
|
||||
|
||||
var addInvoiceButton = new Button("Nuevo Usuario");
|
||||
addInvoiceButton.addClickListener(click -> {
|
||||
this.getUI().ifPresent(ui -> ui.navigate("users/new"));
|
||||
});
|
||||
|
||||
var addComponent = new HorizontalLayout(comboBox, addInvoiceButton);
|
||||
|
||||
var toolbar = new HorizontalLayout(filterText, addComponent);
|
||||
toolbar.addClassName("toolbar");
|
||||
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(userService.findAllUsers(""));
|
||||
}
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
package com.primefactorsolutions.invoices.views.component;
|
||||
|
||||
import com.vaadin.flow.component.Tag;
|
||||
import com.vaadin.flow.component.dependency.JsModule;
|
||||
import com.vaadin.flow.component.dependency.NpmPackage;
|
||||
import com.vaadin.flow.component.shared.HasThemeVariant;
|
||||
import com.vaadin.flow.component.textfield.AbstractNumberField;
|
||||
import com.vaadin.flow.component.textfield.TextFieldVariant;
|
||||
import com.vaadin.flow.function.SerializableFunction;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
@Tag("vaadin-integer-field")
|
||||
@NpmPackage(value = "@vaadin/polymer-legacy-adapter", version = "24.3.10")
|
||||
@JsModule("@vaadin/polymer-legacy-adapter/style-modules.js")
|
||||
@NpmPackage(value = "@vaadin/integer-field", version = "24.3.10")
|
||||
@JsModule("@vaadin/integer-field/src/vaadin-integer-field.js")
|
||||
public class BigIntegerField extends AbstractNumberField<BigIntegerField, BigInteger>
|
||||
implements HasThemeVariant<TextFieldVariant> {
|
||||
|
||||
private static final SerializableFunction<String, BigInteger> PARSER = valueFormClient -> {
|
||||
if (valueFormClient == null || valueFormClient.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new BigInteger(valueFormClient);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final SerializableFunction<BigInteger, String> FORMATTER = valueFromModel -> valueFromModel == null
|
||||
? ""
|
||||
: valueFromModel.toString();
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code LongField}.
|
||||
*/
|
||||
public BigIntegerField() {
|
||||
super(PARSER, FORMATTER, Double.MIN_VALUE, Double.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code LongField} with the given label.
|
||||
*
|
||||
* @param label
|
||||
* the text to set as the label
|
||||
*/
|
||||
public BigIntegerField(String label) {
|
||||
this();
|
||||
setLabel(label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code LongField} with the given label and
|
||||
* placeholder text.
|
||||
*
|
||||
* @param label
|
||||
* the text to set as the label
|
||||
* @param placeholder
|
||||
* the placeholder text to set
|
||||
*/
|
||||
public BigIntegerField(String label, String placeholder) {
|
||||
this(label);
|
||||
setPlaceholder(placeholder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code LongField} with a value change listener.
|
||||
*
|
||||
* @param listener
|
||||
* the value change listener
|
||||
*
|
||||
* @see #addValueChangeListener(ValueChangeListener)
|
||||
*/
|
||||
public BigIntegerField(
|
||||
ValueChangeListener<? super ComponentValueChangeEvent<BigIntegerField, BigInteger>> listener) {
|
||||
this();
|
||||
addValueChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code LongField} with a value change listener and
|
||||
* a label.
|
||||
*
|
||||
* @param label
|
||||
* the text to set as the label
|
||||
* @param listener
|
||||
* the value change listener
|
||||
*
|
||||
* @see #setLabel(String)
|
||||
* @see #addValueChangeListener(ValueChangeListener)
|
||||
*/
|
||||
public BigIntegerField(String label,
|
||||
ValueChangeListener<? super ComponentValueChangeEvent<BigIntegerField, BigInteger>> listener) {
|
||||
this(label);
|
||||
addValueChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code LongField} with a value change listener, a label
|
||||
* and an initial value.
|
||||
*
|
||||
* @param label
|
||||
* the text to set as the label
|
||||
* @param initialValue
|
||||
* the initial value
|
||||
* @param listener
|
||||
* the value change listener
|
||||
*
|
||||
* @see #setLabel(String)
|
||||
* @see #setValue(Object)
|
||||
* @see #addValueChangeListener(ValueChangeListener)
|
||||
*/
|
||||
public BigIntegerField(String label, BigInteger initialValue,
|
||||
ValueChangeListener<? super ComponentValueChangeEvent<BigIntegerField, BigInteger>> listener) {
|
||||
this(label);
|
||||
setValue(initialValue);
|
||||
addValueChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum value of the field. Entering a value which is smaller
|
||||
* than {@code min} invalidates the field.
|
||||
*
|
||||
* @param min
|
||||
* the min value to set
|
||||
*/
|
||||
public void setMin(int min) {
|
||||
super.setMin(min);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum allowed value of the field.
|
||||
*
|
||||
* @return the min property of the field
|
||||
* @see #setMin(int)
|
||||
*/
|
||||
public int getMin() {
|
||||
return (int) getMinDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum value of the field. Entering a value which is greater
|
||||
* than {@code max} invalidates the field.
|
||||
*
|
||||
* @param max
|
||||
* the max value to set
|
||||
*/
|
||||
public void setMax(int max) {
|
||||
super.setMax(max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum allowed value of the field.
|
||||
*
|
||||
* @return the max property of the field
|
||||
* @see #setMax(int)
|
||||
*/
|
||||
public int getMax() {
|
||||
return (int) getMaxDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the allowed number intervals of the field. This specifies how much
|
||||
* the value will be increased/decreased when clicking on the
|
||||
* {@link #setStepButtonsVisible(boolean) step buttons}. It is also used to
|
||||
* invalidate the field, if the value doesn't align with the specified step
|
||||
* and {@link #setMin(int) min} (if specified by user).
|
||||
*
|
||||
* @param step
|
||||
* the new step to set
|
||||
* @throws IllegalArgumentException
|
||||
* if the argument is less or equal to zero.
|
||||
*/
|
||||
public void setStep(int step) {
|
||||
if (step <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"The step cannot be less or equal to zero.");
|
||||
}
|
||||
super.setStep(step);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the allowed number intervals of the field.
|
||||
*
|
||||
* @return the step property of the field
|
||||
* @see #setStep(int)
|
||||
*/
|
||||
public int getStep() {
|
||||
return (int) getStepDouble();
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.primefactorsolutions.invoices.views.component;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.html.Anchor;
|
||||
import com.vaadin.flow.component.html.Span;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Breadcrumbs extends HorizontalLayout {
|
||||
public Breadcrumbs(List<Pair<String, String>> parts) {
|
||||
var components = parts.stream()
|
||||
.flatMap(p -> {
|
||||
if (p.getValue() == null) {
|
||||
return Stream.of((Component)new Span(p.getKey()), (Component)new Span(">"));
|
||||
} else {
|
||||
return Stream.of((Component)new Anchor(p.getValue(), p.getKey()), (Component)new Span(">"));
|
||||
}
|
||||
}).toList();
|
||||
|
||||
if (components.size() > 1) {
|
||||
this.add(components.subList(0, components.size() - 1));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.primefactorsolutions.invoices.views.component;
|
||||
|
||||
import com.primefactorsolutions.invoices.views.Bindable;
|
||||
import com.vaadin.flow.component.ClickEvent;
|
||||
import com.vaadin.flow.component.ComponentEventListener;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CollectionContainer<T> extends VerticalLayout implements Bindable<List<T>> {
|
||||
|
||||
private List<Bindable<T>> elements = new ArrayList<>();
|
||||
|
||||
public CollectionContainer(Class<T> elementClazz) {
|
||||
Button button = new Button("Add");
|
||||
button.addClickListener((ComponentEventListener<ClickEvent<Button>>) buttonClickEvent -> {
|
||||
GenericForm<T> element = new GenericForm<>(elementClazz);
|
||||
try {
|
||||
element.setBean(elementClazz.getConstructor().newInstance());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
elements.add(element);
|
||||
add(element);
|
||||
});
|
||||
add(button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBean(Object bean) {
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
elements.get(i).setBean(((List<T>)bean).get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getBean() {
|
||||
return elements.stream().map(Bindable::getBean).collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
package com.primefactorsolutions.invoices.views.component;
|
||||
|
||||
import com.primefactorsolutions.invoices.views.Bindable;
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.Focusable;
|
||||
import com.vaadin.flow.component.datetimepicker.DateTimePicker;
|
||||
import com.vaadin.flow.component.details.Details;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.textfield.BigDecimalField;
|
||||
import com.vaadin.flow.component.textfield.IntegerField;
|
||||
import com.vaadin.flow.component.textfield.NumberField;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import javax.xml.datatype.XMLGregorianCalendar;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.primefactorsolutions.invoices.utils.TextUtils.makeLabel;
|
||||
|
||||
public class GenericForm<T> extends VerticalLayout implements Bindable<T> {
|
||||
Binder<T> binder;
|
||||
List<Pair<String, GenericForm<?>>> inner2 = new ArrayList<>();
|
||||
List<Pair<String, CollectionContainer<?>>> inner = new ArrayList<>();
|
||||
|
||||
@Getter(value = AccessLevel.PUBLIC)
|
||||
Class<T> tClass;
|
||||
|
||||
boolean recursive;
|
||||
|
||||
public GenericForm(Class<T> tClass) {
|
||||
this(tClass, false);
|
||||
}
|
||||
|
||||
public GenericForm(Class<T> tClass, boolean withDetails) {
|
||||
this.recursive = false;
|
||||
this.tClass = tClass;
|
||||
this.binder = new BeanValidationBinder<>(tClass);
|
||||
List<Component> content = getComponents(tClass).toList();
|
||||
FormLayout formLayout = new FormLayout();
|
||||
formLayout.setResponsiveSteps(
|
||||
new FormLayout.ResponsiveStep("0", 1),
|
||||
new FormLayout.ResponsiveStep("500px", 1),
|
||||
new FormLayout.ResponsiveStep("800px", 1));
|
||||
|
||||
if (withDetails) {
|
||||
Details details = new Details(tClass.getName());
|
||||
details.setOpened(true);
|
||||
details.add(formLayout);
|
||||
|
||||
for (Component c : content) {
|
||||
if (!(c instanceof CollectionContainer<?>)) {
|
||||
formLayout.add(c);
|
||||
} else {
|
||||
details.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
add(details);
|
||||
} else {
|
||||
add(formLayout);
|
||||
|
||||
for (Component c : content) {
|
||||
if (!(c instanceof CollectionContainer<?>)) {
|
||||
formLayout.add(c);
|
||||
} else {
|
||||
add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Stream<Component> getComponents(Class<?> clazz) {
|
||||
return Arrays.stream(clazz.getDeclaredFields())
|
||||
.sorted(Comparator.comparing(Field::getName))
|
||||
.flatMap(field -> {
|
||||
if (field.getType().getPackageName().startsWith("com.primefactorsolutions") && this.recursive) {
|
||||
GenericForm<?> ff = new GenericForm<>(field.getType(), true);
|
||||
inner2.add(Pair.of(field.getName(), ff));
|
||||
return Stream.of(ff);
|
||||
} else {
|
||||
final String label = makeLabel(field.getName());
|
||||
Component component = null;
|
||||
|
||||
if (field.getType().equals(String.class)) {
|
||||
component = new TextField(label);
|
||||
binder.forField((TextField)component)
|
||||
.bind(field.getName());
|
||||
} else if (field.getType().equals(Integer.class) || field.getType().equals(Integer.TYPE)) {
|
||||
final IntegerField formField = new IntegerField(label);
|
||||
binder.forField(formField)
|
||||
.bind(field.getName());
|
||||
component = formField;
|
||||
} else if (field.getType().equals(Long.class) || field.getType().equals(Long.TYPE)) {
|
||||
final LongField formField = new LongField(label);
|
||||
binder.forField(formField)
|
||||
.bind(field.getName());
|
||||
component = formField;
|
||||
} else if (field.getType().equals(BigInteger.class)) {
|
||||
var formField = new BigIntegerField(label);
|
||||
binder.forField(formField)
|
||||
.bind(field.getName());
|
||||
component = formField;
|
||||
} else if (field.getType().equals(Double.class) ||
|
||||
field.getType().equals(Double.TYPE) ||
|
||||
field.getType().equals(Float.class) ||
|
||||
field.getType().equals(Float.TYPE)) {
|
||||
var formField = new NumberField(label);
|
||||
binder.forField(formField)
|
||||
.bind(field.getName());
|
||||
component = formField;
|
||||
} else if (field.getType().equals(BigDecimal.class)) {
|
||||
var formField = new BigDecimalField(label);
|
||||
binder.forField(formField)
|
||||
.bind(field.getName());
|
||||
component = formField;
|
||||
} else if (field.getType().equals(XMLGregorianCalendar.class)) {
|
||||
component = new DateTimePicker(label);
|
||||
} else if (field.getGenericType() instanceof ParameterizedType pt) {
|
||||
final Class<?> typeArgClazz = (Class<?>) pt.getActualTypeArguments()[0];
|
||||
if (typeArgClazz.getPackageName().startsWith("com.primefactorsolutions")) {
|
||||
CollectionContainer<?> child = new CollectionContainer<>(typeArgClazz);
|
||||
inner.add(Pair.of(field.getName(), child));
|
||||
return Stream.of(child);
|
||||
} else {
|
||||
return Stream.of();
|
||||
}
|
||||
}
|
||||
if (component == null) {
|
||||
return Stream.of();
|
||||
} else {
|
||||
if (component instanceof Focusable<?> cf) {
|
||||
cf.addFocusListener((e) -> binder.isValid());
|
||||
}
|
||||
|
||||
return Stream.of(component);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void setBean(Object bean) {
|
||||
binder.setBean((T) bean);
|
||||
|
||||
for(Pair<String, GenericForm<?>> b: inner2) {
|
||||
Object foo = tClass.getDeclaredMethod("get" + StringUtils.capitalize(b.getKey())).invoke(bean);
|
||||
if (foo == null) {
|
||||
foo = tClass.getDeclaredField(b.getKey()).getType().getConstructor().newInstance();
|
||||
}
|
||||
b.getValue().setBean(foo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public T getBean() {
|
||||
T result = binder.getBean();
|
||||
|
||||
for(Pair<String, GenericForm<?>> b: inner2) {
|
||||
Object foo = b.getValue().getBean();
|
||||
tClass.getDeclaredMethod("set" + StringUtils.capitalize(b.getKey()), b.getValue().getTClass())
|
||||
.invoke(result, foo);
|
||||
}
|
||||
|
||||
for (Pair<String, CollectionContainer<?>> b: inner) {
|
||||
List<?> foo = b.getValue().getBean();
|
||||
tClass.getDeclaredMethod("set" + StringUtils.capitalize(b.getKey()), List.class).invoke(result, foo);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
package com.primefactorsolutions.invoices.views.component;
|
||||
|
||||
import com.vaadin.flow.component.Tag;
|
||||
import com.vaadin.flow.component.dependency.JsModule;
|
||||
import com.vaadin.flow.component.dependency.NpmPackage;
|
||||
import com.vaadin.flow.component.shared.HasThemeVariant;
|
||||
import com.vaadin.flow.component.textfield.AbstractNumberField;
|
||||
import com.vaadin.flow.component.textfield.TextFieldVariant;
|
||||
import com.vaadin.flow.function.SerializableFunction;
|
||||
|
||||
@Tag("vaadin-integer-field")
|
||||
@NpmPackage(value = "@vaadin/polymer-legacy-adapter", version = "24.3.10")
|
||||
@JsModule("@vaadin/polymer-legacy-adapter/style-modules.js")
|
||||
@NpmPackage(value = "@vaadin/integer-field", version = "24.3.10")
|
||||
@JsModule("@vaadin/integer-field/src/vaadin-integer-field.js")
|
||||
public class LongField extends AbstractNumberField<LongField, Long>
|
||||
implements HasThemeVariant<TextFieldVariant> {
|
||||
|
||||
private static final SerializableFunction<String, Long> PARSER = valueFormClient -> {
|
||||
if (valueFormClient == null || valueFormClient.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(valueFormClient);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final SerializableFunction<Long, String> FORMATTER = valueFromModel -> valueFromModel == null
|
||||
? ""
|
||||
: valueFromModel.toString();
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code LongField}.
|
||||
*/
|
||||
public LongField() {
|
||||
super(PARSER, FORMATTER, Long.MIN_VALUE, Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code LongField} with the given label.
|
||||
*
|
||||
* @param label
|
||||
* the text to set as the label
|
||||
*/
|
||||
public LongField(String label) {
|
||||
this();
|
||||
setLabel(label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code LongField} with the given label and
|
||||
* placeholder text.
|
||||
*
|
||||
* @param label
|
||||
* the text to set as the label
|
||||
* @param placeholder
|
||||
* the placeholder text to set
|
||||
*/
|
||||
public LongField(String label, String placeholder) {
|
||||
this(label);
|
||||
setPlaceholder(placeholder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code LongField} with a value change listener.
|
||||
*
|
||||
* @param listener
|
||||
* the value change listener
|
||||
*
|
||||
* @see #addValueChangeListener(ValueChangeListener)
|
||||
*/
|
||||
public LongField(
|
||||
ValueChangeListener<? super ComponentValueChangeEvent<LongField, Long>> listener) {
|
||||
this();
|
||||
addValueChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code LongField} with a value change listener and
|
||||
* a label.
|
||||
*
|
||||
* @param label
|
||||
* the text to set as the label
|
||||
* @param listener
|
||||
* the value change listener
|
||||
*
|
||||
* @see #setLabel(String)
|
||||
* @see #addValueChangeListener(ValueChangeListener)
|
||||
*/
|
||||
public LongField(String label,
|
||||
ValueChangeListener<? super ComponentValueChangeEvent<LongField, Long>> listener) {
|
||||
this(label);
|
||||
addValueChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code LongField} with a value change listener, a label
|
||||
* and an initial value.
|
||||
*
|
||||
* @param label
|
||||
* the text to set as the label
|
||||
* @param initialValue
|
||||
* the initial value
|
||||
* @param listener
|
||||
* the value change listener
|
||||
*
|
||||
* @see #setLabel(String)
|
||||
* @see #setValue(Object)
|
||||
* @see #addValueChangeListener(ValueChangeListener)
|
||||
*/
|
||||
public LongField(String label, Long initialValue,
|
||||
ValueChangeListener<? super ComponentValueChangeEvent<LongField, Long>> listener) {
|
||||
this(label);
|
||||
setValue(initialValue);
|
||||
addValueChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum value of the field. Entering a value which is smaller
|
||||
* than {@code min} invalidates the field.
|
||||
*
|
||||
* @param min
|
||||
* the min value to set
|
||||
*/
|
||||
public void setMin(int min) {
|
||||
super.setMin(min);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum allowed value of the field.
|
||||
*
|
||||
* @return the min property of the field
|
||||
* @see #setMin(int)
|
||||
*/
|
||||
public int getMin() {
|
||||
return (int) getMinDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum value of the field. Entering a value which is greater
|
||||
* than {@code max} invalidates the field.
|
||||
*
|
||||
* @param max
|
||||
* the max value to set
|
||||
*/
|
||||
public void setMax(int max) {
|
||||
super.setMax(max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum allowed value of the field.
|
||||
*
|
||||
* @return the max property of the field
|
||||
* @see #setMax(int)
|
||||
*/
|
||||
public int getMax() {
|
||||
return (int) getMaxDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the allowed number intervals of the field. This specifies how much
|
||||
* the value will be increased/decreased when clicking on the
|
||||
* {@link #setStepButtonsVisible(boolean) step buttons}. It is also used to
|
||||
* invalidate the field, if the value doesn't align with the specified step
|
||||
* and {@link #setMin(int) min} (if specified by user).
|
||||
*
|
||||
* @param step
|
||||
* the new step to set
|
||||
* @throws IllegalArgumentException
|
||||
* if the argument is less or equal to zero.
|
||||
*/
|
||||
public void setStep(int step) {
|
||||
if (step <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"The step cannot be less or equal to zero.");
|
||||
}
|
||||
super.setStep(step);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the allowed number intervals of the field.
|
||||
*
|
||||
* @return the step property of the field
|
||||
* @see #setStep(int)
|
||||
*/
|
||||
public int getStep() {
|
||||
return (int) getStepDouble();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.primefactorsolutions.invoices.views.component.invoice;
|
||||
|
||||
import com.primefactorsolutions.invoices.views.component.LongField;
|
||||
import com.vaadin.flow.component.datetimepicker.DateTimePicker;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.textfield.BigDecimalField;
|
||||
import com.vaadin.flow.component.textfield.IntegerField;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
|
||||
public class CabeceraForm<T> extends FormLayout {
|
||||
public Binder<T> binder;
|
||||
|
||||
LongField nitEmisor = new LongField("nitEmisor");
|
||||
TextField razonSocialEmisor = new TextField("razonSocialEmisor");
|
||||
TextField municipio = new TextField("municipio");
|
||||
TextField telefono = new TextField("telefono");
|
||||
IntegerField codigoSucursal = new IntegerField("codigoSucursal");
|
||||
TextField direccion = new TextField("direccion");
|
||||
IntegerField codigoPuntoVenta = new IntegerField("codigoPuntoVenta");
|
||||
DateTimePicker fechaEmision = new DateTimePicker("fechaEmision");
|
||||
IntegerField codigoMoneda = new IntegerField("codigoMoneda");
|
||||
BigDecimalField tipoCambio = new BigDecimalField("tipoCambio");
|
||||
|
||||
public CabeceraForm(Class<T> clazz) {
|
||||
binder = new BeanValidationBinder<>(clazz);
|
||||
binder.bindInstanceFields(this);
|
||||
setResponsiveSteps(
|
||||
new ResponsiveStep("0", 1),
|
||||
new ResponsiveStep("500px", 3),
|
||||
new ResponsiveStep("800px", 5));
|
||||
setColspan(razonSocialEmisor, 5);
|
||||
setColspan(direccion, 5);
|
||||
|
||||
add(nitEmisor,
|
||||
fechaEmision,
|
||||
razonSocialEmisor,
|
||||
direccion,
|
||||
municipio,
|
||||
telefono,
|
||||
codigoSucursal,
|
||||
codigoPuntoVenta,
|
||||
codigoMoneda,
|
||||
tipoCambio
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.primefactorsolutions.invoices.views.component.invoice;
|
||||
|
||||
import com.primefactorsolutions.invoices.views.component.LongField;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.textfield.IntegerField;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
|
||||
public class ClientForm<T> extends FormLayout {
|
||||
public Binder<T> binder;
|
||||
TextField nombreRazonSocial = new TextField("nombreRazonSocial");
|
||||
IntegerField codigoTipoDocumentoIdentidad = new IntegerField("codigoTipoDocumentoIdentidad");
|
||||
TextField numeroDocumento = new TextField("numeroDocumento");
|
||||
TextField complemento = new TextField("complemento");
|
||||
TextField direccionComprador = new TextField("direccionComprador");
|
||||
TextField codigoCliente = new TextField("codigoCliente");
|
||||
TextField lugarDestino = new TextField("lugarDestino");
|
||||
IntegerField codigoPais = new IntegerField("codigoPais");
|
||||
IntegerField codigoMetodoPago = new IntegerField("codigoMetodoPago");
|
||||
LongField numeroTarjeta = new LongField("numeroTarjeta");
|
||||
|
||||
public ClientForm(Class<T> clazz) {
|
||||
binder = new BeanValidationBinder<>(clazz);
|
||||
binder.bindInstanceFields(this);
|
||||
setResponsiveSteps(
|
||||
new ResponsiveStep("0", 1),
|
||||
new ResponsiveStep("500px", 3),
|
||||
new ResponsiveStep("800px", 5));
|
||||
setColspan(nombreRazonSocial, 5);
|
||||
setColspan(direccionComprador, 5);
|
||||
|
||||
add(nombreRazonSocial,
|
||||
direccionComprador,
|
||||
codigoTipoDocumentoIdentidad,
|
||||
numeroDocumento,
|
||||
complemento,
|
||||
codigoCliente,
|
||||
lugarDestino,
|
||||
codigoPais,
|
||||
codigoMetodoPago,
|
||||
numeroTarjeta
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.primefactorsolutions.invoices.views.component.invoice;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.primefactorsolutions.invoices.model.Client;
|
||||
import com.primefactorsolutions.invoices.services.ClientService;
|
||||
import com.vaadin.flow.component.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ClientInputForm extends FormLayout {
|
||||
public Binder<Client> binder;
|
||||
ComboBox<Client> queryText = new ComboBox<>("correoElectronico o telefono");
|
||||
List<Consumer<Client>> listeners = Lists.newArrayList();
|
||||
|
||||
public ClientInputForm(ClientService clientService) {
|
||||
binder = new BeanValidationBinder<>(Client.class);
|
||||
|
||||
queryText.setPlaceholder("Buscar ...");
|
||||
queryText.setItemLabelGenerator(Client::getNombreRazonSocial);
|
||||
queryText.setItemsWithFilterConverter(
|
||||
query -> {
|
||||
var limit = Math.min(query.getPageSize(), query.getLimit());
|
||||
var page = Math.min(query.getPage(), query.getOffset());
|
||||
return clientService.findAllClients(query.getFilter().orElse(""),
|
||||
PageRequest.of(page, limit)).stream();
|
||||
},
|
||||
personSearchTerm -> personSearchTerm
|
||||
);
|
||||
queryText.addValueChangeListener(event -> listeners.forEach(c -> c.accept(event.getValue())));
|
||||
|
||||
add(queryText);
|
||||
}
|
||||
|
||||
public void addListener(Consumer<Client> listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.primefactorsolutions.invoices.views.component.invoice;
|
||||
|
||||
import com.primefactorsolutions.invoices.views.component.BigIntegerField;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.html.Hr;
|
||||
import com.vaadin.flow.component.textfield.BigDecimalField;
|
||||
import com.vaadin.flow.component.textfield.IntegerField;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
|
||||
import static com.primefactorsolutions.invoices.utils.TextUtils.makeLabel;
|
||||
|
||||
public class DetalleForm<T> extends FormLayout {
|
||||
Binder<T> binder;
|
||||
|
||||
TextField actividadEconomica = new TextField(makeLabel("actividadEconomica"));
|
||||
TextField descripcion = new TextField("descripcion");
|
||||
BigIntegerField cantidad = new BigIntegerField("cantidad");
|
||||
IntegerField unidadMedida = new IntegerField("unidadMedida");
|
||||
BigDecimalField precioUnitario = new BigDecimalField("precioUnitario");
|
||||
BigDecimalField montoDescuento = new BigDecimalField("montoDescuento");
|
||||
BigDecimalField subTotal = new BigDecimalField("subTotal");
|
||||
Hr separator = new Hr();
|
||||
|
||||
DetalleForm(Class<T> clazz) {
|
||||
super();
|
||||
binder = new BeanValidationBinder<>(clazz);
|
||||
binder.bindInstanceFields(this);
|
||||
setResponsiveSteps(
|
||||
new ResponsiveStep("0", 1),
|
||||
new ResponsiveStep("500px", 3),
|
||||
new ResponsiveStep("800px", 6));
|
||||
setColspan(descripcion, 6);
|
||||
setColspan(separator, 6);
|
||||
|
||||
add(descripcion,
|
||||
actividadEconomica,
|
||||
cantidad,
|
||||
unidadMedida,
|
||||
precioUnitario,
|
||||
montoDescuento,
|
||||
subTotal,
|
||||
separator
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package com.primefactorsolutions.invoices.views.component.invoice;
|
||||
|
||||
import com.vaadin.flow.component.ComponentEvent;
|
||||
import com.vaadin.flow.component.ComponentEventListener;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.shared.Registration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DetallesForm<T> extends VerticalLayout {
|
||||
|
||||
Class<T> clazz;
|
||||
Supplier<T> supplier;
|
||||
|
||||
public DetallesForm(Class<T> clazz, Supplier<T> supplier) {
|
||||
this.clazz = clazz;
|
||||
this.supplier = supplier;
|
||||
addDetalle();
|
||||
}
|
||||
|
||||
public void addDetalle() {
|
||||
var content = new VerticalLayout();
|
||||
var value = supplier.get();
|
||||
var detalle = new DetalleForm<>(clazz);
|
||||
detalle.binder.setBean(value);
|
||||
|
||||
detalle.binder.addValueChangeListener(v -> {
|
||||
fireEvent(new ChangeEvent(this, true));
|
||||
});
|
||||
|
||||
content.add(detalle);
|
||||
var delButton = new Button("Remove");
|
||||
delButton.addClickListener(c -> this.remove(content));
|
||||
content.add(delButton);
|
||||
|
||||
add(content);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<T> getValues() {
|
||||
return getChildren()
|
||||
.flatMap(d -> {
|
||||
return d.getChildren()
|
||||
.map(c -> {
|
||||
if (c instanceof DetalleForm) {
|
||||
return ((DetalleForm<T>) c).binder.getBean();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Registration addChangeListener(
|
||||
ComponentEventListener<DetallesForm.ChangeEvent> listener) {
|
||||
return addListener(DetallesForm.ChangeEvent.class, listener);
|
||||
}
|
||||
|
||||
public static class ChangeEvent
|
||||
extends ComponentEvent<DetallesForm<?>> {
|
||||
public ChangeEvent(DetallesForm source,
|
||||
boolean fromClient) {
|
||||
super(source, fromClient);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.primefactorsolutions.invoices.views.component.invoice;
|
||||
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.textfield.BigDecimalField;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
|
||||
public class TotalesForm<T> extends FormLayout {
|
||||
public Binder<T> binder;
|
||||
BigDecimalField montoTotal = new BigDecimalField("montoTotal");
|
||||
BigDecimalField montoTotalSujetoIva = new BigDecimalField("montoTotalSujetoIva");
|
||||
BigDecimalField montoTotalMoneda = new BigDecimalField("montoTotalMoneda");
|
||||
TextField informacionAdicional = new TextField("informacionAdicional");
|
||||
BigDecimalField descuentoAdicional = new BigDecimalField("descuentoAdicional");
|
||||
public TotalesForm(Class<T> clazz) {
|
||||
binder = new BeanValidationBinder<>(clazz);
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
setResponsiveSteps(
|
||||
new ResponsiveStep("0", 1),
|
||||
new ResponsiveStep("500px", 3),
|
||||
new ResponsiveStep("800px", 5));
|
||||
setColspan(informacionAdicional, 5);
|
||||
|
||||
add(
|
||||
montoTotalMoneda,
|
||||
montoTotal,
|
||||
descuentoAdicional,
|
||||
montoTotalSujetoIva,
|
||||
informacionAdicional
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.primefactorsolutions.invoices.xml.adapters;
|
||||
|
||||
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
|
||||
public class DateTimeXmlAdapter extends XmlAdapter<String, LocalDateTime> {
|
||||
|
||||
@Override
|
||||
public String marshal(LocalDateTime v) throws Exception {
|
||||
return v.toInstant(ZoneOffset.UTC).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime unmarshal(String v) throws Exception {
|
||||
return LocalDateTime.ofInstant(Instant.parse(v), ZoneId.of("UTC"));
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.primefactorsolutions.invoices.xml.adapters;
|
||||
|
||||
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
public class DateXmlAdapter extends XmlAdapter<String, Date> {
|
||||
|
||||
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public String marshal(Date v) throws Exception {
|
||||
synchronized (dateFormat) {
|
||||
return dateFormat.format(v);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date unmarshal(String v) throws Exception {
|
||||
synchronized (dateFormat) {
|
||||
return dateFormat.parse(v);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,5 +6,10 @@ spring.mustache.check-template-location = false
|
||||
vaadin.launch-browser = true
|
||||
# To improve the performance during development.
|
||||
# For more information https://vaadin.com/docs/latest/integrations/spring/configuration#special-configuration-parameters
|
||||
vaadin.allowed-packages = com.vaadin,org.vaadin,dev.hilla,com.example.application
|
||||
vaadin.allowed-packages = com.vaadin,org.vaadin,dev.hilla,com.primefactorsolutions.invoices
|
||||
spring.jpa.defer-datasource-initialization = true
|
||||
spring.datasource.initialize = false
|
||||
spring.jpa.show-sql = true
|
||||
|
||||
spring.jpa.properties.hibernate.search.backend.directory.type=local-heap
|
||||
#spring.jpa.properties.hibernate.search.backend.directory.root = target/
|
||||
|
17
src/main/resources/bindings/bindings.xjb
Normal file
17
src/main/resources/bindings/bindings.xjb
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<jaxb:bindings
|
||||
xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:annox="urn:jaxb.jvnet.org:annox"
|
||||
xsi:schemaLocation="https://jakarta.ee/xml/ns/jaxb https://jakarta.ee/xml/ns/jaxb/bindingschema_3_0.xsd"
|
||||
jaxb:extensionBindingPrefixes="xjc annox"
|
||||
version="3.0">
|
||||
|
||||
<jaxb:globalBindings typesafeEnumMemberName="generateName">
|
||||
<xjc:javaType name="java.time.LocalDate" xmlType="xs:date"
|
||||
adapter="com.primefactorsolutions.invoices.xml.adapters.DateXmlAdapter" />
|
||||
<xjc:javaType name="java.time.LocalDateTime" xmlType="xs:dateTime"
|
||||
adapter="com.primefactorsolutions.invoices.xml.adapters.DateTimeXmlAdapter" />
|
||||
</jaxb:globalBindings>
|
||||
</jaxb:bindings>
|
@ -1,64 +1,18 @@
|
||||
INSERT INTO "STATUS" (ID, VERSION, NAME) VALUES
|
||||
(1, 1, 'Imported lead'),
|
||||
(2, 1, 'Not contacted'),
|
||||
(3, 1, 'Contacted'),
|
||||
(4, 1, 'Customer'),
|
||||
(5, 1, 'Closed (lost)');
|
||||
INSERT INTO "COMPANY" (ID, VERSION, NAME) VALUES
|
||||
(6, 1, 'Phillips Van Heusen Corp.'),
|
||||
(7, 1, 'Avaya Inc.'),
|
||||
(8, 1, 'Laboratory Corporation of America Holdings'),
|
||||
(9, 1, 'AutoZone, Inc.'),
|
||||
(10, 1, 'Linens ''n Things Inc.');
|
||||
INSERT INTO "CONTACT" (ID, VERSION, EMAIL,FIRST_NAME,LAST_NAME,COMPANY_ID,STATUS_ID) VALUES
|
||||
(11, 1, 'eula.lane@jigrormo.ye', 'Eula', 'Lane', 8, 1),
|
||||
(12, 1, 'barry.rodriquez@zun.mm', 'Barry', 'Rodriquez', 7, 5),
|
||||
(13, 1, 'eugenia.selvi@capfad.vn', 'Eugenia', 'Selvi', 6, 3),
|
||||
(14, 1, 'alejandro.miles@dec.bn', 'Alejandro', 'Miles', 10, 3),
|
||||
(15, 1, 'cora.tesi@bivo.yt', 'Cora', 'Tesi', 6, 4),
|
||||
(16, 1, 'marguerite.ishii@judbilo.gn', 'Marguerite', 'Ishii', 10, 2),
|
||||
(17, 1, 'mildred.jacobs@joraf.wf', 'Mildred', 'Jacobs', 8, 1),
|
||||
(18, 1, 'gene.goodman@kem.tl', 'Gene', 'Goodman', 8, 5),
|
||||
(19, 1, 'lettie.bennett@odeter.bb', 'Lettie', 'Bennett', 6, 1),
|
||||
(20, 1, 'mabel.leach@lisohuje.vi', 'Mabel', 'Leach', 10, 2),
|
||||
(21, 1, 'jordan.miccinesi@duod.gy', 'Jordan', 'Miccinesi', 8, 3),
|
||||
(22, 1, 'marie.parkes@nowufpus.ph', 'Marie', 'Parkes', 7, 1),
|
||||
(23, 1, 'rose.gray@kagu.hr', 'Rose', 'Gray', 9, 4),
|
||||
(24, 1, 'garrett.stokes@fef.bg', 'Garrett', 'Stokes', 9, 3),
|
||||
(25, 1, 'barbara.matthieu@derwogi.jm', 'Barbara', 'Matthieu', 7, 5),
|
||||
(26, 1, 'jean.rhodes@wehovuce.gu', 'Jean', 'Rhodes', 7, 3),
|
||||
(27, 1, 'jack.romoli@zamum.bw', 'Jack', 'Romoli', 6, 4),
|
||||
(28, 1, 'pearl.holden@dunebuh.cr', 'Pearl', 'Holden', 8, 1),
|
||||
(29, 1, 'belle.montero@repiwid.si', 'Belle', 'Montero', 9, 5),
|
||||
(30, 1, 'olive.molina@razuppa.ga', 'Olive', 'Molina', 6, 2),
|
||||
(31, 1, 'minerva.todd@kulmenim.ad', 'Minerva', 'Todd', 9, 3),
|
||||
(32, 1, 'bobby.pearson@ib.kg', 'Bobby', 'Pearson', 9, 1),
|
||||
(33, 1, 'larry.ciappi@ba.lk', 'Larry', 'Ciappi', 10, 2),
|
||||
(34, 1, 'ronnie.salucci@tohhij.lv', 'Ronnie', 'Salucci', 9, 1),
|
||||
(35, 1, 'walter.grossi@tuvo.sa', 'Walter', 'Grossi', 9, 1);
|
||||
INSERT INTO "CONTACT" (ID, VERSION, EMAIL,FIRST_NAME,LAST_NAME,COMPANY_ID,STATUS_ID) VALUES
|
||||
(36, 1, 'frances.koopmans@foga.tw', 'Frances', 'Koopmans', 7, 5),
|
||||
(37, 1, 'frances.fujimoto@uswuzzub.jp', 'Frances', 'Fujimoto', 6, 5),
|
||||
(38, 1, 'olivia.vidal@hivwerip.vc', 'Olivia', 'Vidal', 9, 2),
|
||||
(39, 1, 'edna.henry@gugusu.rw', 'Edna', 'Henry', 8, 4),
|
||||
(40, 1, 'lydia.brun@zedekak.md', 'Lydia', 'Brun', 7, 3),
|
||||
(41, 1, 'jay.blake@ral.mk', 'Jay', 'Blake', 10, 4),
|
||||
(42, 1, 'isabel.serafini@turuhu.bh', 'Isabel', 'Serafini', 10, 1),
|
||||
(43, 1, 'rebecca.carter@omjo.et', 'Rebecca', 'Carter', 8, 4),
|
||||
(44, 1, 'maurice.fabbrini@rig.bh', 'Maurice', 'Fabbrini', 9, 3),
|
||||
(45, 1, 'ollie.turnbull@sicewap.org', 'Ollie', 'Turnbull', 6, 1),
|
||||
(46, 1, 'jerry.hopkins@fo.mh', 'Jerry', 'Hopkins', 9, 5),
|
||||
(47, 1, 'nora.lyons@gegijap.na', 'Nora', 'Lyons', 10, 1),
|
||||
(48, 1, 'anne.weis@kuvesa.pe', 'Anne', 'Weis', 7, 4),
|
||||
(49, 1, 'louise.gauthier@lapahu.mt', 'Louise', 'Gauthier', 6, 2),
|
||||
(50, 1, 'lloyd.fani@zev.ru', 'Lloyd', 'Fani', 8, 1),
|
||||
(51, 1, 'maud.dunn@nabeaga.ni', 'Maud', 'Dunn', 6, 1),
|
||||
(52, 1, 'henry.gigli@kaot.ps', 'Henry', 'Gigli', 6, 5),
|
||||
(53, 1, 'virgie.werner@tawuctuj.cf', 'Virgie', 'Werner', 10, 4),
|
||||
(54, 1, 'gregory.cozzi@eh.ru', 'Gregory', 'Cozzi', 8, 2),
|
||||
(55, 1, 'lucinda.gil@fajjusuz.kr', 'Lucinda', 'Gil', 7, 5),
|
||||
(56, 1, 'gertrude.verbeek@pave.cc', 'Gertrude', 'Verbeek', 6, 5),
|
||||
(57, 1, 'mattie.graham@ispaviw.gt', 'Mattie', 'Graham', 7, 2),
|
||||
(58, 1, 'bryan.shaw@ha.ee', 'Bryan', 'Shaw', 9, 1),
|
||||
(59, 1, 'essie.adams@iliat.cw', 'Essie', 'Adams', 8, 5),
|
||||
(60, 1, 'gary.osborne@do.ga', 'Gary', 'Osborne', 7, 5);
|
||||
INSERT INTO "COMPANY" (ID, VERSION, NIT_EMISOR, RAZON_SOCIAL_EMISOR, TELEFONO, MUNICIPIO, DIRECCION)
|
||||
VALUES ('108ace19-6d78-4a70-a01f-30b9e3f6b2b8', 1, '1234567890', 'PFS', '4567890', 'Cochabamba', 'Calle Test 123');
|
||||
|
||||
INSERT INTO "INVOICE" (ID, VERSION, COMPANY_ID, NOMBRE_RAZON_SOCIAL, FECHA_EMISION, PAYLOAD, STATUS)
|
||||
VALUES ('0d8c7cc0-d43c-4e7e-9c8a-81f070fbf436', 1, '108ace19-6d78-4a70-a01f-30b9e3f6b2b8', 'Metadao', '2024-01-01T12:00:00', '{}', 0);
|
||||
|
||||
INSERT INTO "CLIENT" (ID, VERSION, COMPANY_ID, STATUS, CORREO_ELECTRONICO, TELEFONO, NOMBRE_RAZON_SOCIAL,
|
||||
CODIGO_TIPO_DOCUMENTO_IDENTIDAD, NUMERO_DOCUMENTO, DIRECCION_COMPRADOR, CODIGO_CLIENTE, CODIGO_PAIS,
|
||||
CODIGO_METODO_PAGO, NUMERO_TARJETA)
|
||||
VALUES ('d36b4edf-e7ad-43de-8305-9dc39a61a0d0', 1, '108ace19-6d78-4a70-a01f-30b9e3f6b2b8', 1,
|
||||
'alexprud@gmail.com', 12345678, 'Alex prudencio', 1, '123123123', 'test av. 123', '1', 1, 1, 45000099988);
|
||||
|
||||
INSERT INTO "PRODUCT" (ID, VERSION, COMPANY_ID, STATUS, codigo_Producto_Sin, codigo_Producto, descripcion, unidad_Medida,
|
||||
precio_Unitario) VALUES ('dcecb825-7bc6-402d-850a-9d4a08fe6663', 1, '108ace19-6d78-4a70-a01f-30b9e3f6b2b8', 1, 1,
|
||||
'PROD001', 'Test product', 1, 1);
|
||||
|
||||
INSERT INTO "USER_" (ID, VERSION, COMPANY_ID, EMAIL, FULL_NAME, ROLE, STATUS) VALUES ('b9f1bbe0-4542-48d3-b88e-452f2891cb68',
|
||||
1, '108ace19-6d78-4a70-a01f-30b9e3f6b2b8', 'alex@test.com', 'alex prudencio', 1, 1);
|
182
src/main/resources/help/ComercialExportacionServicio.json
Normal file
182
src/main/resources/help/ComercialExportacionServicio.json
Normal file
@ -0,0 +1,182 @@
|
||||
{
|
||||
"sections": [
|
||||
{
|
||||
"name": "cabecera",
|
||||
"entries": [
|
||||
{
|
||||
"name": "nitEmisor",
|
||||
"text": "N\u00famero de NIT registrado en el Padr\u00f3n Nacional de Contribuyentes que corresponde a la persona o empresa que emite la factura. Nota.- Consignar el valor de uno (1) en cantidad consignar 1, 58 (Unidad Servicio) en unidad de medida y el precio del servicio como precio unitario."
|
||||
},
|
||||
{
|
||||
"name": "razonSocialEmisor",
|
||||
"text": "Raz\u00f3n Social o nombre registrado en el Padr\u00f3n Nacional de Contribuyentes de la persona o empresa que emite la factura."
|
||||
},
|
||||
{
|
||||
"name": "municipio",
|
||||
"text": "Lugar registrado en el Padr\u00f3n Nacional de contribuyentes"
|
||||
},
|
||||
{
|
||||
"name": "telefono",
|
||||
"text": "Tel\u00e9fono registrado en el Padr\u00f3n Nacional de contribuyentes"
|
||||
},
|
||||
{
|
||||
"name": "numeroFactura",
|
||||
"text": "N\u00famero asignado a la factura."
|
||||
},
|
||||
{
|
||||
"name": "cuf",
|
||||
"text": "C\u00f3digo \u00fanico de facturaci\u00f3n (CUF) debe ser generado por el emisor siguiendo el algoritmo indicado."
|
||||
},
|
||||
{
|
||||
"name": "cufd",
|
||||
"text": "C\u00f3digo \u00fanico de facturaci\u00f3n diario (CUFD), valor \u00fanico que se obtiene al consumir el servicio web correspondiente."
|
||||
},
|
||||
{
|
||||
"name": "codigoSucursal",
|
||||
"text": "C\u00f3digo de la sucursal registrada en el Padr\u00f3n y en la cual se est\u00e1 emitiendo la factura. Por ejemplo: sucursal = 0 (casa matriz)."
|
||||
},
|
||||
{
|
||||
"name": "direccion",
|
||||
"text": "Direcci\u00f3n de la sucursal registrada en el Padr\u00f3n Nacional de Contribuyentes."
|
||||
},
|
||||
{
|
||||
"name": "codigoPuntoVenta",
|
||||
"text": "C\u00f3digo del punto de Venta creado mediante un servicio web\u00a0y en el cual se emite la factura."
|
||||
},
|
||||
{
|
||||
"name": "fechaEmision",
|
||||
"text": "Fecha y hora en la cual se emite la factura. Expresada en formato UTC Extendido, por ejemplo: \u201c2020-02-15T08:40:12.215\u201d."
|
||||
},
|
||||
{
|
||||
"name": "nombreRazonSocial",
|
||||
"text": "Raz\u00f3n Social o nombre de la persona u empresa a la cual se emite la factura."
|
||||
},
|
||||
{
|
||||
"name": "codigoTipoDocumentoIdentidad",
|
||||
"text": "Valor de la param\u00e9trica que identifica el Tipo de Documento utilizado para la emisi\u00f3n de la factura. Puede contener valores que van del 1 al 5. \u00a0(Ejemplo 1 que representa al CI)."
|
||||
},
|
||||
{
|
||||
"name": "numeroDocumento",
|
||||
"text": "N\u00famero que corresponde al Tipo de Documento Identidad utilizado y al cual se realizar\u00e1 la facturaci\u00f3n."
|
||||
},
|
||||
{
|
||||
"name": "complemento",
|
||||
"text": "Valor que otorga el SEGIP en casos de c\u00e9dulas de identidad con n\u00famero duplicado."
|
||||
},
|
||||
{
|
||||
"name": "direccionComprador",
|
||||
"text": "Direcci\u00f3n donde se est\u00e1 exportando."
|
||||
},
|
||||
{
|
||||
"name": "codigoCliente",
|
||||
"text": "C\u00f3digo de identificaci\u00f3n \u00fanico del cliente, deber\u00e1 ser asignado por el sistema de facturaci\u00f3n del contribuyente."
|
||||
},
|
||||
{
|
||||
"name": "lugarDestino",
|
||||
"text": "Lugar al cual se est\u00e1 realizando la exportaci\u00f3n."
|
||||
},
|
||||
{
|
||||
"name": "codigoPais",
|
||||
"text": "Valor de la param\u00e9trica que identifica el tipo de pa\u00eds."
|
||||
},
|
||||
{
|
||||
"name": "codigoMetodoPago",
|
||||
"text": "Valor de la param\u00e9trica que identifica el m\u00e9todo de pago utilizado para realizar la compra. Por ejemplo 1 que representa a un pago en efectivo."
|
||||
},
|
||||
{
|
||||
"name": "numeroTarjeta",
|
||||
"text": "Cuando el m\u00e9todo de pago es 2 (Tarjeta), debe enviarse este valor pero ofuscado con los primeros y \u00faltimos 4 d\u00edgitos en claro y ceros al medio. Ej: 4797000000007896, en otro caso, debe enviarse un valor nulo."
|
||||
},
|
||||
{
|
||||
"name": "montoTotal",
|
||||
"text": "Monto total por el cual se realiza el hecho generador."
|
||||
},
|
||||
{
|
||||
"name": "montoTotalSujetoIva",
|
||||
"text": "Seteada a cero (0) por defecto para este sector"
|
||||
},
|
||||
{
|
||||
"name": "codigoMoneda",
|
||||
"text": "Valor de la param\u00e9trica que identifica la moneda en la cual se realiza la transacci\u00f3n."
|
||||
},
|
||||
{
|
||||
"name": "tipoCambio",
|
||||
"text": "Tipo de cambio de acuerdo a la moneda en la que se realiza el hecho generador, si el c\u00f3digo de moneda es boliviano deber\u00e1 ser igual a 1."
|
||||
},
|
||||
{
|
||||
"name": "montoTotalMoneda",
|
||||
"text": "Es el Monto Total expresado en el tipo de moneda, si el c\u00f3digo de moneda es boliviano deber\u00e1 ser igual al monto total."
|
||||
},
|
||||
{
|
||||
"name": "informacionAdicional",
|
||||
"text": "Informaci\u00f3n Adicional."
|
||||
},
|
||||
{
|
||||
"name": "descuentoAdicional",
|
||||
"text": "Descuento adicional a ser aplicado. cero (0) si no aplica"
|
||||
},
|
||||
{
|
||||
"name": "codigoExcepcion",
|
||||
"text": "Por defecto, enviar este campo con un valor de cero (0) o nulo. Solo cuando se desee autorizar al SIN el registro de una factura emitida a un NIT inv\u00e1lido se debe enviar\u00a0el valor de uno (1) en el mismo"
|
||||
},
|
||||
{
|
||||
"name": "cafc",
|
||||
"text": "C\u00f3digo de Autorizaci\u00f3n de Facturas por Contingencia"
|
||||
},
|
||||
{
|
||||
"name": "leyenda",
|
||||
"text": "Leyenda asociada a la actividad econ\u00f3mica."
|
||||
},
|
||||
{
|
||||
"name": "usuario",
|
||||
"text": "Identifica al usuario que emite la factura, deber\u00e1 ser descriptivo. Por ejemplo JPEREZ."
|
||||
},
|
||||
{
|
||||
"name": "codigoDocumentoSector",
|
||||
"text": "Valor de la param\u00e9trica que identifica el tipo de factura que se est\u00e1 emitiendo. Para este tipo de factura este valor es 28."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "detalle",
|
||||
"entries": [
|
||||
{
|
||||
"name": "actividadEconomica",
|
||||
"text": "Actividad econ\u00f3mica registrada en el Padr\u00f3n Nacional de Contribuyentes relacionada al NIT."
|
||||
},
|
||||
{
|
||||
"name": "codigoProductoSin",
|
||||
"text": "Homologado a los c\u00f3digos de productos gen\u00e9ricos enviados por el SIN a trav\u00e9s del servicio de sincronizaci\u00f3n."
|
||||
},
|
||||
{
|
||||
"name": "codigoProducto",
|
||||
"text": "C\u00f3digo que otorga el contribuyente a su servicio o producto."
|
||||
},
|
||||
{
|
||||
"name": "descripcion",
|
||||
"text": "Descripci\u00f3n que otorga el contribuyente a su servicio o producto."
|
||||
},
|
||||
{
|
||||
"name": "cantidad",
|
||||
"text": "Cantidad del producto o servicio otorgado. En caso de servicio este valor debe ser 1."
|
||||
},
|
||||
{
|
||||
"name": "unidadMedida",
|
||||
"text": "Valor de la param\u00e9trica que identifica la unidad de medida."
|
||||
},
|
||||
{
|
||||
"name": "precioUnitario",
|
||||
"text": "Precio que otorga el contribuyente a su servicio o producto."
|
||||
},
|
||||
{
|
||||
"name": "montoDescuento",
|
||||
"text": "Monto de descuento sobre el producto o servicio espec\u00edfico, para el caso de la factura comercial de exportaci\u00f3n se deber\u00e1 enviar el valor 0 si no aplica."
|
||||
},
|
||||
{
|
||||
"name": "subTotal",
|
||||
"text": "El subtotal es igual a la (cantidad * precio unitario) \u2013 descuento."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
127
src/main/resources/pfs-invoice.html
Normal file
127
src/main/resources/pfs-invoice.html
Normal file
@ -0,0 +1,127 @@
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
@page {
|
||||
size: 7in 9.25in;
|
||||
margin: 27mm 16mm 27mm 16mm;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:100%;">
|
||||
<table style="float: left;">
|
||||
<tr>
|
||||
<td>${cabecera.razonSocial!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>${cabecera.direccion!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>${cabecera.telefono!""}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table style="float: right;">
|
||||
<tr>
|
||||
<td>NIT</td><td>${cabecera.nitEmisor!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Factura</td><td>${cabecera.numeroFactura!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cod. Aut.</td><td>${cabecera.cuf!""}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
<h3 style="text-align:center;">FACTURA COMERCIAL DE EXPORTACIÓN DE SERVICIOS</h3>
|
||||
<div style="width: 100%; margin-bottom: 2em; margin-top: 2em;">
|
||||
<table style="float: left;">
|
||||
<tr>
|
||||
<td>Fecha:</td><td>${cabecera.fechaEmision!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Nombre/Razón Social:</td><td>${cabecera.nombreRazonSocial!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tipo de cambio:</td><td>${cabecera.tipoCambio!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Moneda de la Transaccción Comercial:</td><td>${cabecera.moneda!""}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table style="float: right;">
|
||||
<tr>
|
||||
<td>NIT/CI/CEX:</td><td>${cabecera.numeroDocumento!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cod. Cliente:</td><td>${cabecera.codigoCliente!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Dirección Comprador:</td><td>${cabecera.direccionComprador!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Lugar Destino:</td><td>${cabecera.lugarDestino!""}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
<table style="width: 100%; border: 1px solid black; margin-top: 2em;">
|
||||
<thead style="border: 1px solid black; background-color: lightgray;">
|
||||
<tr>
|
||||
<th>CÓDIGO SERVICIO</th>
|
||||
<th>CANTIDAD</th>
|
||||
<th>UNIDAD MEDIDA</th>
|
||||
<th>DESCRIPCIÓN</th>
|
||||
<th>PRECIO UNITARIO</th>
|
||||
<th>DESCUENTO</th>
|
||||
<th>SUBTOTAL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<#list detalle as d>
|
||||
<tr>
|
||||
<th>${d.codigoProducto!""}</th>
|
||||
<th>${d.cantidad!""}</th>
|
||||
<th>${d.unidadMedida!""}</th>
|
||||
<th>${d.descripcion!""}</th>
|
||||
<th>${d.precioUnitario!""}</th>
|
||||
<th>${d.montoDescuento!""}</th>
|
||||
<th>${d.subtotal!""}</th>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
<table style="float: right; border: 1px solid black;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>SUBTOTAL (DÓLAR ESTADOUNIDENSE)</td>
|
||||
<td>${cabecera.subtotalMoneda!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DESCUENTO (DÓLAR ESTADOUNIDENSE)</td>
|
||||
<td>${cabecera.descuentoAdicional!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TOTAL GENERAL (DÓLAR ESTADOUNIDENSE)</td>
|
||||
<td>${cabecera.montoTotalMoneda!""}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TOTAL GENERAL (BOLIVIANOS)</td>
|
||||
<td>${cabecera.montoTotal!""}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="clear:both;"></div>
|
||||
<h4>Informacion Adicional</h4>
|
||||
<p style="border: 1px solid black;">${cabecera.informacionAdicional!""}</p>
|
||||
<hr/>
|
||||
<p style="font-size: smaller;">
|
||||
ESTA FACTURA CONTRIBUYE AL DESARROLLO DEL PAÍS, EL USO ILÍCITO SERÁ SANCIONADO PENALMENTE DE ACUERDO A LEY Ley N° 453:
|
||||
El proveedor debe brindar atención sin discriminación, con respeto, calidez y cordialidad a los usuarios y consumidores.
|
||||
<em>“Este documento es la Representación Gráfica de un Documento Fiscal Digital emitido en una modalidad de facturación en línea”</em>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
340
src/main/resources/schemas/facturaComputarizadaComercialExportacionServicio.xsd
Executable file
340
src/main/resources/schemas/facturaComputarizadaComercialExportacionServicio.xsd
Executable file
@ -0,0 +1,340 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- XSD ver.23/08/2021 -->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
attributeFormDefault="unqualified" elementFormDefault="qualified">
|
||||
<xs:element name="facturaComputarizadaComercialExportacionServicio">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="cabecera">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="nitEmisor">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="9999999999999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="razonSocialEmisor">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="200"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="municipio">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="25"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="telefono" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="25"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="numeroFactura">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="9999999999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cuf">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="100"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cufd">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="100"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoSucursal">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="0"/>
|
||||
<xs:maxInclusive value="9999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="direccion">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="500"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoPuntoVenta" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="0"/>
|
||||
<xs:maxInclusive value="9999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="fechaEmision" type="xs:dateTime"/>
|
||||
<xs:element name="nombreRazonSocial" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="500"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoTipoDocumentoIdentidad">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="5"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="numeroDocumento">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="20"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="complemento" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="5"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="direccionComprador">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="500"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoCliente">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="100"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="lugarDestino">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="500"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoPais">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="212"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoMetodoPago">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="308"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="numeroTarjeta" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="0"/>
|
||||
<xs:maxInclusive value="9999999999999999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="montoTotal">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="17"/>
|
||||
<xs:fractionDigits value="2"/>
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="montoTotalSujetoIva" type="xs:decimal" fixed="0"/>
|
||||
<xs:element name="codigoMoneda">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="154"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="tipoCambio">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="17"/>
|
||||
<xs:fractionDigits value="5"/>
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="montoTotalMoneda">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="17"/>
|
||||
<xs:fractionDigits value="2"/>
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="informacionAdicional"
|
||||
nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="10000"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="descuentoAdicional" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="17"/>
|
||||
<xs:fractionDigits value="2"/>
|
||||
<xs:minInclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoExcepcion" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="0"/>
|
||||
<xs:maxInclusive value="1"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cafc" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="50"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="leyenda">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="200"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="usuario">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="100"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoDocumentoSector"
|
||||
type="xs:integer" fixed="28"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="detalle" minOccurs="1" maxOccurs="500">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="actividadEconomica">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="10"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoProductoSin">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="99999999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoProducto">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="50"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="descripcion">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="500"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cantidad" type="xs:integer" fixed="1"/>
|
||||
<xs:element name="unidadMedida">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="200"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="precioUnitario">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="20"/>
|
||||
<xs:fractionDigits value="5"/>
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="montoDescuento" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="20"/>
|
||||
<xs:fractionDigits value="5"/>
|
||||
<xs:minInclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="subTotal">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="20"/>
|
||||
<xs:fractionDigits value="5"/>
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
343
src/main/resources/schemas/facturaElectronicaComercialExportacionServicio.xsd
Executable file
343
src/main/resources/schemas/facturaElectronicaComercialExportacionServicio.xsd
Executable file
@ -0,0 +1,343 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- XSD ver.23/08/2021 -->
|
||||
<xs:schema xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
attributeFormDefault="unqualified" elementFormDefault="qualified"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#"
|
||||
schemaLocation="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"/>
|
||||
<xs:element name="facturaElectronicaComercialExportacionServicio">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="cabecera">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="nitEmisor">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="9999999999999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="razonSocialEmisor">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="200"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="municipio">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="25"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="telefono" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="25"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="numeroFactura">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="9999999999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cuf">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="100"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cufd">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="100"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoSucursal">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="0"/>
|
||||
<xs:maxInclusive value="9999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="direccion">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="500"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoPuntoVenta" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="0"/>
|
||||
<xs:maxInclusive value="9999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="fechaEmision" type="xs:dateTime"/>
|
||||
<xs:element name="nombreRazonSocial" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="500"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoTipoDocumentoIdentidad">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="5"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="numeroDocumento">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="20"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="complemento" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="5"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="direccionComprador">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="500"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoCliente">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="100"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="lugarDestino">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="500"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoPais">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="212"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoMetodoPago">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="308"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="numeroTarjeta" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="0"/>
|
||||
<xs:maxInclusive value="9999999999999999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="montoTotal">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="17"/>
|
||||
<xs:fractionDigits value="2"/>
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="montoTotalSujetoIva" type="xs:decimal" fixed="0"/>
|
||||
<xs:element name="codigoMoneda">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="154"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="tipoCambio">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="17"/>
|
||||
<xs:fractionDigits value="5"/>
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="montoTotalMoneda">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="17"/>
|
||||
<xs:fractionDigits value="2"/>
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="informacionAdicional"
|
||||
nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="10000"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="descuentoAdicional" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="17"/>
|
||||
<xs:fractionDigits value="2"/>
|
||||
<xs:minInclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoExcepcion" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="0"/>
|
||||
<xs:maxInclusive value="1"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cafc" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="50"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="leyenda">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="200"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="usuario">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="100"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoDocumentoSector"
|
||||
type="xs:integer" fixed="28"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="detalle" minOccurs="1" maxOccurs="500">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="actividadEconomica">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="10"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoProductoSin">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="99999999"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="codigoProducto">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="50"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="descripcion">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="500"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cantidad" type="xs:integer" fixed="1"/>
|
||||
<xs:element name="unidadMedida">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="200"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="precioUnitario">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="20"/>
|
||||
<xs:fractionDigits value="5"/>
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="montoDescuento" nillable="true">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="20"/>
|
||||
<xs:fractionDigits value="5"/>
|
||||
<xs:minInclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="subTotal">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:totalDigits value="20"/>
|
||||
<xs:fractionDigits value="5"/>
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element ref="ds:Signature"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user