@pokash/n8n-nodes-optima-rest-api 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -491,7 +491,7 @@ class OptimaRestApi {
|
|
|
491
491
|
displayName: 'SQL Filter',
|
|
492
492
|
name: 'filtrSQL',
|
|
493
493
|
type: 'string',
|
|
494
|
-
required:
|
|
494
|
+
required: false,
|
|
495
495
|
displayOptions: {
|
|
496
496
|
show: {
|
|
497
497
|
resource: ['print'],
|
|
@@ -500,7 +500,7 @@ class OptimaRestApi {
|
|
|
500
500
|
},
|
|
501
501
|
default: '',
|
|
502
502
|
placeholder: 'TrN_TrnId = 123',
|
|
503
|
-
description: 'SQL filter to select documents',
|
|
503
|
+
description: 'SQL filter to select documents (e.g. "TrN_TrNID = 123" or "EDN_EDNId = 1002")',
|
|
504
504
|
},
|
|
505
505
|
// Print Format ID
|
|
506
506
|
{
|
|
@@ -517,6 +517,46 @@ class OptimaRestApi {
|
|
|
517
517
|
default: 1,
|
|
518
518
|
description: 'ID of the print format from Optima',
|
|
519
519
|
},
|
|
520
|
+
// Print Dynamic Parameters
|
|
521
|
+
{
|
|
522
|
+
displayName: 'Dynamic Parameters',
|
|
523
|
+
name: 'dynamicParameters',
|
|
524
|
+
type: 'fixedCollection',
|
|
525
|
+
typeOptions: {
|
|
526
|
+
multipleValues: true,
|
|
527
|
+
},
|
|
528
|
+
displayOptions: {
|
|
529
|
+
show: {
|
|
530
|
+
resource: ['print'],
|
|
531
|
+
operation: ['printDocument'],
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
default: {},
|
|
535
|
+
placeholder: 'Add Parameter',
|
|
536
|
+
description: 'Dynamic parameters passed to the print template',
|
|
537
|
+
options: [
|
|
538
|
+
{
|
|
539
|
+
name: 'parameter',
|
|
540
|
+
displayName: 'Parameter',
|
|
541
|
+
values: [
|
|
542
|
+
{
|
|
543
|
+
displayName: 'Name',
|
|
544
|
+
name: 'name',
|
|
545
|
+
type: 'string',
|
|
546
|
+
default: '',
|
|
547
|
+
description: 'Parameter name as defined in the print template',
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
displayName: 'Value',
|
|
551
|
+
name: 'value',
|
|
552
|
+
type: 'string',
|
|
553
|
+
default: '',
|
|
554
|
+
description: 'Parameter value',
|
|
555
|
+
},
|
|
556
|
+
],
|
|
557
|
+
},
|
|
558
|
+
],
|
|
559
|
+
},
|
|
520
560
|
],
|
|
521
561
|
};
|
|
522
562
|
}
|
|
@@ -531,16 +571,16 @@ class OptimaRestApi {
|
|
|
531
571
|
// Create unique cache key based on credentials
|
|
532
572
|
const loginModel = credentials.loginModel || 'subscription';
|
|
533
573
|
const cacheKey = `${gatewayUrl}:${credentials.username}:${credentials.company}:${loginModel}`;
|
|
534
|
-
//
|
|
535
|
-
const
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
574
|
+
// Helper function to get or refresh authentication token
|
|
575
|
+
const getAuthToken = async (forceRefresh = false) => {
|
|
576
|
+
// Check cache unless forced refresh
|
|
577
|
+
if (!forceRefresh) {
|
|
578
|
+
const cached = tokenCache.get(cacheKey);
|
|
579
|
+
const now = Date.now();
|
|
580
|
+
if (cached && cached.expiresAt > now) {
|
|
581
|
+
return cached.token;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
544
584
|
// Build login body based on selected model
|
|
545
585
|
const loginBody = {
|
|
546
586
|
username: credentials.username,
|
|
@@ -548,11 +588,9 @@ class OptimaRestApi {
|
|
|
548
588
|
company: credentials.company,
|
|
549
589
|
};
|
|
550
590
|
if (loginModel === 'subscription') {
|
|
551
|
-
// Subscription model (Optima 2026+)
|
|
552
591
|
loginBody.subscriptionPackages = credentials.subscriptionPackages || 'Podstawowy';
|
|
553
592
|
}
|
|
554
593
|
else {
|
|
555
|
-
// Traditional modules model
|
|
556
594
|
loginBody.modules = credentials.modules || 'KP';
|
|
557
595
|
}
|
|
558
596
|
const loginResponse = await this.helpers.request({
|
|
@@ -561,11 +599,43 @@ class OptimaRestApi {
|
|
|
561
599
|
body: loginBody,
|
|
562
600
|
json: true,
|
|
563
601
|
});
|
|
564
|
-
token = loginResponse.Token;
|
|
602
|
+
const token = loginResponse.Token;
|
|
565
603
|
// Cache token for 50 minutes (assuming 60 min expiry, refresh 10 min early)
|
|
604
|
+
const now = Date.now();
|
|
566
605
|
const expiresAt = now + (50 * 60 * 1000);
|
|
567
606
|
tokenCache.set(cacheKey, { token, expiresAt });
|
|
568
|
-
|
|
607
|
+
return token;
|
|
608
|
+
};
|
|
609
|
+
// Helper function to make authenticated API requests with automatic retry on 401
|
|
610
|
+
const makeAuthenticatedRequest = async (requestOptions) => {
|
|
611
|
+
var _a;
|
|
612
|
+
// Get token
|
|
613
|
+
let token = await getAuthToken();
|
|
614
|
+
// Add authorization header
|
|
615
|
+
const options = {
|
|
616
|
+
...requestOptions,
|
|
617
|
+
headers: {
|
|
618
|
+
...requestOptions.headers,
|
|
619
|
+
Authorization: `Bearer ${token}`,
|
|
620
|
+
},
|
|
621
|
+
};
|
|
622
|
+
try {
|
|
623
|
+
// Try the request
|
|
624
|
+
return await this.helpers.request(options);
|
|
625
|
+
}
|
|
626
|
+
catch (error) {
|
|
627
|
+
// Check if it's a 401 error
|
|
628
|
+
if (error.statusCode === 401 || ((_a = error.response) === null || _a === void 0 ? void 0 : _a.statusCode) === 401) {
|
|
629
|
+
// Token expired/invalid - refresh and retry once
|
|
630
|
+
token = await getAuthToken(true);
|
|
631
|
+
// Retry with new token
|
|
632
|
+
options.headers.Authorization = `Bearer ${token}`;
|
|
633
|
+
return await this.helpers.request(options);
|
|
634
|
+
}
|
|
635
|
+
// Re-throw other errors
|
|
636
|
+
throw error;
|
|
637
|
+
}
|
|
638
|
+
};
|
|
569
639
|
for (let i = 0; i < items.length; i++) {
|
|
570
640
|
try {
|
|
571
641
|
if (resource === 'customer') {
|
|
@@ -589,12 +659,9 @@ class OptimaRestApi {
|
|
|
589
659
|
const url = queryString
|
|
590
660
|
? `${gatewayUrl}/api/customer?${queryString}`
|
|
591
661
|
: `${gatewayUrl}/api/customer`;
|
|
592
|
-
const response = await
|
|
662
|
+
const response = await makeAuthenticatedRequest({
|
|
593
663
|
method: 'GET',
|
|
594
664
|
url,
|
|
595
|
-
headers: {
|
|
596
|
-
Authorization: `Bearer ${token}`,
|
|
597
|
-
},
|
|
598
665
|
json: true,
|
|
599
666
|
});
|
|
600
667
|
// API returns { Success: true, Customers: [...], TotalCount: ... }
|
|
@@ -661,12 +728,9 @@ class OptimaRestApi {
|
|
|
661
728
|
}
|
|
662
729
|
else if (operation === 'create') {
|
|
663
730
|
const customerData = JSON.parse(this.getNodeParameter('customerData', i));
|
|
664
|
-
const response = await
|
|
731
|
+
const response = await makeAuthenticatedRequest({
|
|
665
732
|
method: 'POST',
|
|
666
733
|
url: `${gatewayUrl}/api/customer`,
|
|
667
|
-
headers: {
|
|
668
|
-
Authorization: `Bearer ${token}`,
|
|
669
|
-
},
|
|
670
734
|
body: customerData,
|
|
671
735
|
json: true,
|
|
672
736
|
});
|
|
@@ -683,12 +747,9 @@ class OptimaRestApi {
|
|
|
683
747
|
const customerData = JSON.parse(this.getNodeParameter('customerData', i));
|
|
684
748
|
// Add ID to the customer data for PUT request
|
|
685
749
|
customerData.ID = customerId;
|
|
686
|
-
const response = await
|
|
750
|
+
const response = await makeAuthenticatedRequest({
|
|
687
751
|
method: 'PUT',
|
|
688
752
|
url: `${gatewayUrl}/api/customer`,
|
|
689
|
-
headers: {
|
|
690
|
-
Authorization: `Bearer ${token}`,
|
|
691
|
-
},
|
|
692
753
|
body: customerData,
|
|
693
754
|
json: true,
|
|
694
755
|
});
|
|
@@ -702,12 +763,9 @@ class OptimaRestApi {
|
|
|
702
763
|
}
|
|
703
764
|
else if (operation === 'delete') {
|
|
704
765
|
const customerId = this.getNodeParameter('customerId', i);
|
|
705
|
-
await
|
|
766
|
+
await makeAuthenticatedRequest({
|
|
706
767
|
method: 'DELETE',
|
|
707
768
|
url: `${gatewayUrl}/api/customer/${customerId}`,
|
|
708
|
-
headers: {
|
|
709
|
-
Authorization: `Bearer ${token}`,
|
|
710
|
-
},
|
|
711
769
|
json: true,
|
|
712
770
|
});
|
|
713
771
|
const result = {
|
|
@@ -723,12 +781,9 @@ class OptimaRestApi {
|
|
|
723
781
|
if (operation === 'createInvoice') {
|
|
724
782
|
const documentType = this.getNodeParameter('documentType', i);
|
|
725
783
|
const documentData = JSON.parse(this.getNodeParameter('documentData', i));
|
|
726
|
-
const response = await
|
|
784
|
+
const response = await makeAuthenticatedRequest({
|
|
727
785
|
method: 'POST',
|
|
728
786
|
url: `${gatewayUrl}/api/Documents/Invoice/${documentType}`,
|
|
729
|
-
headers: {
|
|
730
|
-
Authorization: `Bearer ${token}`,
|
|
731
|
-
},
|
|
732
787
|
body: documentData,
|
|
733
788
|
json: true,
|
|
734
789
|
});
|
|
@@ -743,12 +798,9 @@ class OptimaRestApi {
|
|
|
743
798
|
else if (operation === 'createAdditionalRecord') {
|
|
744
799
|
const recordType = this.getNodeParameter('recordType', i);
|
|
745
800
|
const recordData = JSON.parse(this.getNodeParameter('recordData', i));
|
|
746
|
-
const response = await
|
|
801
|
+
const response = await makeAuthenticatedRequest({
|
|
747
802
|
method: 'POST',
|
|
748
803
|
url: `${gatewayUrl}/api/Documents/AdditionalRecords/${recordType}`,
|
|
749
|
-
headers: {
|
|
750
|
-
Authorization: `Bearer ${token}`,
|
|
751
|
-
},
|
|
752
804
|
body: recordData,
|
|
753
805
|
json: true,
|
|
754
806
|
});
|
|
@@ -773,12 +825,9 @@ class OptimaRestApi {
|
|
|
773
825
|
};
|
|
774
826
|
const dictConfig = dictionaryEndpoints[operation];
|
|
775
827
|
if (dictConfig) {
|
|
776
|
-
const response = await
|
|
828
|
+
const response = await makeAuthenticatedRequest({
|
|
777
829
|
method: 'GET',
|
|
778
830
|
url: `${gatewayUrl}/api/${dictConfig.endpoint}`,
|
|
779
|
-
headers: {
|
|
780
|
-
Authorization: `Bearer ${token}`,
|
|
781
|
-
},
|
|
782
831
|
json: true,
|
|
783
832
|
});
|
|
784
833
|
// API returns { Success: true, [DataKey]: [...], TotalCount: ... }
|
|
@@ -855,12 +904,9 @@ class OptimaRestApi {
|
|
|
855
904
|
const url = queryString
|
|
856
905
|
? `${gatewayUrl}/api/product?${queryString}`
|
|
857
906
|
: `${gatewayUrl}/api/product`;
|
|
858
|
-
const response = await
|
|
907
|
+
const response = await makeAuthenticatedRequest({
|
|
859
908
|
method: 'GET',
|
|
860
909
|
url,
|
|
861
|
-
headers: {
|
|
862
|
-
Authorization: `Bearer ${token}`,
|
|
863
|
-
},
|
|
864
910
|
json: true,
|
|
865
911
|
});
|
|
866
912
|
// API returns { Success: true, Products: [...], TotalCount: ... }
|
|
@@ -928,18 +974,26 @@ class OptimaRestApi {
|
|
|
928
974
|
}
|
|
929
975
|
else if (resource === 'print') {
|
|
930
976
|
if (operation === 'printDocument') {
|
|
931
|
-
const filtrSQL = this.getNodeParameter('filtrSQL', i);
|
|
977
|
+
const filtrSQL = this.getNodeParameter('filtrSQL', i, '');
|
|
932
978
|
const formatId = this.getNodeParameter('formatId', i);
|
|
979
|
+
const dynamicParamsRaw = this.getNodeParameter('dynamicParameters', i, {});
|
|
933
980
|
const requestBody = {
|
|
934
981
|
FormatId: formatId,
|
|
935
|
-
FiltrSQL: filtrSQL,
|
|
936
982
|
};
|
|
937
|
-
|
|
983
|
+
if (filtrSQL) {
|
|
984
|
+
requestBody.FiltrSQL = filtrSQL;
|
|
985
|
+
}
|
|
986
|
+
if (dynamicParamsRaw.parameter) {
|
|
987
|
+
const params = dynamicParamsRaw.parameter;
|
|
988
|
+
const dynamicParameters = {};
|
|
989
|
+
for (const p of params) {
|
|
990
|
+
dynamicParameters[p.name] = p.value;
|
|
991
|
+
}
|
|
992
|
+
requestBody.DynamicParameters = dynamicParameters;
|
|
993
|
+
}
|
|
994
|
+
const response = await makeAuthenticatedRequest({
|
|
938
995
|
method: 'POST',
|
|
939
996
|
url: `${gatewayUrl}/api/Documents/Print`,
|
|
940
|
-
headers: {
|
|
941
|
-
Authorization: `Bearer ${token}`,
|
|
942
|
-
},
|
|
943
997
|
body: requestBody,
|
|
944
998
|
json: false,
|
|
945
999
|
encoding: null, // Get binary data (PDF file)
|