Compare commits
10 Commits
393db71413
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 57a5fa6d18 | |||
| 0e30684c2f | |||
| 3be8de28c6 | |||
| e9de3fde2c | |||
| 9f92c6e3ae | |||
| 627df17b2b | |||
| c8b5f78757 | |||
| 5889b327bd | |||
| cb0e69169e | |||
| df4c782fbb |
25
changelog.md
25
changelog.md
@@ -1,5 +1,30 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-12-11 - 2.0.2 - fix(page)
|
||||
Use theme variables for page styling, make pagecontainer background theme-aware, and use accent background for footer separator
|
||||
|
||||
- Extract documentSettings.theme to a local variable in dedocument-page and use safe optional checks when emitting CSS custom properties
|
||||
- Use theme pageBackground / coverPageBackground values consistently for page background-image fallback logic
|
||||
- Make pagecontainer background follow the --text-bg-color CSS variable instead of a hard #ffffff color
|
||||
- Switch footer separator color variable to --color-accent-bg so the footer stripe uses the theme accent background
|
||||
|
||||
## 2025-12-10 - 2.0.1 - fix(core)
|
||||
Migrate file I/O to @push.rocks/smartfs, adopt TC39 decorators v3 accessor in web components, and update docs/tests
|
||||
|
||||
- Added dependency @push.rocks/smartfs and replaced usages of @push.rocks/smartfile.fs with the SmartFs class-based API
|
||||
- Updated test helpers and test code to use SmartFs (SmartFsProviderNode) and new file read/write methods
|
||||
- Replaced legacy property declarations with TC39 decorators v3 accessor keyword across web components (ts_web/elements/*)
|
||||
- Replaced synchronous smartfile directory operations with async SmartFs directory.exists/create flow for .nogit
|
||||
- Updated README and added readme.hints.md with SmartFs usage examples, decorator guidance, and other developer hints
|
||||
|
||||
## 2025-12-10 - 2.0.0 - BREAKING CHANGE(build)
|
||||
Upgrade dependencies and dev tooling; adjust TypeScript config
|
||||
|
||||
- Bumped runtime dependencies: @design.estate/*, @push.rocks/*, @git.zone/tsrun (to ^2.0.0), @tsclass/tsclass, puppeteer, @types/node, qrcode types, and others.
|
||||
- Updated devDependencies: @git.zone/tsbuild, tsbundle, tstest, tswatch to newer releases.
|
||||
- Removed experimentalDecorators and useDefineForClassFields from tsconfig.json — this may change decorator handling and affect compilation.
|
||||
- These dependency and config changes may introduce breaking behavior; recommend a major version bump.
|
||||
|
||||
## 2025-01-01 - 1.6.11 - fix(license)
|
||||
Update copyright notice in license to reflect new ownership
|
||||
|
||||
|
||||
42
package.json
42
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@design.estate/dees-document",
|
||||
"version": "1.6.11",
|
||||
"version": "2.0.2",
|
||||
"private": false,
|
||||
"description": "A sophisticated framework for dynamically generating and rendering business documents like invoices with modern web technologies, featuring PDF creation, templating, and automation.",
|
||||
"main": "dist_ts_web/index.js",
|
||||
@@ -21,29 +21,29 @@
|
||||
"author": "Lossless GmbH",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@design.estate/dees-catalog": "^1.4.1",
|
||||
"@design.estate/dees-domtools": "^2.0.65",
|
||||
"@design.estate/dees-element": "^2.0.39",
|
||||
"@design.estate/dees-wcctools": "^1.0.90",
|
||||
"@git.zone/tsrun": "^1.3.3",
|
||||
"@push.rocks/smartfile": "^11.0.21",
|
||||
"@push.rocks/smartjson": "^5.0.20",
|
||||
"@push.rocks/smartpath": "^5.0.18",
|
||||
"@push.rocks/smartpdf": "^3.1.8",
|
||||
"@push.rocks/smarttime": "^4.0.8",
|
||||
"@tsclass/tsclass": "^4.4.3",
|
||||
"@types/node": "^22.10.1",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"puppeteer": "^24.3.0",
|
||||
"@design.estate/dees-catalog": "^3.3.0",
|
||||
"@design.estate/dees-domtools": "^2.3.6",
|
||||
"@design.estate/dees-element": "^2.1.3",
|
||||
"@design.estate/dees-wcctools": "^1.2.1",
|
||||
"@git.zone/tsrun": "^2.0.0",
|
||||
"@push.rocks/smartfile": "^13.1.0",
|
||||
"@push.rocks/smartfs": "^1.2.0",
|
||||
"@push.rocks/smartjson": "^6.0.0",
|
||||
"@push.rocks/smartpath": "^6.0.0",
|
||||
"@push.rocks/smartpdf": "^4.1.1",
|
||||
"@push.rocks/smarttime": "^4.1.1",
|
||||
"@tsclass/tsclass": "^9.3.0",
|
||||
"@types/node": "^25.0.0",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"puppeteer": "^24.32.1",
|
||||
"qrcode": "^1.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^2.2.0",
|
||||
"@git.zone/tsbundle": "^2.1.0",
|
||||
"@git.zone/tstest": "^1.0.90",
|
||||
"@git.zone/tswatch": "^2.0.34",
|
||||
"@push.rocks/projectinfo": "^5.0.2",
|
||||
"@push.rocks/tapbundle": "^5.5.3"
|
||||
"@git.zone/tsbuild": "^3.1.2",
|
||||
"@git.zone/tsbundle": "^2.6.3",
|
||||
"@git.zone/tstest": "^3.1.3",
|
||||
"@git.zone/tswatch": "^2.3.7",
|
||||
"@push.rocks/projectinfo": "^5.0.2"
|
||||
},
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
|
||||
10331
pnpm-lock.yaml
generated
10331
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1 +1,40 @@
|
||||
|
||||
# Development Hints
|
||||
|
||||
## Dependencies (v2.0.0)
|
||||
|
||||
- Uses `@push.rocks/smartfs` (v1.2.0) for filesystem operations - SmartFs is class-based with fluent API
|
||||
- Uses `@push.rocks/smartfile` (v13.1.0) - note: v13 removed the `.fs` namespace, use smartfs instead
|
||||
- Uses `@git.zone/tstest/tapbundle` for tests (NOT @push.rocks/tapbundle)
|
||||
- Test files must end with `export default tap.start()`
|
||||
|
||||
## TC39 Decorators v3
|
||||
|
||||
All decorated properties in web components use the `accessor` keyword:
|
||||
```typescript
|
||||
@property({ type: Object })
|
||||
accessor letterData: TInvoice;
|
||||
```
|
||||
|
||||
## SmartFs Usage
|
||||
|
||||
```typescript
|
||||
import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs';
|
||||
const smartfs = new SmartFs(new SmartFsProviderNode());
|
||||
|
||||
// Reading files
|
||||
await smartfs.file('/path/to/file').encoding('utf8').read();
|
||||
|
||||
// Writing files
|
||||
await smartfs.file('/path/to/file').write(buffer);
|
||||
|
||||
// Directory operations
|
||||
await smartfs.directory('/path').exists();
|
||||
await smartfs.directory('/path').create();
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
- `ts/` - Node.js server-side code (PdfService)
|
||||
- `ts_web/` - Browser web components (Lit-based)
|
||||
- `ts_shared/` - Shared code (translations, interfaces)
|
||||
- `test/` - Test files
|
||||
|
||||
337
readme.md
337
readme.md
@@ -1,199 +1,276 @@
|
||||
# @design.estate/dees-document
|
||||
|
||||
A comprehensive tool for dynamically generating and rendering business documents like invoices using modern web technologies.
|
||||
A powerful TypeScript framework for dynamically generating professional business documents like invoices with web components and PDF export capabilities. 🧾
|
||||
|
||||
## Install
|
||||
## Issue Reporting and Security
|
||||
|
||||
To incorporate `@design.estate/dees-document` into your project, execute the following command in your terminal:
|
||||
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
npm install @design.estate/dees-document --save
|
||||
pnpm install @design.estate/dees-document
|
||||
```
|
||||
|
||||
This command will install the package and add it to your project's dependencies, thus making all the necessary modules available within your `node_modules` directory.
|
||||
## Features
|
||||
|
||||
- 📄 **PDF Generation** - Server-side PDF creation from structured data using Puppeteer
|
||||
- 🎨 **Web Components** - Lit-based custom elements for document rendering
|
||||
- 🌍 **Multi-language Support** - Built-in translation system (EN, DE, ES)
|
||||
- 📱 **Automatic Pagination** - Smart content overflow handling across pages
|
||||
- 💳 **QR Payment Codes** - EPC QR codes for SEPA payments
|
||||
- 🖨️ **Print Mode** - Optimized rendering for both screen and print
|
||||
- 📐 **A4 Format** - Precise DIN A4 document dimensions
|
||||
- ✨ **Theming** - Customizable colors, backgrounds, and branding
|
||||
|
||||
## Usage
|
||||
|
||||
The `@design.estate/dees-document` package serves as a robust framework to facilitate the generation of business documents, such as invoices, contracts, and reports. Leveraging modern web technologies, this package integrates seamlessly with TypeScript and ES modules, offering a type-safe environment conducive to efficient, dynamic document creation.
|
||||
|
||||
Below, we provide a detailed guide for utilizing this package, from initializing your environment to generating complete PDF documents.
|
||||
|
||||
### Setting Up the Environment
|
||||
|
||||
Before diving into document creation, ensure your environment is properly configured. Make sure to import necessary dependencies and setup configurations:
|
||||
### Server-Side PDF Generation
|
||||
|
||||
```typescript
|
||||
import { PdfService, IPdfServiceConstructorOptions } from '@design.estate/dees-document';
|
||||
import { PdfService } from '@design.estate/dees-document';
|
||||
import type { TInvoice } from '@tsclass/tsclass/finance';
|
||||
|
||||
async function setupPdfService() {
|
||||
const options: IPdfServiceConstructorOptions = {
|
||||
// Configure your options here
|
||||
};
|
||||
// Initialize the PDF service
|
||||
const pdfService = new PdfService({});
|
||||
await pdfService.start();
|
||||
|
||||
const pdfService = await PdfService.createAndStart(options);
|
||||
console.log('PDF Service started successfully.');
|
||||
return pdfService;
|
||||
}
|
||||
```
|
||||
|
||||
In this setup snippet, you set up the `PdfService` which is the core component for PDF generation. The configuration options should be adjusted to fit your needs, especially considering options such as file paths, languages, and template directories.
|
||||
|
||||
### Creating a Document Template
|
||||
|
||||
To create documents, particularly invoices, you'll first need to define a template. This template describes the structure of your document:
|
||||
|
||||
```typescript
|
||||
import { ILetter } from '@design.estate/dees-document';
|
||||
|
||||
const invoiceTemplate: ILetter = {
|
||||
// Create invoice data
|
||||
const invoice: TInvoice = {
|
||||
type: 'invoice',
|
||||
invoiceType: 'debitnote',
|
||||
id: 'INV-2024-001',
|
||||
invoiceId: 'INV-2024-001',
|
||||
date: Date.now(),
|
||||
currency: 'EUR',
|
||||
dueInDays: 30,
|
||||
reverseCharge: false,
|
||||
from: {
|
||||
name: 'Your Company Name',
|
||||
name: 'Your Company GmbH',
|
||||
type: 'company',
|
||||
status: 'active',
|
||||
address: {
|
||||
streetName: 'Your Street',
|
||||
streetName: 'Business Street',
|
||||
houseNumber: '123',
|
||||
city: 'Your City',
|
||||
country: 'Your Country',
|
||||
postalCode: '12345',
|
||||
city: 'Berlin',
|
||||
country: 'Germany',
|
||||
postalCode: '10115',
|
||||
},
|
||||
sepaConnection: {
|
||||
bic: 'DEUTDEFF',
|
||||
iban: 'DE89370400440532013000',
|
||||
},
|
||||
registrationDetails: {
|
||||
vatId: 'DE123456789',
|
||||
registrationName: 'Amtsgericht Berlin',
|
||||
registrationId: 'HRB 12345',
|
||||
},
|
||||
email: 'your-email@example.com',
|
||||
phone: '123-456-7890',
|
||||
},
|
||||
to: {
|
||||
name: 'Recipient Company Name',
|
||||
name: 'Customer Inc.',
|
||||
type: 'company',
|
||||
status: 'active',
|
||||
address: {
|
||||
streetName: 'Recipient Street',
|
||||
streetName: 'Client Avenue',
|
||||
houseNumber: '456',
|
||||
city: 'Recipient City',
|
||||
country: 'Recipient Country',
|
||||
postalCode: '67890',
|
||||
city: 'Munich',
|
||||
country: 'Germany',
|
||||
postalCode: '80331',
|
||||
},
|
||||
email: 'recipient-email@example.com',
|
||||
phone: '098-765-4321',
|
||||
},
|
||||
content: {
|
||||
invoiceData: {
|
||||
items: [
|
||||
{
|
||||
name: 'Service or Product Name',
|
||||
unitQuantity: 2,
|
||||
unitNetPrice: 100.0,
|
||||
unitType: 'service',
|
||||
vatPercentage: 19,
|
||||
currency: 'EUR',
|
||||
},
|
||||
],
|
||||
registrationDetails: {
|
||||
vatId: 'DE987654321',
|
||||
},
|
||||
},
|
||||
subject: 'Invoice for Services Rendered',
|
||||
date: new Date().getTime(),
|
||||
items: [
|
||||
{
|
||||
name: 'Web Development Services',
|
||||
unitQuantity: 40,
|
||||
unitNetPrice: 95,
|
||||
unitType: 'hours',
|
||||
vatPercentage: 19,
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
name: 'Hosting (Annual)',
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 299,
|
||||
unitType: 'item',
|
||||
vatPercentage: 19,
|
||||
position: 2,
|
||||
},
|
||||
],
|
||||
subject: 'Invoice INV-2024-001',
|
||||
versionInfo: {
|
||||
type: 'final',
|
||||
version: '1.0.0',
|
||||
},
|
||||
};
|
||||
|
||||
// Generate PDF
|
||||
const pdfResult = await pdfService.createPdfFromLetterObject({
|
||||
letterData: invoice,
|
||||
documentSettings: {
|
||||
languageCode: 'EN',
|
||||
enableDefaultHeader: true,
|
||||
enableDefaultFooter: true,
|
||||
enableFoldMarks: true,
|
||||
dateStyle: 'long',
|
||||
},
|
||||
});
|
||||
|
||||
// Save to file
|
||||
import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs';
|
||||
const fs = new SmartFs(new SmartFsProviderNode());
|
||||
await fs.file('./invoice.pdf').write(Buffer.from(pdfResult.buffer));
|
||||
|
||||
// Don't forget to stop the service when done
|
||||
await pdfService.stop();
|
||||
```
|
||||
|
||||
The `invoiceTemplate` object utilizes the `ILetter` interface which specifies the structure for invoice data, including sender and recipient details, itemization, and pricing.
|
||||
### Document Settings
|
||||
|
||||
### Generating the Document
|
||||
|
||||
Once a template is established, the next step is generating a PDF:
|
||||
Customize document appearance with `IDocumentSettings`:
|
||||
|
||||
```typescript
|
||||
async function generateInvoice(pdfService: PdfService, invoiceData: ILetter) {
|
||||
const pdfBuffer = await pdfService.createPdfFromLetterObject(invoiceData);
|
||||
console.log('Invoice PDF generated successfully.');
|
||||
const documentSettings = {
|
||||
// Language for translations
|
||||
languageCode: 'DE', // 'EN' | 'DE' | 'ES'
|
||||
|
||||
// Here you could save the PDF to your filesystem, send it via email, etc.
|
||||
}
|
||||
// Layout options
|
||||
enableDefaultHeader: true,
|
||||
enableDefaultFooter: true,
|
||||
enableFoldMarks: true,
|
||||
enableTopDraftText: true,
|
||||
enableInvoiceContractRefSection: true,
|
||||
|
||||
// Display options
|
||||
vatGroupPositions: true,
|
||||
dateStyle: 'long', // 'short' | 'medium' | 'long' | 'full'
|
||||
|
||||
// Theming
|
||||
theme: {
|
||||
colorPrimaryForeground: '#ffffff',
|
||||
colorPrimaryBackground: '#e4002b',
|
||||
colorAccentForeground: '#333333',
|
||||
colorAccentBackground: '#f5f5f5',
|
||||
pageBackground: 'url(your-watermark.png)',
|
||||
coverPageBackground: 'url(your-cover.png)',
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
In this function, the `createPdfFromLetterObject` method converts your invoice data into a `Buffer` containing the PDF. This `Buffer` can subsequently be saved as a file or sent over HTTP.
|
||||
### Web Component Usage
|
||||
|
||||
### Comprehensive Example
|
||||
|
||||
Below is an example integrating all previous steps into a single coherent script:
|
||||
For browser-based document viewing:
|
||||
|
||||
```typescript
|
||||
async function main() {
|
||||
const pdfService = await setupPdfService();
|
||||
const invoiceData: ILetter = {
|
||||
// Populate your invoice object
|
||||
};
|
||||
await generateInvoice(pdfService, invoiceData);
|
||||
}
|
||||
import '@design.estate/dees-document/web';
|
||||
|
||||
main().then(() => console.log('Invoice generation process completed.'));
|
||||
// In your HTML/Lit template
|
||||
html`
|
||||
<dedocument-viewer
|
||||
.letterData=${invoiceData}
|
||||
.documentSettings=${documentSettings}
|
||||
></dedocument-viewer>
|
||||
`;
|
||||
|
||||
// Or render the document directly
|
||||
html`
|
||||
<dedocument-dedocument
|
||||
.letterData=${invoiceData}
|
||||
.documentSettings=${documentSettings}
|
||||
></dedocument-dedocument>
|
||||
`;
|
||||
```
|
||||
|
||||
This script encompasses initializing services and generating a PDF in a streamlined, efficient workflow.
|
||||
### Translation System
|
||||
|
||||
### Advanced Features
|
||||
|
||||
`@design.estate/dees-document` provides several advanced functionalities, enabling rich document creation:
|
||||
|
||||
1. **Custom Templates & Styling**
|
||||
|
||||
- Customize the styling through CSS or using inline styles in TypeScript.
|
||||
- Templates can be adjusted to present different document types (e.g., contracts, reports).
|
||||
|
||||
2. **Modular Components and Reuse**
|
||||
|
||||
- Utilize modular components to create reusable parts across different documents, enhancing maintainability and reducing redundancy.
|
||||
|
||||
3. **Interactive Documents**
|
||||
|
||||
- Integrate interactivities like forms, buttons, and interactive charts within your documents.
|
||||
|
||||
4. **Localization Support**
|
||||
|
||||
- Documents can be localized to support multiple languages, enhancing accessibility and usability.
|
||||
|
||||
5. **Responsive and Adaptive Designs**
|
||||
|
||||
- Create documents that adjust layout dynamically depending on print or digital medium, maintaining consistency across platforms.
|
||||
|
||||
6. **Security Features**
|
||||
|
||||
- Apply digital signatures and encrypt sensitive documents to ensure secure and authentic document distribution.
|
||||
|
||||
7. **Complex Business Logic**
|
||||
- Implement complex logic for feature-rich documents such as inventory systems, automatic tax calculations, or real-time pricing adjustments.
|
||||
|
||||
### Utilize Translation for Localization
|
||||
|
||||
The package offers a translation mechanism to adapt your documents for international clients:
|
||||
The package includes a translation system for multi-language document generation:
|
||||
|
||||
```typescript
|
||||
import { translate } from '@design.estate/dees-document/shared';
|
||||
|
||||
const languageCode: 'DE' | 'EN' | 'ES' = 'EN'; // Set required language code
|
||||
console.log(translate(languageCode, 'invoice', 'Invoice')); // Translated output
|
||||
// Translate document labels
|
||||
translate('DE', 'invoice@@totalGross'); // "Gesamtbetrag (Brutto)"
|
||||
translate('EN', 'invoice@@totalGross'); // "Total (Gross)"
|
||||
translate('ES', 'invoice@@totalGross'); // "Total (Bruto)"
|
||||
```
|
||||
|
||||
Different language settings can be applied, enabling the seamless presentation of document contents tailored to regional and linguistic preferences.
|
||||
## Module Exports
|
||||
|
||||
### Conclusion
|
||||
The package provides multiple entry points:
|
||||
|
||||
The `@design.estate/dees-document` package is a versatile and powerful solution for businesses seeking to automate and streamline their document generation processes using modern web technologies. By integrating seamlessly with TypeScript, it offers robust capabilities for creating complex, customizable, and interactive documents that can meet a variety of business needs.
|
||||
```typescript
|
||||
// Node.js server-side (PDF generation)
|
||||
import { PdfService } from '@design.estate/dees-document';
|
||||
import { PdfService } from '@design.estate/dees-document/node';
|
||||
|
||||
From custom templates to localization and advanced security features, this module provides the flexibility and power to create polished and professional documents efficiently. Whether you're generating invoices, contracts, or detailed reports, `@design.estate/dees-document` has the tools to support your enterprise workflows with ease and precision.
|
||||
// Browser web components
|
||||
import '@design.estate/dees-document/web';
|
||||
|
||||
// Shared utilities and types
|
||||
import { translate, IDocumentSettings } from '@design.estate/dees-document/shared';
|
||||
|
||||
// TypeScript interfaces
|
||||
import type { IDocumentSettings } from '@design.estate/dees-document/interfaces';
|
||||
```
|
||||
|
||||
## Document Components
|
||||
|
||||
The framework includes these web components:
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| `<dedocument-dedocument>` | Main document container with pagination |
|
||||
| `<dedocument-viewer>` | Document viewer with controls |
|
||||
| `<dedocument-page>` | Single A4 page with scaling support |
|
||||
| `<dedocument-pageheader>` | Company logo and branding header |
|
||||
| `<dedocument-letterheader>` | Sender/recipient addresses |
|
||||
| `<dedocument-pagecontent>` | Main content area |
|
||||
| `<dedocument-pagefooter>` | Company info and page numbers |
|
||||
| `<dedocument-contentinvoice>` | Invoice-specific content layout |
|
||||
| `<dedocument-paymentcode>` | EPC QR code for SEPA payments |
|
||||
|
||||
## Draft vs Final Documents
|
||||
|
||||
Control document version display:
|
||||
|
||||
```typescript
|
||||
const invoice = {
|
||||
// ... other fields
|
||||
versionInfo: {
|
||||
type: 'draft', // Shows watermark "DRAFT" across pages
|
||||
version: '0.1.0',
|
||||
},
|
||||
};
|
||||
|
||||
// For final documents
|
||||
const invoice = {
|
||||
// ... other fields
|
||||
versionInfo: {
|
||||
type: 'final', // Clean document without watermark
|
||||
version: '1.0.0',
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
|
||||
|
||||
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
Task Venture Capital GmbH
|
||||
Registered at District Court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
For any legal inquiries or further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import * as tsclass from '@tsclass/tsclass';
|
||||
import * as smartfile from '@push.rocks/smartfile';
|
||||
import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs';
|
||||
import * as path from 'path';
|
||||
|
||||
export { tsclass, smartfile, path };
|
||||
export const smartfs = new SmartFs(new SmartFsProviderNode());
|
||||
|
||||
export { tsclass, path };
|
||||
|
||||
210
test/test.ts
210
test/test.ts
@@ -1,120 +1,106 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import * as paths from './paths.js';
|
||||
import * as interfaces from '../ts_shared/interfaces/index.js';
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import * as deesDocumentServer from '../ts/index.js';
|
||||
import * as plugins from "./plugins.js";
|
||||
import * as paths from "./paths.js";
|
||||
import * as interfaces from "../ts_shared/interfaces/index.js";
|
||||
import { expect, tap } from "@git.zone/tstest/tapbundle";
|
||||
import * as deesDocumentServer from "../ts/index.js";
|
||||
|
||||
let testPdfServiceInstance: deesDocumentServer.PdfService;
|
||||
const testLetterData: plugins.tsclass.business.ILetter = {
|
||||
accentColor: null,
|
||||
type: 'invoice',
|
||||
const testLetterData: plugins.tsclass.finance.TInvoice = {
|
||||
type: "invoice",
|
||||
invoiceType: "debitnote",
|
||||
date: null,
|
||||
needsCoverSheet: true,
|
||||
objectActions: [],
|
||||
pdf: null,
|
||||
content: {
|
||||
invoiceData: {
|
||||
id: 'XX-CLIENT-48765',
|
||||
reverseCharge: true,
|
||||
dueInDays: 30,
|
||||
currency: 'EUR',
|
||||
notes: [],
|
||||
type: 'debitnote',
|
||||
billedBy: {
|
||||
address: null,
|
||||
description: null,
|
||||
name: 'Some Service GmbH',
|
||||
type: null,
|
||||
customerNumber: null,
|
||||
email: null,
|
||||
facebookUrl: null,
|
||||
fax: null,
|
||||
legalEntity: null,
|
||||
sepaConnection: {
|
||||
bic: 'BPOTBEB1',
|
||||
iban: 'BE72000000001616',
|
||||
},
|
||||
},
|
||||
billedTo: null,
|
||||
status: null,
|
||||
deliveryDate: new Date().getTime(),
|
||||
periodOfPerformance: null,
|
||||
printResult: null,
|
||||
items: [
|
||||
{
|
||||
name: 'Website Creation',
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
vatPercentage: 0,
|
||||
position: 1,
|
||||
},
|
||||
],
|
||||
id: "XX-CLIENT-48765",
|
||||
invoiceId: "XX-CLIENT-48765",
|
||||
reverseCharge: true,
|
||||
dueInDays: 30,
|
||||
currency: "EUR",
|
||||
notes: [],
|
||||
status: null,
|
||||
deliveryDate: new Date().getTime(),
|
||||
periodOfPerformance: null,
|
||||
printResult: null,
|
||||
items: [
|
||||
{
|
||||
name: "Website Creation",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: "item",
|
||||
vatPercentage: 0,
|
||||
position: 1,
|
||||
},
|
||||
contractData: {
|
||||
contractDate: Date.now(),
|
||||
id: 'LL-CONTRACT-48765',
|
||||
},
|
||||
textData: [],
|
||||
timesheetData: '',
|
||||
},
|
||||
],
|
||||
from: {
|
||||
name: 'PdfService Test Company',
|
||||
type: 'company',
|
||||
description: 'doing pdf stuff',
|
||||
name: "PdfService Test Company",
|
||||
type: "company",
|
||||
status: "active",
|
||||
foundedDate: { day: 1, month: 1, year: 2025 },
|
||||
description: "doing pdf stuff",
|
||||
address: {
|
||||
streetName: 'Awesome Street',
|
||||
houseNumber: '5',
|
||||
city: 'Bremen',
|
||||
country: 'Germany',
|
||||
postalCode: '28359',
|
||||
streetName: "Awesome Street",
|
||||
houseNumber: "5",
|
||||
city: "Bremen",
|
||||
country: "Germany",
|
||||
postalCode: "28359",
|
||||
},
|
||||
sepaConnection: {
|
||||
bic: 'BPOTBEB1',
|
||||
iban: 'BE72000000001616',
|
||||
bic: "BPOTBEB1",
|
||||
iban: "BE72000000001616",
|
||||
},
|
||||
registrationDetails: {
|
||||
vatId: "",
|
||||
registrationName: "",
|
||||
registrationId: "",
|
||||
},
|
||||
},
|
||||
to: {
|
||||
name: 'Awesome To Company',
|
||||
type: 'company',
|
||||
description: 'a company that does stuff',
|
||||
name: "Awesome To Company",
|
||||
type: "company",
|
||||
status: "active",
|
||||
foundedDate: { day: 1, month: 1, year: 2025 },
|
||||
description: "a company that does stuff",
|
||||
address: {
|
||||
streetName: 'Awesome Street',
|
||||
houseNumber: '5',
|
||||
city: 'Bremen',
|
||||
country: 'Germany',
|
||||
postalCode: '28359',
|
||||
streetName: "Awesome Street",
|
||||
houseNumber: "5",
|
||||
city: "Bremen",
|
||||
country: "Germany",
|
||||
postalCode: "28359",
|
||||
},
|
||||
registrationDetails: {
|
||||
vatId: "",
|
||||
registrationName: "",
|
||||
registrationId: "",
|
||||
},
|
||||
},
|
||||
incidenceId: null,
|
||||
language: null,
|
||||
legalContact: null,
|
||||
logoUrl: null,
|
||||
pdfAttachments: null,
|
||||
subject: 'Invoice XX-CLIENT-48765',
|
||||
subject: "Invoice XX-CLIENT-48765",
|
||||
versionInfo: {
|
||||
type: 'final',
|
||||
version: '1.0.0',
|
||||
type: "final",
|
||||
version: "1.0.0",
|
||||
},
|
||||
};
|
||||
|
||||
tap.test('should create a document from an invoice', async () => {
|
||||
tap.test("should create a document from an invoice", async () => {
|
||||
testPdfServiceInstance = new deesDocumentServer.PdfService({});
|
||||
await testPdfServiceInstance.start();
|
||||
expect(testPdfServiceInstance).toBeInstanceOf(deesDocumentServer.PdfService);
|
||||
});
|
||||
|
||||
tap.test('should create an invoice', async () => {
|
||||
tap.test("should create an invoice", async () => {
|
||||
let counter = 0;
|
||||
const saveResult = async (optionsArg: {
|
||||
letterData: plugins.tsclass.business.ILetter;
|
||||
letterData: plugins.tsclass.finance.TInvoice;
|
||||
documentSettings: interfaces.IDocumentSettings;
|
||||
}) => {
|
||||
const pdfResult = await testPdfServiceInstance.createPdfFromLetterObject(optionsArg);
|
||||
await plugins.smartfile.memory.toFs(
|
||||
Buffer.from(pdfResult.buffer),
|
||||
plugins.path.join(paths.nogitDir, `test-${counter++}.pdf`),
|
||||
const pdfResult = await testPdfServiceInstance.createPdfFromLetterObject(
|
||||
optionsArg
|
||||
);
|
||||
await plugins.smartfs.file(plugins.path.join(paths.nogitDir, `test-${counter++}.pdf`))
|
||||
.write(Buffer.from(pdfResult.buffer));
|
||||
};
|
||||
await saveResult({
|
||||
letterData: testLetterData,
|
||||
@@ -124,106 +110,106 @@ tap.test('should create an invoice', async () => {
|
||||
letterData: {
|
||||
...testLetterData,
|
||||
versionInfo: {
|
||||
type: 'draft',
|
||||
version: '1.0.0',
|
||||
type: "draft",
|
||||
version: "1.0.0",
|
||||
},
|
||||
},
|
||||
documentSettings: {},
|
||||
});
|
||||
(testLetterData.content.invoiceData.items = [
|
||||
(testLetterData.items = [
|
||||
{
|
||||
name: 'Website Creation',
|
||||
name: "Website Creation",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 0,
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
name: 'Hosting',
|
||||
name: "Hosting",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 19,
|
||||
position: 2,
|
||||
},
|
||||
{
|
||||
name: 'Overnight Shipping',
|
||||
name: "Overnight Shipping",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 24,
|
||||
position: 3,
|
||||
},
|
||||
{
|
||||
name: 'Website Creation',
|
||||
name: "Website Creation",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 0,
|
||||
position: 4,
|
||||
},
|
||||
{
|
||||
name: 'Hosting',
|
||||
name: "Hosting",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 19,
|
||||
position: 5,
|
||||
},
|
||||
{
|
||||
name: 'Overnight Shipping',
|
||||
name: "Overnight Shipping",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 24,
|
||||
position: 6,
|
||||
},
|
||||
{
|
||||
name: 'Website Creation',
|
||||
name: "Website Creation",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 0,
|
||||
position: 7,
|
||||
},
|
||||
{
|
||||
name: 'Hosting',
|
||||
name: "Hosting",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 19,
|
||||
position: 8,
|
||||
},
|
||||
{
|
||||
name: 'Overnight Shipping',
|
||||
name: "Overnight Shipping",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 24,
|
||||
position: 9,
|
||||
},
|
||||
{
|
||||
name: 'Website Creation',
|
||||
name: "Website Creation",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 0,
|
||||
position: 10,
|
||||
},
|
||||
{
|
||||
name: 'Hosting',
|
||||
name: "Hosting",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 19,
|
||||
position: 11,
|
||||
},
|
||||
{
|
||||
name: 'Overnight Shipping',
|
||||
name: "Overnight Shipping",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 1200,
|
||||
unitType: 'item',
|
||||
unitType: "item",
|
||||
vatPercentage: 24,
|
||||
position: 12,
|
||||
},
|
||||
@@ -234,8 +220,8 @@ tap.test('should create an invoice', async () => {
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('should stop the service', async () => {
|
||||
tap.test("should stop the service", async () => {
|
||||
await testPdfServiceInstance.stop();
|
||||
});
|
||||
|
||||
tap.start();
|
||||
export default tap.start();
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@design.estate/dees-document',
|
||||
version: '1.6.11',
|
||||
version: '2.0.2',
|
||||
description: 'A sophisticated framework for dynamically generating and rendering business documents like invoices with modern web technologies, featuring PDF creation, templating, and automation.'
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import * as helpers from './helpers.js';
|
||||
import * as plugins from "./plugins.js";
|
||||
import * as helpers from "./helpers.js";
|
||||
|
||||
export interface IPdfServiceConstructorOptions {}
|
||||
|
||||
@@ -8,7 +8,9 @@ export interface IPdfServiceConstructorOptions {}
|
||||
*/
|
||||
export class PdfService {
|
||||
// STATIC
|
||||
public static async createAndStart(optionsArg: IPdfServiceConstructorOptions) {
|
||||
public static async createAndStart(
|
||||
optionsArg: IPdfServiceConstructorOptions
|
||||
) {
|
||||
const pdfService = new PdfService(optionsArg);
|
||||
await pdfService.start();
|
||||
return pdfService;
|
||||
@@ -42,17 +44,23 @@ export class PdfService {
|
||||
* creates an letter
|
||||
*/
|
||||
public async createPdfFromLetterObject(optionsArg: {
|
||||
letterData: plugins.tsclass.business.ILetter;
|
||||
letterData: plugins.tsclass.business.TLetter;
|
||||
documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
}) {
|
||||
}): Promise<plugins.smartpdf.IPdf> {
|
||||
const html = `
|
||||
<script type="module">
|
||||
${await helpers.getBundleAsString()}
|
||||
</script>
|
||||
<dedocument-dedocument printMode documentSettings="${plugins.smartjson.stringifyBase64(optionsArg.documentSettings)}" letterData="${plugins.smartjson.stringifyBase64(optionsArg.letterData)}"></dedocument-dedocument>
|
||||
<dedocument-dedocument printMode documentSettings="${plugins.smartjson.stringifyBase64(
|
||||
optionsArg.documentSettings
|
||||
)}" letterData="${plugins.smartjson.stringifyBase64(
|
||||
optionsArg.letterData
|
||||
)}"></dedocument-dedocument>
|
||||
`;
|
||||
// console.log(html);
|
||||
const pdfResult = await this.smartpdfInstance.getA4PdfResultForHtmlString(html);
|
||||
const pdfResult = await this.smartpdfInstance.getA4PdfResultForHtmlString(
|
||||
html
|
||||
);
|
||||
return pdfResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ import * as plugins from './plugins.js';
|
||||
import * as paths from './paths.js';
|
||||
|
||||
export const getBundleAsString = async () => {
|
||||
return plugins.smartfile.fs.toStringSync(paths.bundleFile);
|
||||
return plugins.smartfs.file(paths.bundleFile).encoding('utf8').read();
|
||||
};
|
||||
|
||||
@@ -6,7 +6,9 @@ export const packageDir = plugins.path.join(
|
||||
);
|
||||
|
||||
export const nogitDir = plugins.path.join(packageDir, '.nogit/');
|
||||
plugins.smartfile.fs.ensureDirSync(nogitDir);
|
||||
if (!(await plugins.smartfs.directory(nogitDir).exists())) {
|
||||
await plugins.smartfs.directory(nogitDir).create();
|
||||
}
|
||||
|
||||
export const bundleDir = plugins.path.join(packageDir, './dist_bundle');
|
||||
export const bundleFile = plugins.path.join(bundleDir, './bundle.js');
|
||||
|
||||
@@ -10,10 +10,13 @@ export { shared };
|
||||
|
||||
// @push.rocks/scope
|
||||
import * as smartfile from '@push.rocks/smartfile';
|
||||
import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs';
|
||||
import * as smartjson from '@push.rocks/smartjson';
|
||||
import * as smartpath from '@push.rocks/smartpath';
|
||||
import * as smartpdf from '@push.rocks/smartpdf';
|
||||
|
||||
export const smartfs = new SmartFs(new SmartFsProviderNode());
|
||||
|
||||
export { smartfile, smartpath, smartjson, smartpdf };
|
||||
|
||||
// @tsclass scope
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import * as plugins from "./plugins.js";
|
||||
import * as interfaces from "./interfaces/index.js";
|
||||
|
||||
const fromContact: plugins.tsclass.business.IContact = {
|
||||
const fromContact: plugins.tsclass.business.TContact = {
|
||||
name: "Awesome From Company",
|
||||
type: "company",
|
||||
status: "active",
|
||||
foundedDate: { day: 1, month: 1, year: 2025 },
|
||||
description: "a company that does stuff",
|
||||
address: {
|
||||
streetName: "Awesome Street",
|
||||
@@ -12,7 +14,6 @@ const fromContact: plugins.tsclass.business.IContact = {
|
||||
country: "Germany",
|
||||
postalCode: "28359",
|
||||
},
|
||||
vatId: "DE12345678",
|
||||
sepaConnection: {
|
||||
bic: "BPOTBEB1",
|
||||
iban: "BE01234567891616",
|
||||
@@ -20,11 +21,18 @@ const fromContact: plugins.tsclass.business.IContact = {
|
||||
email: "hello@awesome.company",
|
||||
phone: "+49 421 1234567",
|
||||
fax: "+49 421 1234568",
|
||||
registrationDetails: {
|
||||
registrationId: "HRB 35230 HB",
|
||||
registrationName: "Amtsgericht Bremen",
|
||||
vatId: "DE12345678",
|
||||
},
|
||||
};
|
||||
|
||||
const toContact: plugins.tsclass.business.IContact = {
|
||||
const toContact: plugins.tsclass.business.TContact = {
|
||||
name: "Awesome To GmbH",
|
||||
type: "company",
|
||||
status: "active",
|
||||
foundedDate: { day: 1, month: 1, year: 2025 },
|
||||
customerNumber: "LL-CLIENT-123",
|
||||
description: "a company that does stuff",
|
||||
address: {
|
||||
@@ -34,217 +42,202 @@ const toContact: plugins.tsclass.business.IContact = {
|
||||
country: "Germany",
|
||||
postalCode: "28359",
|
||||
},
|
||||
vatId: "BE12345678",
|
||||
registrationDetails: {
|
||||
registrationId: "HRB 35230 HB",
|
||||
registrationName: "Amtsgericht Bremen",
|
||||
vatId: "DE12345678",
|
||||
},
|
||||
};
|
||||
|
||||
export const demoLetter: plugins.tsclass.business.ILetter = {
|
||||
export const demoLetter: plugins.tsclass.finance.TInvoice = {
|
||||
type: "accounting-doc",
|
||||
accountingDocType: "invoice",
|
||||
accountingDocId: "LL-INV-48765",
|
||||
accountingDocStatus: "draft",
|
||||
id: "LL-INV-48765",
|
||||
versionInfo: {
|
||||
type: "draft",
|
||||
version: "1.0.0",
|
||||
type: "draft",
|
||||
},
|
||||
accentColor: null,
|
||||
content: {
|
||||
textData: null,
|
||||
timesheetData: null,
|
||||
contractData: {
|
||||
contractDate: Date.now(),
|
||||
id: "someid",
|
||||
},
|
||||
letterData: {} as plugins.tsclass.business.ILetter,
|
||||
invoiceData: {
|
||||
id: "LL-INV-48765",
|
||||
reverseCharge: true,
|
||||
dueInDays: 30,
|
||||
billedBy: fromContact,
|
||||
billedTo: toContact,
|
||||
status: null,
|
||||
deliveryDate: new Date().getTime(),
|
||||
periodOfPerformance: {
|
||||
from: +new Date().setDate(new Date().getDate() - 7),
|
||||
to: +new Date(),
|
||||
},
|
||||
printResult: null,
|
||||
currency: "EUR",
|
||||
notes: [],
|
||||
type: "debitnote",
|
||||
items: [
|
||||
{
|
||||
name: "Item with 19% VAT",
|
||||
unitQuantity: 2,
|
||||
unitNetPrice: 100,
|
||||
unitType: "hours",
|
||||
vatPercentage: 19,
|
||||
position: 0,
|
||||
},
|
||||
{
|
||||
name: "Item with 7% VAT",
|
||||
unitQuantity: 4,
|
||||
unitNetPrice: 100,
|
||||
unitType: "hours",
|
||||
vatPercentage: 7,
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
name: "Item with 7% VAT",
|
||||
unitQuantity: 3,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 7,
|
||||
position: 2,
|
||||
},
|
||||
{
|
||||
name: "Item with 21% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 21,
|
||||
position: 3,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 6,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 4,
|
||||
},
|
||||
{
|
||||
name: "Item with 19% VAT",
|
||||
unitQuantity: 8,
|
||||
unitNetPrice: 100,
|
||||
unitType: "hours",
|
||||
vatPercentage: 19,
|
||||
position: 5,
|
||||
},
|
||||
{
|
||||
name: "Item with 7% VAT",
|
||||
unitQuantity: 9,
|
||||
unitNetPrice: 100,
|
||||
unitType: "hours",
|
||||
vatPercentage: 7,
|
||||
position: 6,
|
||||
},
|
||||
{
|
||||
name: "Item with 7% VAT",
|
||||
unitQuantity: 4,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 7,
|
||||
position: 8,
|
||||
},
|
||||
{
|
||||
name: "Item with 21% VAT",
|
||||
unitQuantity: 3,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 21,
|
||||
position: 9,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 10,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 11,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 12,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 13,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 14,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 15,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 16,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 17,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 18,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 19,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 20,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
language: "de",
|
||||
date: Date.now(),
|
||||
type: "invoice",
|
||||
needsCoverSheet: false,
|
||||
objectActions: [],
|
||||
pdf: null,
|
||||
incidenceId: "LL-INV-48765",
|
||||
subject: "LL-INV-48765",
|
||||
reverseCharge: true,
|
||||
dueInDays: 30,
|
||||
from: fromContact,
|
||||
to: toContact,
|
||||
incidenceId: null,
|
||||
language: null,
|
||||
legalContact: null,
|
||||
logoUrl: null,
|
||||
pdfAttachments: null,
|
||||
subject: "Invoice: LL-INV-48765",
|
||||
status: null,
|
||||
deliveryDate: new Date().getTime(),
|
||||
periodOfPerformance: {
|
||||
from: +new Date().setDate(new Date().getDate() - 7),
|
||||
to: +new Date(),
|
||||
},
|
||||
printResult: null,
|
||||
currency: "EUR",
|
||||
notes: [],
|
||||
items: [
|
||||
{
|
||||
name: "Item with 19% VAT",
|
||||
unitQuantity: 2,
|
||||
unitNetPrice: 100,
|
||||
unitType: "hours",
|
||||
vatPercentage: 19,
|
||||
position: 0,
|
||||
},
|
||||
{
|
||||
name: "Item with 7% VAT",
|
||||
unitQuantity: 4,
|
||||
unitNetPrice: 100,
|
||||
unitType: "hours",
|
||||
vatPercentage: 7,
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
name: "Item with 7% VAT",
|
||||
unitQuantity: 3,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 7,
|
||||
position: 2,
|
||||
},
|
||||
{
|
||||
name: "Item with 21% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 21,
|
||||
position: 3,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 6,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 4,
|
||||
},
|
||||
{
|
||||
name: "Item with 19% VAT",
|
||||
unitQuantity: 8,
|
||||
unitNetPrice: 100,
|
||||
unitType: "hours",
|
||||
vatPercentage: 19,
|
||||
position: 5,
|
||||
},
|
||||
{
|
||||
name: "Item with 7% VAT",
|
||||
unitQuantity: 9,
|
||||
unitNetPrice: 100,
|
||||
unitType: "hours",
|
||||
vatPercentage: 7,
|
||||
position: 6,
|
||||
},
|
||||
{
|
||||
name: "Item with 7% VAT",
|
||||
unitQuantity: 4,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 7,
|
||||
position: 8,
|
||||
},
|
||||
{
|
||||
name: "Item with 21% VAT",
|
||||
unitQuantity: 3,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 21,
|
||||
position: 9,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 10,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 11,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 12,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 13,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 14,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 15,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 16,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 17,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 18,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 19,
|
||||
},
|
||||
{
|
||||
name: "Item with 0% VAT",
|
||||
unitQuantity: 1,
|
||||
unitNetPrice: 230,
|
||||
unitType: "hours",
|
||||
vatPercentage: 0,
|
||||
position: 20,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const demoDocumentSettings: interfaces.IDocumentSettings = {
|
||||
|
||||
@@ -148,82 +148,10 @@ export const DE_translations: Dictionary = {
|
||||
vat: "Umsatzsteuer",
|
||||
};
|
||||
|
||||
// Define Spanish translations
|
||||
// export const ES_translations: TTranslationImplementation = {
|
||||
// address: "Dirección",
|
||||
// bankConnection: "Conexión bancaria",
|
||||
// contactInfo: "Información de contacto",
|
||||
// description: "Descripción",
|
||||
// invoice: "Factura",
|
||||
// itemPos: "Pos.",
|
||||
// quantity: "Cantidad",
|
||||
// registrationInfo: "Información de registro",
|
||||
// reverseVatNote:
|
||||
// "El IVA se aplica por inversión del sujeto pasivo y debe ser pagado por el cliente.",
|
||||
// totalNetPrice: "Precio total neto",
|
||||
// unitNetPrice: "Precio unitario neto",
|
||||
// unitType: "Tipo de unidad",
|
||||
// yourCustomerId: "Su número de cliente:",
|
||||
// yourVatId: "Su ID de IVA:",
|
||||
// continuesOnPage: "Continúa en la página",
|
||||
// finalPageStatement: "Esta es la última página de este documento.",
|
||||
// page: "Página",
|
||||
// vatShort: "IVA",
|
||||
// };
|
||||
|
||||
// Define French translations
|
||||
// export const FR_translations: TTranslationImplementation = {
|
||||
// address: "Adresse",
|
||||
// bankConnection: "Coordonnées bancaires",
|
||||
// contactInfo: "Informations de contact",
|
||||
// description: "Description",
|
||||
// invoice: "Facture",
|
||||
// itemPos: "Position",
|
||||
// quantity: "Quantité",
|
||||
// registrationInfo: "Informations d'enregistrement",
|
||||
// reverseVatNote:
|
||||
// "La TVA s'applique selon le mécanisme d'autoliquidation et est à payer par le client.",
|
||||
// totalNetPrice: "Prix net total",
|
||||
// unitNetPrice: "Prix unitaire net",
|
||||
// unitType: "Type d'unité",
|
||||
// yourCustomerId: "Votre numéro de client :",
|
||||
// yourVatId: "Votre numéro de TVA :",
|
||||
// continuesOnPage: "Continue sur la page",
|
||||
// finalPageStatement: "Ceci est la dernière page de ce document.",
|
||||
// page: "Page",
|
||||
// vatShort: "TVA",
|
||||
// };
|
||||
|
||||
// Define Italian translations
|
||||
// export const IT_translations: TTranslationImplementation = {
|
||||
// address: "Indirizzo",
|
||||
// bankConnection: "Coordinate bancarie",
|
||||
// contactInfo: "Informazioni di contatto",
|
||||
// description: "Descrizione",
|
||||
// invoice: "Fattura",
|
||||
// itemPos: "Pos.",
|
||||
// quantity: "Quantità",
|
||||
// registrationInfo: "Informazioni di registrazione",
|
||||
// reverseVatNote:
|
||||
// "L'IVA è applicata con inversione contabile ed è a carico del cliente.",
|
||||
// totalNetPrice: "Prezzo netto totale",
|
||||
// unitNetPrice: "Prezzo netto unitario",
|
||||
// unitType: "Tipo di unità",
|
||||
// yourCustomerId: "Il tuo numero cliente:",
|
||||
// yourVatId: "Il tuo numero di partita IVA:",
|
||||
// continuesOnPage: "Continua alla pagina",
|
||||
// finalPageStatement: "Questa è l'ultima pagina di questo documento.",
|
||||
// page: "Pagina",
|
||||
// vatShort: "IVA",
|
||||
// };
|
||||
|
||||
// Language Code Map
|
||||
export const languageCodeMap: Record<string, Dictionary> = {
|
||||
EN: EN_translations,
|
||||
DE: DE_translations,
|
||||
// ES: ES_translations,
|
||||
// FR: FR_translations,
|
||||
// IT: IT_translations,
|
||||
};
|
||||
|
||||
// Language Code Type
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@design.estate/dees-document',
|
||||
version: '1.6.11',
|
||||
version: '2.0.2',
|
||||
description: 'A sophisticated framework for dynamically generating and rendering business documents like invoices with modern web technologies, featuring PDF creation, templating, and automation.'
|
||||
}
|
||||
|
||||
@@ -41,13 +41,13 @@ export class DeContentInvoice extends DeesElement {
|
||||
type: Object,
|
||||
reflect: true,
|
||||
})
|
||||
public letterData: plugins.tsclass.business.ILetter;
|
||||
accessor letterData: plugins.tsclass.finance.TInvoice;
|
||||
|
||||
@property({
|
||||
type: Object,
|
||||
reflect: true,
|
||||
})
|
||||
public documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
accessor documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -178,7 +178,7 @@ export class DeContentInvoice extends DeesElement {
|
||||
return totalNet;
|
||||
}
|
||||
|
||||
for (const item of this.letterData.content.invoiceData.items) {
|
||||
for (const item of this.letterData.items) {
|
||||
totalNet += item.unitNetPrice * item.unitQuantity;
|
||||
}
|
||||
return totalNet;
|
||||
@@ -200,7 +200,7 @@ export class DeContentInvoice extends DeesElement {
|
||||
public getVatGroups = () => {
|
||||
const vatGroups: {
|
||||
vatPercentage: number;
|
||||
items: plugins.tsclass.finance.IInvoice["items"];
|
||||
items: plugins.tsclass.finance.TInvoice["items"];
|
||||
vatAmountSum: number;
|
||||
}[] = [];
|
||||
|
||||
@@ -209,14 +209,14 @@ export class DeContentInvoice extends DeesElement {
|
||||
}
|
||||
|
||||
const taxAmounts: number[] = [];
|
||||
for (const item of this.letterData.content.invoiceData.items) {
|
||||
for (const item of this.letterData.items) {
|
||||
taxAmounts.includes(item.vatPercentage)
|
||||
? null
|
||||
: taxAmounts.push(item.vatPercentage);
|
||||
}
|
||||
|
||||
for (const taxAmount of taxAmounts) {
|
||||
const matchingItems = this.letterData.content.invoiceData.items.filter(
|
||||
const matchingItems = this.letterData.items.filter(
|
||||
(itemArg) => itemArg.vatPercentage === taxAmount
|
||||
);
|
||||
let sum = 0;
|
||||
@@ -324,7 +324,7 @@ export class DeContentInvoice extends DeesElement {
|
||||
}).format(
|
||||
new Date(this.letterData.date).setDate(
|
||||
new Date(this.letterData.date).getDate() +
|
||||
this.letterData?.content.invoiceData.dueInDays
|
||||
this.letterData?.dueInDays
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
@@ -334,14 +334,12 @@ export class DeContentInvoice extends DeesElement {
|
||||
}
|
||||
|
||||
private renderPaymentInfo(): TemplateResult {
|
||||
const bic =
|
||||
this.letterData?.content.invoiceData.billedBy.sepaConnection.bic;
|
||||
const name = this.letterData?.content.invoiceData.billedBy.name;
|
||||
const iban =
|
||||
this.letterData?.content.invoiceData.billedBy.sepaConnection.iban;
|
||||
const currency = this.letterData?.content.invoiceData.currency;
|
||||
const bic = this.letterData?.from.sepaConnection.bic;
|
||||
const name = this.letterData?.from.name;
|
||||
const iban = this.letterData?.from.sepaConnection.iban;
|
||||
const currency = this.letterData?.currency;
|
||||
const totalGross = this.getTotalGross();
|
||||
const reference = this.letterData?.content.invoiceData.id;
|
||||
const reference = this.letterData?.id;
|
||||
|
||||
return html`<div class="infoBox">
|
||||
<div>
|
||||
@@ -362,22 +360,23 @@ export class DeContentInvoice extends DeesElement {
|
||||
}
|
||||
|
||||
private renderReferencedContract(): TemplateResult {
|
||||
return this.documentSettings.enableInvoiceContractRefSection &&
|
||||
this.letterData?.content?.contractData?.contractDate
|
||||
? html`
|
||||
<div class="infoBox">
|
||||
<div class="label">
|
||||
${this.translateKey("invoice@@referencedContract")}
|
||||
</div>
|
||||
${this.translateKey("invoice@@referencedContract.text")}
|
||||
${new Intl.DateTimeFormat(this.documentSettings.languageCode, {
|
||||
dateStyle: this.documentSettings.dateStyle,
|
||||
}).format(
|
||||
new Date(this.letterData?.content.contractData.contractDate)
|
||||
)}.
|
||||
</div>
|
||||
`
|
||||
: null;
|
||||
return null;
|
||||
// return this.documentSettings.enableInvoiceContractRefSection &&
|
||||
// this.invoiceData?.content?.contractData?.contractDate
|
||||
// ? html`
|
||||
// <div class="infoBox">
|
||||
// <div class="label">
|
||||
// ${this.translateKey("invoice@@referencedContract")}
|
||||
// </div>
|
||||
// ${this.translateKey("invoice@@referencedContract.text")}
|
||||
// ${new Intl.DateTimeFormat(this.documentSettings.languageCode, {
|
||||
// dateStyle: this.documentSettings.dateStyle,
|
||||
// }).format(
|
||||
// new Date(this.invoiceData?.content.contractData.contractDate)
|
||||
// )}.
|
||||
// </div>
|
||||
// `
|
||||
// : null;
|
||||
}
|
||||
|
||||
public async attachInvoiceDom() {
|
||||
@@ -406,7 +405,7 @@ export class DeContentInvoice extends DeesElement {
|
||||
${this.translateKey("invoice@@price.total.net")}
|
||||
</div>
|
||||
</div>
|
||||
${this.letterData?.content.invoiceData?.items?.map(
|
||||
${this.letterData?.items?.map(
|
||||
(invoiceItem, index) => html`
|
||||
<div class="grid needsDataHeader">
|
||||
<div class="lineItem rightAlign">${index + 1}</div>
|
||||
@@ -438,10 +437,7 @@ export class DeContentInvoice extends DeesElement {
|
||||
</div>
|
||||
${this.getVatGroups().map((vatGroupArg) => {
|
||||
let itemNumbers = vatGroupArg.items
|
||||
.map(
|
||||
(item) =>
|
||||
this.letterData.content.invoiceData.items.indexOf(item) + 1
|
||||
)
|
||||
.map((item) => this.letterData.items.indexOf(item) + 1)
|
||||
.join(", ");
|
||||
return html`
|
||||
<div class="sumline">
|
||||
@@ -472,7 +468,7 @@ export class DeContentInvoice extends DeesElement {
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
|
||||
${this.letterData?.content.invoiceData.reverseCharge
|
||||
${this.letterData?.reverseCharge
|
||||
? html`<div class="taxNote">
|
||||
${this.translateKey("invoice@@vat.reverseCharge.note")}
|
||||
</div>`
|
||||
|
||||
@@ -25,7 +25,6 @@ import { DePage } from "./page.js";
|
||||
import { DeContentInvoice } from "./contentinvoice.js";
|
||||
|
||||
import { demoFunc } from "./document.demo.js";
|
||||
import { dedocumentSharedStyle } from "../style.js";
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
@@ -41,25 +40,25 @@ export class DeDocument extends DeesElement {
|
||||
type: String,
|
||||
reflect: true,
|
||||
})
|
||||
public format: "a4" = "a4";
|
||||
accessor format: "a4" = "a4";
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
reflect: true,
|
||||
})
|
||||
public viewWidth: number = null;
|
||||
accessor viewWidth: number = null;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
reflect: true,
|
||||
})
|
||||
public viewHeight: number = null;
|
||||
accessor viewHeight: number = null;
|
||||
|
||||
@property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
})
|
||||
printMode = false;
|
||||
accessor printMode = false;
|
||||
|
||||
@property({
|
||||
type: Object,
|
||||
@@ -72,7 +71,7 @@ export class DeDocument extends DeesElement {
|
||||
}
|
||||
},
|
||||
})
|
||||
public letterData: plugins.tsclass.business.ILetter;
|
||||
accessor letterData: plugins.tsclass.business.TLetter;
|
||||
|
||||
@property({
|
||||
type: Object,
|
||||
@@ -85,7 +84,7 @@ export class DeDocument extends DeesElement {
|
||||
}
|
||||
},
|
||||
})
|
||||
public documentSettings: plugins.shared.interfaces.IDocumentSettings =
|
||||
accessor documentSettings: plugins.shared.interfaces.IDocumentSettings =
|
||||
defaultDocumentSettings;
|
||||
|
||||
constructor() {
|
||||
@@ -95,7 +94,6 @@ export class DeDocument extends DeesElement {
|
||||
|
||||
public static styles = [
|
||||
domtools.elementBasic.staticStyles,
|
||||
dedocumentSharedStyle,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
@@ -136,7 +134,7 @@ export class DeDocument extends DeesElement {
|
||||
|
||||
public latestDocumentSettings: plugins.shared.interfaces.IDocumentSettings =
|
||||
null;
|
||||
public latestRenderedLetterData: plugins.tsclass.business.ILetter = null;
|
||||
public latestRenderedLetterData: plugins.tsclass.business.TLetter = null;
|
||||
public cleanupStore: any[] = [];
|
||||
|
||||
public async renderDocument() {
|
||||
@@ -158,7 +156,8 @@ export class DeDocument extends DeesElement {
|
||||
// lets append the content
|
||||
const content: DeContentInvoice = new DeContentInvoice();
|
||||
cleanUpStoreCurrentRender.push(content);
|
||||
content.letterData = this.letterData;
|
||||
content.letterData = this
|
||||
.letterData as unknown as plugins.tsclass.finance.TInvoice;
|
||||
content.documentSettings = this.documentSettings;
|
||||
document.body.appendChild(content);
|
||||
|
||||
|
||||
@@ -31,25 +31,25 @@ export class DeLetterHeader extends DeesElement {
|
||||
type: Object,
|
||||
reflect: true,
|
||||
})
|
||||
public letterData: plugins.tsclass.business.ILetter;
|
||||
accessor letterData: plugins.tsclass.finance.TInvoice;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
reflect: true,
|
||||
})
|
||||
public pageNumber: number = 1;
|
||||
accessor pageNumber: number = 1;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
reflect: true,
|
||||
})
|
||||
public pageTotalNumber: number = 1;
|
||||
accessor pageTotalNumber: number = 1;
|
||||
|
||||
@property({
|
||||
type: Object,
|
||||
reflect: true,
|
||||
})
|
||||
public documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
accessor documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -101,7 +101,7 @@ export class DeLetterHeader extends DeesElement {
|
||||
];
|
||||
|
||||
private renderDeliveryDate(from: Date, to: Date): TemplateResult {
|
||||
if (this.letterData.type !== "invoice") return null;
|
||||
if (this.letterData.accountingDocType !== "invoice") return null;
|
||||
const dateFormat = new Intl.DateTimeFormat(
|
||||
this.documentSettings.languageCode,
|
||||
{ dateStyle: this.documentSettings.dateStyle }
|
||||
@@ -171,25 +171,21 @@ export class DeLetterHeader extends DeesElement {
|
||||
"letterhead@@vat.yourId"
|
||||
)}
|
||||
</div>
|
||||
${this.letterData.to.vatId || "not provided"}
|
||||
${this.letterData.to.registrationDetails.vatId || "not provided"}
|
||||
|
||||
<!-- TODO: Make use of components -->
|
||||
${this.letterData.type === "invoice"
|
||||
${this.letterData.accountingDocType === "invoice"
|
||||
? html` <div class="label">
|
||||
${plugins.shared.translation.translate(
|
||||
this.documentSettings.languageCode,
|
||||
"letterhead@@invoice.number"
|
||||
)}
|
||||
</div>
|
||||
${this.letterData.content.invoiceData.id || "not registered"}`
|
||||
${this.letterData.id || "not registered"}`
|
||||
: null}
|
||||
${this.renderDeliveryDate(
|
||||
new Date(
|
||||
this.letterData.content?.invoiceData?.periodOfPerformance?.from
|
||||
),
|
||||
new Date(
|
||||
this.letterData.content?.invoiceData?.periodOfPerformance?.to
|
||||
)
|
||||
new Date(this.letterData.periodOfPerformance?.from),
|
||||
new Date(this.letterData.periodOfPerformance?.to)
|
||||
)}
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
import * as plugins from "../plugins.js";
|
||||
|
||||
import { defaultDocumentSettings } from "./document.js";
|
||||
import { dedocumentSharedStyle } from "../style.js";
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
@@ -28,44 +27,44 @@ export class DePage extends DeesElement {
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
viewWidth: number = null;
|
||||
accessor viewWidth: number = null;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
viewHeight: number = null;
|
||||
accessor viewHeight: number = null;
|
||||
|
||||
@property({
|
||||
type: String,
|
||||
})
|
||||
public format: "a4" = "a4";
|
||||
accessor format: "a4" = "a4";
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
public pageNumber: number = 1;
|
||||
accessor pageNumber: number = 1;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
public pageTotalNumber: number = 1;
|
||||
accessor pageTotalNumber: number = 1;
|
||||
|
||||
@property({
|
||||
type: Object,
|
||||
})
|
||||
public letterData: tsclass.business.ILetter = null;
|
||||
accessor letterData: tsclass.business.TLetter = null;
|
||||
|
||||
@property({
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
})
|
||||
printMode = false;
|
||||
accessor printMode = false;
|
||||
|
||||
@property({
|
||||
type: Object,
|
||||
reflect: true,
|
||||
})
|
||||
public documentSettings: plugins.shared.interfaces.IDocumentSettings =
|
||||
accessor documentSettings: plugins.shared.interfaces.IDocumentSettings =
|
||||
defaultDocumentSettings;
|
||||
|
||||
constructor() {
|
||||
@@ -75,7 +74,6 @@ export class DePage extends DeesElement {
|
||||
|
||||
public static styles = [
|
||||
domtools.elementBasic.staticStyles,
|
||||
dedocumentSharedStyle,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
@@ -134,17 +132,14 @@ export class DePage extends DeesElement {
|
||||
];
|
||||
|
||||
public render(): TemplateResult {
|
||||
const theme = this.documentSettings.theme;
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
--theme-color-primary-fg: ${this.documentSettings.theme
|
||||
?.colorPrimaryForeground};
|
||||
--theme-color-primary-bg: ${this.documentSettings.theme
|
||||
?.colorPrimaryBackground};
|
||||
--theme-color-accent-fg: ${this.documentSettings.theme
|
||||
?.colorAccentForeground};
|
||||
--theme-color-accent-bg: ${this.documentSettings.theme
|
||||
?.colorAccentBackground};
|
||||
${theme?.colorPrimaryForeground ? `--theme-color-primary-fg: ${theme.colorPrimaryForeground};` : ''}
|
||||
${theme?.colorPrimaryBackground ? `--theme-color-primary-bg: ${theme.colorPrimaryBackground};` : ''}
|
||||
${theme?.colorAccentForeground ? `--theme-color-accent-fg: ${theme.colorAccentForeground};` : ''}
|
||||
${theme?.colorAccentBackground ? `--theme-color-accent-bg: ${theme.colorAccentBackground};` : ''}
|
||||
}
|
||||
|
||||
.page {
|
||||
@@ -153,21 +148,17 @@ export class DePage extends DeesElement {
|
||||
}
|
||||
|
||||
.page:not(.page--first) {
|
||||
background-image: ${this.documentSettings.theme?.pageBackground ??
|
||||
"none"};
|
||||
background-image: ${theme?.pageBackground ?? "none"};
|
||||
}
|
||||
|
||||
.page.page--first {
|
||||
background-image: ${this.documentSettings.theme
|
||||
?.coverPageBackground ??
|
||||
this.documentSettings.theme?.pageBackground ??
|
||||
"none"};
|
||||
background-image: ${theme?.coverPageBackground ?? theme?.pageBackground ?? "none"};
|
||||
}
|
||||
</style>
|
||||
<div id="scaleWrapper">
|
||||
<dedocument-pagecontainer .printMode=${this.printMode}>
|
||||
<div
|
||||
class="page page__background ${this.pageNumber === 1
|
||||
class="page ${this.pageNumber === 1
|
||||
? "page--first"
|
||||
: ""}"
|
||||
></div>
|
||||
|
||||
@@ -27,12 +27,12 @@ export class DePageContainer extends DeesElement {
|
||||
@property({
|
||||
type: String,
|
||||
})
|
||||
public format: "a4" = "a4";
|
||||
accessor format: "a4" = "a4";
|
||||
|
||||
@property({
|
||||
type: Boolean,
|
||||
})
|
||||
public printMode = false;
|
||||
accessor printMode = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -50,6 +50,7 @@ export class DePageContainer extends DeesElement {
|
||||
position: relative;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
background: var(--text-bg-color, #ffffff);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -28,23 +28,23 @@ export class DePageContent extends DeesElement {
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
public letterData: plugins.tsclass.business.ILetter;
|
||||
accessor letterData: plugins.tsclass.business.TLetter;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
public pageNumber: number = 1;
|
||||
accessor pageNumber: number = 1;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
public pageTotalNumber: number = 1;
|
||||
accessor pageTotalNumber: number = 1;
|
||||
|
||||
@property({
|
||||
type: Object,
|
||||
reflect: true,
|
||||
})
|
||||
public documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
accessor documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@@ -27,23 +27,23 @@ export class DePageFooter extends DeesElement {
|
||||
@property({
|
||||
type: Object,
|
||||
})
|
||||
letterData: plugins.tsclass.business.ILetter;
|
||||
accessor letterData: plugins.tsclass.business.TLetter;
|
||||
|
||||
@property({
|
||||
type: Object,
|
||||
reflect: true,
|
||||
})
|
||||
documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
accessor documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
public pageNumber: number = 1;
|
||||
accessor pageNumber: number = 1;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
public pageTotalNumber: number = 1;
|
||||
accessor pageTotalNumber: number = 1;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -119,17 +119,20 @@ export class DePageFooter extends DeesElement {
|
||||
${this.letterData.from.address.city}<br />
|
||||
${this.letterData.from.address.country}
|
||||
</div>
|
||||
<div>
|
||||
<strong
|
||||
>${plugins.shared.translation.translate(
|
||||
this.documentSettings.languageCode,
|
||||
"footer@@registration.label"
|
||||
)}:</strong
|
||||
><br />
|
||||
Amtsgericht Bremen<br />
|
||||
<i>reg-#:</i> HRB 35230 HB<br />
|
||||
<i>vat-id:</i> ${this.letterData.from.vatId}
|
||||
</div>
|
||||
${this.letterData.from.registrationDetails
|
||||
? html` <div>
|
||||
<strong
|
||||
>${plugins.shared.translation.translate(
|
||||
this.documentSettings.languageCode,
|
||||
"footer@@registration.label"
|
||||
)}:</strong
|
||||
><br />
|
||||
${this.letterData.from.registrationDetails.registrationName}<br />
|
||||
<i>reg-#:</i> ${this.letterData.from.registrationDetails
|
||||
.registrationId}<br />
|
||||
<i>vat-id:</i> ${this.letterData.from.registrationDetails.vatId}
|
||||
</div>`
|
||||
: null}
|
||||
<div>
|
||||
<strong
|
||||
>${plugins.shared.translation.translate(
|
||||
|
||||
@@ -28,23 +28,23 @@ export class DePageHeader extends DeesElement {
|
||||
@property({
|
||||
type: Object,
|
||||
})
|
||||
public letterData: plugins.tsclass.business.ILetter = null;
|
||||
accessor letterData: plugins.tsclass.business.TLetter = null;
|
||||
|
||||
@property({
|
||||
type: Object,
|
||||
reflect: true,
|
||||
})
|
||||
documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
accessor documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
public pageNumber: number = 1;
|
||||
accessor pageNumber: number = 1;
|
||||
|
||||
@property({
|
||||
type: Number,
|
||||
})
|
||||
public pageTotalNumber: number = 1;
|
||||
accessor pageTotalNumber: number = 1;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@@ -33,25 +33,25 @@ export class DedocumentPaymentCode extends DeesElement {
|
||||
];
|
||||
|
||||
@query("canvas")
|
||||
private canvasEl!: HTMLCanvasElement;
|
||||
accessor canvasEl!: HTMLCanvasElement;
|
||||
|
||||
@property()
|
||||
public bic: string;
|
||||
accessor bic: string;
|
||||
|
||||
@property()
|
||||
public name: string;
|
||||
accessor name: string;
|
||||
|
||||
@property()
|
||||
public iban: string;
|
||||
accessor iban: string;
|
||||
|
||||
@property()
|
||||
public currency: string;
|
||||
accessor currency: string;
|
||||
|
||||
@property({ type: Number })
|
||||
public totalGross: number;
|
||||
accessor totalGross: number;
|
||||
|
||||
@property()
|
||||
public reference: string;
|
||||
accessor reference: string;
|
||||
|
||||
private updateQRCode(): void {
|
||||
if (!this.canvasEl) return;
|
||||
|
||||
@@ -26,13 +26,13 @@ export class DeDocumentViewer extends DeesElement {
|
||||
type: Object,
|
||||
reflect: true,
|
||||
})
|
||||
public letterData: plugins.tsclass.business.ILetter = null;
|
||||
accessor letterData: plugins.tsclass.business.TLetter = null;
|
||||
|
||||
@property({
|
||||
type: Object,
|
||||
reflect: true,
|
||||
})
|
||||
public documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
accessor documentSettings: plugins.shared.interfaces.IDocumentSettings;
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { html } from '@design.estate/dees-element';
|
||||
import * as plugins from "../plugins.js";
|
||||
import { html } from "@design.estate/dees-element";
|
||||
|
||||
export const page1 = () => html`
|
||||
<style>
|
||||
@@ -7,11 +7,15 @@ export const page1 = () => html`
|
||||
margin: 16px;
|
||||
}
|
||||
</style>
|
||||
<dedocument-dedocument .printMode=${false} letterData=${plugins.smartjson.stringifyBase64({
|
||||
<dedocument-dedocument
|
||||
.printMode=${false}
|
||||
letterData=${plugins.smartjson.stringifyBase64({
|
||||
...plugins.shared.demoLetter,
|
||||
from: {
|
||||
...plugins.shared.demoLetter.from,
|
||||
description: 'a string set via stringified JSON'
|
||||
}
|
||||
} as plugins.tsclass.business.ILetter)}> </dedocument-dedocument>
|
||||
description: "a string set via stringified JSON",
|
||||
},
|
||||
} as plugins.tsclass.finance.TInvoice)}
|
||||
>
|
||||
</dedocument-dedocument>
|
||||
`;
|
||||
|
||||
@@ -21,7 +21,7 @@ export const dedocumentSharedStyle = css`
|
||||
--text-bg-color: var(--color-primary-bg);
|
||||
--label-fg: var(--color-dark);
|
||||
--label-bg: var(--color-grey);
|
||||
--footer-separator-bg-color: var(--color-accent);
|
||||
--footer-separator-bg-color: var(--color-accent-bg);
|
||||
--footer-separator-fg-color: var(--color-light);
|
||||
|
||||
/* Functional variables */
|
||||
@@ -32,7 +32,6 @@ export const dedocumentSharedStyle = css`
|
||||
--text-font-size: var(--theme-text-font-size, 12px);
|
||||
|
||||
color: var(--text-fg-color);
|
||||
background: var(--text-bg-color);
|
||||
font-family: var(--text-font-family);
|
||||
font-size: var(--text-font-size);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
|
||||
Reference in New Issue
Block a user