Skip to content

Commit 8f30335

Browse files
committed
update to simplified annotation usage
1 parent ced1f6b commit 8f30335

File tree

8 files changed

+261
-706
lines changed

8 files changed

+261
-706
lines changed

README.md

Lines changed: 54 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -18,118 +18,86 @@ See [Getting Started](https://cap.cloud.sap/docs/get-started) on how to jumpstar
1818

1919
Usage of this plugin requires a valid subscription of the [SAP Print Service](https://help.sap.com/docs/SCP_PRINT_SERVICE).
2020

21-
To integrate the print functionality in your application, simply annotate any action with `@print`. This annotation automatically manages the process of sending documents to the print queues, requiring no additional setup for handling print jobs.
21+
## Usage
2222

23-
### Required Fields
23+
To use this plugin to print documents there are two main steps:
2424

25-
The following three fields should be annotated with the corresponding `@print` annotations:
25+
1. Add required annotations to your CDS model.
26+
a. Entity
27+
b. Action
28+
2. Configure print queues to select from available options. (Optional, but recommended)
2629

27-
1. **`@print.queue`**: Specifies the queue to which the document should be sent for printing.
28-
2. **`@print.numberOfCopies`**: Defines the number of copies to be printed.
29-
3. **`@print.fileContent`**: Provides the file content to be printed. You can also specify the file name using the `fileNameField` property.
30+
### Annotations in CDS model
3031

31-
#### Example
32-
33-
```cds
34-
@print.fileContent: {
35-
fileNameField: '<Field Name>',
36-
}
37-
```
38-
39-
Multiple fields can be annotated with `@print.fileContent` to send several documents to the print queue in a single action.
40-
41-
### Main Document
42-
43-
To designate a specific document as the primary document for printing, annotate it with `@print.MainDocument`:
32+
#### Entity
4433

45-
```cds
46-
@print.MainDocument
47-
invoiceContent,
48-
```
49-
50-
This ensures the specified document is treated as the main document when multiple documents are involved.
51-
52-
## Print Queue Configuration
34+
First of all, the entity needs to be annotated to define the content and the name of the document to be printed.
5335

54-
You can retrieve all available print queues from the Print Service Application for selection by defining a `Queues` entity with **skip persistency**. This setup will offer a value help for the print queues, allowing users to select from available options.
55-
56-
### Define the `Queues` Entity
57-
58-
Define an entity like `Product` and associate it with the `Queues` entity as shown below:
59-
60-
#### Example
6136
```cds
62-
entity Product {
63-
qName : Association to one Queues;
37+
entity Incidents : cuid {
38+
@print.fileContent
39+
file : LargeBinary @Core.MediaType: 'application/pdf';
40+
@print.fileName
41+
fileName : String;
6442
}
6543
66-
@cds.skip.persistence
67-
entity Queues {
68-
key ID : String;
69-
description : String;
70-
}
7144
```
7245

73-
#### Annotating with `@print.queue`
46+
- `@print.fileContent`: Annotates the field containing the document content to be printed.
47+
- `@print.fileName`: Annotates the field containing the name of the document
7448

75-
Once the `Queues` entity is defined, specify it in the `@print.queue` annotation like so:
49+
#### Annotation of actions
50+
Sending a print request works via bound actions annotated with `@print`. The parameter of the action are used to define the print job details.
7651

7752
```cds
78-
@print.queue: {
79-
SourceEntity: 'Queues'
53+
service IncidentService {
54+
entity Incidents as projection on db.Incidents actions {
55+
56+
@print
57+
action printIncidentFile(
58+
@Common: {
59+
ValueListWithFixedValues,
60+
ValueList: {
61+
$Type: 'Common.ValueListType',
62+
CollectionPath: 'Queues',
63+
Parameters: [{
64+
$Type: 'Common.ValueListParameterInOut',
65+
LocalDataProperty: qnameID,
66+
ValueListProperty: 'ID'
67+
}]
68+
},
69+
Label: 'Print Queues',
70+
}
71+
@print.queue
72+
qnameID: String,
73+
@print.numberOfCopies
74+
@UI.ParameterDefaultValue : 1
75+
copies: Integer
76+
);
77+
};
8078
}
81-
qName
8279
```
8380

84-
### Parameterizing Print Queue in Actions
85-
86-
Alternatively, if the print queue is passed as a parameter in the action, you can annotate it directly within the action definition. This can be done as follows:
81+
- `@print`: Annotates the action that triggers the print job.
82+
- `@print.queue`: Annotates the parameter specifying the print queue. It is recommended to use a value help for this parameter to select from available print queues. See TOOD
83+
- `@print.numberOfCopies`: Annotates the parameter specifying the number of copies to print
8784

88-
#### In Database Definition:
85+
### Queues
86+
Every print request needs to specify a print queue it is send to. It is recommended to provide a value help for the print queue selection. To enbale this, define an entity as projection on the `Queues` entity provided by the print service. When this projection is in place, the plugin automatically provides the available print queues coming from the print service.
8987

9088
```cds
91-
entity Product {
92-
qName : Association to one Queues;
93-
}
89+
using {sap.print as sp} from '@cap-js/print';
9490
95-
@cds.skip.persistence
96-
entity Queues {
97-
key ID : String;
98-
description : String;
91+
service IncidentService {
92+
entity Queues as projection on sp.Queues;
9993
}
10094
```
10195

102-
#### In Service Definition:
103-
104-
```cds
105-
service MyService {
106-
@print
107-
action print(
108-
@print.queue: {
109-
SourceEntity: 'Queues'
110-
}
111-
@Common: {
112-
ValueListWithFixedValues,
113-
ValueList: {
114-
$Type: 'Common.ValueListType',
115-
CollectionPath: 'Queues',
116-
Parameters: [{
117-
$Type: 'Common.ValueListParameterInOut',
118-
LocalDataProperty: qnameID,
119-
ValueListProperty: 'ID'
120-
}]
121-
},
122-
Label: 'Print Queues',
123-
}
124-
qnameID: String
125-
);
126-
127-
entity Queues as projection on db.Queues;
128-
}
129-
```
96+
## Local Development
13097

131-
In this setup, the `qnameID` parameter will be used to dynamically select the print queue from the `Queues` entity. The `Common.ValueList` provides a drop-down selection for available queues during runtime.
98+
When running the application locally, i.e. `cds watch`, the print service is mocked. This mock implementation prints the print job details to the console instead of sending it to the actual print service. It also provides a number of sample print queues for selection.
13299

100+
You can also run the application locally with a binding to the cloud print service with CAP profiles. For more information, see [Hybrid Testing](https://cap.cloud.sap/docs/advanced/hybrid-testing#hybrid-testing).
133101

134102
## Note
135103

@@ -143,14 +111,6 @@ If you are running the application in a production way locally(E.g. adding VCAP_
143111
}
144112
```
145113

146-
If you are running the application in offline mode which is without remote connection to the online environment, you can add the environmental variable `PRINT_CONSOLE_MODE=true cds watch` in the `package.json` as shown below.
147-
148-
```json
149-
"scripts": {
150-
"watch-offline": "PRINT_CONSOLE_MODE=true cds watch"
151-
}
152-
```
153-
154114
## Support, Feedback, Contributing
155115

156116
This project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://github.com/cap-js/print/issues). Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](CONTRIBUTING.md).

cds-plugin.js

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
const {
2-
getFieldsHoldingPrintConfig,
3-
getAnnotatedParamsOfAction,
4-
getPrintParamsAttributeFromAction
5-
} = require('./lib/annotation-helper');
6-
71
const cds = require('@sap/cds');
82
const LOG = cds.log('print');
93

104
const PRINT = "@print";
5+
const PRINT_NUMBER_OF_COPIES = "@print.numberOfCopies";
6+
const PRINT_QUEUE = "@print.queue";
7+
const PRINT_FILE_NAME = "@print.fileName";
8+
const PRINT_FILE_CONTENT = "@print.fileContent";
9+
10+
const QUEUE_ENTITY_NAME = "sap.print.Queues";
1111

1212
cds.once("served", async () => {
1313
// Iterate over all services
1414
for (let srv of cds.services) {
1515
// Iterate over all entities in the service
1616
for (let entity of srv.entities) {
1717

18-
if (entity.projection?.from.ref[0] === "sap.print.Queues") {
18+
if (entity.projection?.from.ref[0] === QUEUE_ENTITY_NAME) {
1919
const printer = await cds.connect.to("print");
2020

2121
srv.after('READ', entity, async (_, req) => {
@@ -45,22 +45,37 @@ cds.once("served", async () => {
4545

4646
const object = await SELECT.one.from(req.subject).columns([fileNameAttribute, contentAttribute]);
4747

48+
if(!object) return req.reject(404, `Object not found for printing.`);
49+
if(!numberOfCopies) return req.reject(400, `Please specify number of copies to print.`);
50+
if(!queueID) return req.reject(400, `Please specify print queue.`);
51+
52+
const streamToBase64 = async (stream) => {
53+
const chunks = [];
54+
for await (const chunk of stream) {
55+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
56+
}
57+
return Buffer.concat(chunks).toString('base64');
58+
};
4859
try {
4960

5061
await printer.print({
5162
qname: queueID,
5263
numberOfCopies: numberOfCopies,
5364
docsToPrint: [{
5465
fileName: object[fileNameAttribute],
55-
content: object[contentAttribute].toString('base64'),
66+
content: await streamToBase64(object[contentAttribute]),
5667
isMainDocument: true
5768
}]
5869
})
5970

71+
return req.info({
72+
status: 200,
73+
message: `Print job for file ${object[fileNameAttribute]} sent to queue ${queueID} for ${numberOfCopies} copies.`
74+
});
75+
6076
}
6177
catch (error) {
62-
LOG.error(error)
63-
req.reject(500, `Printing failed: ${error.message ?? "Unknown error"}`);
78+
return req.reject(500, `Error: ${error.message ?? "Unknown error"}`);
6479
}
6580

6681

@@ -70,3 +85,25 @@ cds.once("served", async () => {
7085
}
7186
}
7287
});
88+
89+
function getPrintParamsAttributeFromAction(entity, action) {
90+
91+
const copiesElement = Object.values(action.params).find(el => el[PRINT_NUMBER_OF_COPIES]);
92+
const queueElement = Object.values(action.params).find(el => el[PRINT_QUEUE]);
93+
94+
const fileName = Object.values(entity.elements).find(el => el[PRINT_FILE_NAME]);
95+
const content = Object.values(entity.elements).find(el => el[PRINT_FILE_CONTENT]);
96+
97+
98+
if(!copiesElement || !queueElement, !fileName || !content) {
99+
cds.error(`Print action ${action.name} is missing required annotations. Make sure @print.numberOfCopies, @print.queue are present in the action and @print.fileName and @print.fileContent are present in the entity.`);
100+
}
101+
102+
return {
103+
numberOfCopiesAttribute: copiesElement.name,
104+
queueIDAttribute: queueElement.name,
105+
fileNameAttribute: fileName.name,
106+
contentAttribute: content.name
107+
};
108+
}
109+

0 commit comments

Comments
 (0)