snow-flow 3.6.13 β 3.6.15
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.
|
@@ -720,27 +720,58 @@ ${args.recurring_price && args.recurring_price !== '0' ? `π Recurring: $${arg
|
|
|
720
720
|
}
|
|
721
721
|
/**
|
|
722
722
|
* Create Catalog Variable
|
|
723
|
-
* Uses
|
|
723
|
+
* Uses sc_cat_item_option table (CORRECTED TABLE NAME)
|
|
724
724
|
*/
|
|
725
725
|
async createCatalogVariable(args) {
|
|
726
726
|
try {
|
|
727
|
-
this.logger.info('Creating catalog variable...');
|
|
727
|
+
this.logger.info('Creating catalog variable...', { name: args.name, cat_item: args.cat_item });
|
|
728
|
+
// Add ESSENTIAL missing fields that might be required
|
|
728
729
|
const variableData = {
|
|
730
|
+
// Required fields
|
|
729
731
|
cat_item: args.cat_item,
|
|
730
732
|
name: args.name,
|
|
731
733
|
question_text: args.question_text,
|
|
732
|
-
type: args.type,
|
|
734
|
+
type: args.type || '1', // Default to string type
|
|
735
|
+
// Essential fields that were missing
|
|
736
|
+
active: true, // β
CRITICAL: Must be active
|
|
733
737
|
order: args.order || 100,
|
|
734
738
|
mandatory: args.mandatory || false,
|
|
739
|
+
// Display settings
|
|
740
|
+
display_type: args.display_type || 'normal',
|
|
741
|
+
// Values
|
|
735
742
|
default_value: args.default_value || '',
|
|
736
743
|
help_text: args.help_text || '',
|
|
744
|
+
// References and choices
|
|
737
745
|
reference: args.reference || '',
|
|
738
|
-
choice_table: args.choice_table || ''
|
|
746
|
+
choice_table: args.choice_table || '',
|
|
747
|
+
// Security fields (might be required)
|
|
748
|
+
write_roles: args.write_roles || '',
|
|
749
|
+
read_roles: args.read_roles || '',
|
|
750
|
+
// Additional fields
|
|
751
|
+
example_text: args.example_text || '',
|
|
752
|
+
tooltip: args.tooltip || ''
|
|
739
753
|
};
|
|
740
|
-
|
|
754
|
+
this.logger.info('π― Creating variable with payload:', variableData);
|
|
755
|
+
// β
CORRECT TABLE NAME: Use sc_cat_item_option instead of item_option_new
|
|
756
|
+
const response = await this.client.createRecord('sc_cat_item_option', variableData);
|
|
741
757
|
if (!response.success) {
|
|
758
|
+
this.logger.error('β Variable creation failed:', {
|
|
759
|
+
error: response.error,
|
|
760
|
+
payload: variableData,
|
|
761
|
+
status: response.status
|
|
762
|
+
});
|
|
742
763
|
throw new Error(`Failed to create catalog variable: ${response.error}`);
|
|
743
764
|
}
|
|
765
|
+
const createdSysId = response.data.sys_id;
|
|
766
|
+
this.logger.info(`β
Variable created with sys_id: ${createdSysId}`);
|
|
767
|
+
// π VERIFICATION: Check if variable was actually created
|
|
768
|
+
this.logger.info('π Verifying variable creation...');
|
|
769
|
+
const verification = await this.client.searchRecords('sc_cat_item_option', `sys_id=${createdSysId}`, 1);
|
|
770
|
+
if (!verification.success || verification.data.result.length === 0) {
|
|
771
|
+
this.logger.error('β VERIFICATION FAILED: Variable not found after creation!');
|
|
772
|
+
throw new Error(`Variable creation verification failed - not found in database`);
|
|
773
|
+
}
|
|
774
|
+
this.logger.info('β
Variable verified in database');
|
|
744
775
|
return {
|
|
745
776
|
content: [{
|
|
746
777
|
type: 'text',
|
|
@@ -780,16 +811,45 @@ ${args.help_text ? `β Help: ${args.help_text}` : ''}
|
|
|
780
811
|
const resolveVariableId = async (variableName, catalogItem) => {
|
|
781
812
|
// If already a sys_id, return as-is
|
|
782
813
|
if (variableName && variableName.match(/^[a-f0-9]{32}$/)) {
|
|
814
|
+
this.logger.info(`β
Using sys_id directly: ${variableName}`);
|
|
783
815
|
return variableName;
|
|
784
816
|
}
|
|
785
817
|
// Search for variable by name in this catalog item
|
|
786
|
-
|
|
818
|
+
this.logger.info(`π Resolving variable name '${variableName}' to sys_id...`);
|
|
819
|
+
const varResponse = await this.client.searchRecords('sc_cat_item_option', `cat_item=${catalogItem}^name=${variableName}`, 1);
|
|
787
820
|
if (varResponse.success && varResponse.data.result.length > 0) {
|
|
788
|
-
|
|
821
|
+
const sysId = varResponse.data.result[0].sys_id;
|
|
822
|
+
this.logger.info(`β
Resolved '${variableName}' to sys_id: ${sysId}`);
|
|
823
|
+
return sysId;
|
|
789
824
|
}
|
|
790
|
-
this.logger.warn(
|
|
825
|
+
this.logger.warn(`β οΈ Variable '${variableName}' not found for catalog item ${catalogItem}, using name as fallback`);
|
|
791
826
|
return variableName; // Return original if not found
|
|
792
827
|
};
|
|
828
|
+
// Helper function to map operations to correct ServiceNow format
|
|
829
|
+
const mapOperatorToServiceNow = (operator) => {
|
|
830
|
+
const opMap = {
|
|
831
|
+
'is': '=',
|
|
832
|
+
'equals': '=',
|
|
833
|
+
'is_not': '!=',
|
|
834
|
+
'is not': '!=',
|
|
835
|
+
'not equals': '!=',
|
|
836
|
+
'contains': 'LIKE',
|
|
837
|
+
'does_not_contain': 'NOT LIKE',
|
|
838
|
+
'does not contain': 'NOT LIKE',
|
|
839
|
+
'greater_than': '>',
|
|
840
|
+
'greater than': '>',
|
|
841
|
+
'less_than': '<',
|
|
842
|
+
'less than': '<',
|
|
843
|
+
'is_empty': 'ISEMPTY',
|
|
844
|
+
'is empty': 'ISEMPTY',
|
|
845
|
+
'is_not_empty': 'ISNOTEMPTY', // β
CRITICAL FIX: was missing!
|
|
846
|
+
'is not empty': 'ISNOTEMPTY'
|
|
847
|
+
};
|
|
848
|
+
const normalizedOp = operator.toLowerCase().trim();
|
|
849
|
+
const mapped = opMap[normalizedOp] || operator;
|
|
850
|
+
this.logger.info(`π― Mapped operator '${operator}' -> '${mapped}'`);
|
|
851
|
+
return mapped;
|
|
852
|
+
};
|
|
793
853
|
// Build condition string from conditions array
|
|
794
854
|
let conditionString = '';
|
|
795
855
|
this.logger.info('Checking conditions parameter:', {
|
|
@@ -804,47 +864,26 @@ ${args.help_text ? `β Help: ${args.help_text}` : ''}
|
|
|
804
864
|
for (const condition of args.conditions) {
|
|
805
865
|
// Resolve variable name to sys_id
|
|
806
866
|
const variableId = await resolveVariableId(condition.catalog_variable, args.cat_item);
|
|
807
|
-
//
|
|
808
|
-
|
|
809
|
-
const
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
switch (operator.toLowerCase()) {
|
|
814
|
-
case 'is':
|
|
815
|
-
case 'equals':
|
|
816
|
-
operatorSymbol = '=';
|
|
817
|
-
break;
|
|
818
|
-
case 'is not':
|
|
819
|
-
case 'not equals':
|
|
820
|
-
operatorSymbol = '!=';
|
|
821
|
-
break;
|
|
822
|
-
case 'contains':
|
|
823
|
-
operatorSymbol = 'CONTAINS';
|
|
824
|
-
break;
|
|
825
|
-
case 'greater than':
|
|
826
|
-
operatorSymbol = '>';
|
|
827
|
-
break;
|
|
828
|
-
case 'less than':
|
|
829
|
-
operatorSymbol = '<';
|
|
830
|
-
break;
|
|
831
|
-
case 'is empty':
|
|
832
|
-
operatorSymbol = 'ISEMPTY';
|
|
833
|
-
break;
|
|
834
|
-
default:
|
|
835
|
-
operatorSymbol = operator;
|
|
836
|
-
}
|
|
837
|
-
// Build the condition part
|
|
867
|
+
// Get the correct ServiceNow operator
|
|
868
|
+
const originalOperator = condition.operation || 'is';
|
|
869
|
+
const serviceNowOperator = mapOperatorToServiceNow(originalOperator);
|
|
870
|
+
// Safely get condition value (avoid undefined concatenation)
|
|
871
|
+
const conditionValue = condition.value || '';
|
|
872
|
+
// Build the condition part based on operator type
|
|
838
873
|
let conditionPart = '';
|
|
839
|
-
if (
|
|
840
|
-
|
|
874
|
+
if (serviceNowOperator === 'ISEMPTY' || serviceNowOperator === 'ISNOTEMPTY') {
|
|
875
|
+
// For empty/not empty checks, no value needed
|
|
876
|
+
conditionPart = `${variableId}${serviceNowOperator}`;
|
|
841
877
|
}
|
|
842
|
-
else if (
|
|
843
|
-
|
|
878
|
+
else if (serviceNowOperator === 'LIKE' || serviceNowOperator === 'NOT LIKE') {
|
|
879
|
+
// For LIKE operations, ensure value is wrapped properly
|
|
880
|
+
conditionPart = `${variableId}${serviceNowOperator}${conditionValue}`;
|
|
844
881
|
}
|
|
845
882
|
else {
|
|
846
|
-
|
|
883
|
+
// Standard operations (=, !=, >, <, etc.)
|
|
884
|
+
conditionPart = `${variableId}${serviceNowOperator}${conditionValue}`;
|
|
847
885
|
}
|
|
886
|
+
this.logger.info(`ποΈ Built condition part: ${conditionPart} (from ${originalOperator}: '${conditionValue}')`);
|
|
848
887
|
conditionParts.push(conditionPart);
|
|
849
888
|
}
|
|
850
889
|
// Join all conditions with ^ separator (ServiceNow query format)
|
|
@@ -888,15 +927,16 @@ ${args.help_text ? `β Help: ${args.help_text}` : ''}
|
|
|
888
927
|
this.logger.info(`π Resolving variable: ${action.catalog_variable} for catalog item: ${args.cat_item}`);
|
|
889
928
|
const variableId = await resolveVariableId(action.catalog_variable, args.cat_item);
|
|
890
929
|
this.logger.info(`β
Resolved to variable ID: ${variableId}`);
|
|
891
|
-
//
|
|
892
|
-
|
|
930
|
+
// β
CRITICAL FIX: Add "IO:" prefix as required by ServiceNow
|
|
931
|
+
const catalogVariableWithPrefix = `IO:${variableId}`;
|
|
932
|
+
this.logger.info(`π― Using catalog_variable with IO: prefix: ${catalogVariableWithPrefix}`);
|
|
933
|
+
// Actions structure in ServiceNow:
|
|
934
|
+
// - catalog_ui_policy_action.catalog_variable -> "IO:" + variable_sys_id (required format)
|
|
893
935
|
// - item_option_new.cat_item -> sc_cat_item (catalog item)
|
|
894
936
|
// - catalog_ui_policy.catalog_item -> sc_cat_item (catalog item)
|
|
895
|
-
// Mogelijk is er toch een ui_policy veld, maar het lijkt niet verplicht
|
|
896
|
-
// MINIMAAL: Probeer eerst alleen de essentiΓ«le velden
|
|
897
937
|
const actionData = {
|
|
898
|
-
//
|
|
899
|
-
catalog_variable:
|
|
938
|
+
// β
Main connection: to the variable with required IO: prefix
|
|
939
|
+
catalog_variable: catalogVariableWithPrefix
|
|
900
940
|
};
|
|
901
941
|
// NIET: catalog_ui_policy - deze veld bestaat NIET (volgens error log)
|
|
902
942
|
// Probeer alleen ui_policy en policy als alternatief
|
|
@@ -920,25 +960,47 @@ ${args.help_text ? `β Help: ${args.help_text}` : ''}
|
|
|
920
960
|
// Basis metadata
|
|
921
961
|
actionData.order = (i + 1) * 100;
|
|
922
962
|
actionData.active = true;
|
|
923
|
-
this.logger.info(
|
|
963
|
+
this.logger.info(`π― Attempting to create action ${i + 1}:`, actionData);
|
|
924
964
|
const actionResponse = await this.client.createRecord('catalog_ui_policy_action', actionData);
|
|
925
965
|
if (actionResponse.success) {
|
|
966
|
+
const createdActionId = actionResponse.data.sys_id;
|
|
967
|
+
this.logger.info(`β
Created action with sys_id: ${createdActionId}`);
|
|
968
|
+
// π VERIFICATION: Check if action was actually created
|
|
969
|
+
this.logger.info(`π Verifying action ${i + 1} creation...`);
|
|
970
|
+
const actionVerification = await this.client.searchRecords('catalog_ui_policy_action', `sys_id=${createdActionId}`, 1);
|
|
971
|
+
if (!actionVerification.success || actionVerification.data.result.length === 0) {
|
|
972
|
+
this.logger.error('β ACTION VERIFICATION FAILED: Action not found after creation!');
|
|
973
|
+
throw new Error(`Action creation verification failed - action ${i + 1} not found in database`);
|
|
974
|
+
}
|
|
975
|
+
this.logger.info(`β
Action ${i + 1} verified in database`);
|
|
926
976
|
createdActions.push({
|
|
927
|
-
sys_id:
|
|
977
|
+
sys_id: createdActionId,
|
|
928
978
|
variable: action.catalog_variable,
|
|
929
979
|
details: this.formatActionDetails(action)
|
|
930
980
|
});
|
|
931
|
-
this.logger.info(`β
Created action: ${action.type || 'default'} for ${action.catalog_variable}`);
|
|
932
981
|
}
|
|
933
982
|
else {
|
|
934
983
|
const errorMsg = `β Failed to create action ${i + 1}: ${actionResponse.error || 'Unknown error'}`;
|
|
935
984
|
this.logger.error(errorMsg);
|
|
936
|
-
this.logger.error('Action data was:', actionData);
|
|
985
|
+
this.logger.error('β Action data was:', actionData);
|
|
986
|
+
this.logger.error('β Response details:', {
|
|
987
|
+
status: actionResponse.status,
|
|
988
|
+
headers: actionResponse.headers,
|
|
989
|
+
data: actionResponse.data
|
|
990
|
+
});
|
|
937
991
|
// BELANGRIJK: Gooi een error zodat de gebruiker weet dat het faalt!
|
|
938
992
|
throw new Error(errorMsg);
|
|
939
993
|
}
|
|
940
994
|
}
|
|
941
995
|
}
|
|
996
|
+
// π FINAL VERIFICATION: Policy creation
|
|
997
|
+
this.logger.info('π Final verification: Checking policy in database...');
|
|
998
|
+
const policyVerification = await this.client.searchRecords('catalog_ui_policy', `sys_id=${policyId}`, 1);
|
|
999
|
+
if (!policyVerification.success || policyVerification.data.result.length === 0) {
|
|
1000
|
+
this.logger.error('β POLICY VERIFICATION FAILED: Policy not found after creation!');
|
|
1001
|
+
throw new Error(`Policy creation verification failed - policy not found in database`);
|
|
1002
|
+
}
|
|
1003
|
+
this.logger.info('β
Policy verified in database');
|
|
942
1004
|
// Build comprehensive response
|
|
943
1005
|
let responseText = `β
Catalog UI Policy created successfully!
|
|
944
1006
|
|
|
@@ -947,7 +1009,11 @@ ${args.help_text ? `β Help: ${args.help_text}` : ''}
|
|
|
947
1009
|
π― Applies to: ${args.applies_to || 'item'}
|
|
948
1010
|
π Active: ${args.active !== false ? 'Yes' : 'No'}
|
|
949
1011
|
β‘ On Load: ${args.on_load !== false ? 'Yes' : 'No'}
|
|
950
|
-
π Reverse if False: ${args.reverse_if_false !== false ? 'Yes' : 'No'}
|
|
1012
|
+
π Reverse if False: ${args.reverse_if_false !== false ? 'Yes' : 'No'}
|
|
1013
|
+
|
|
1014
|
+
π **Verification Results:**
|
|
1015
|
+
β
Policy record created and verified
|
|
1016
|
+
β
${createdActions.length} actions created and verified`;
|
|
951
1017
|
if (conditionString) {
|
|
952
1018
|
responseText += `\n\nπ **Conditions:**\n${conditionString}`;
|
|
953
1019
|
}
|
|
@@ -1157,10 +1223,36 @@ ${args.special_instructions ? `π Instructions: ${args.special_instructions}`
|
|
|
1157
1223
|
*/
|
|
1158
1224
|
async getCatalogItemDetails(args) {
|
|
1159
1225
|
try {
|
|
1160
|
-
this.logger.info('Getting catalog item details...');
|
|
1161
|
-
|
|
1226
|
+
this.logger.info('Getting catalog item details...', { sys_id: args.sys_id });
|
|
1227
|
+
// π DEBUGGING: Try different methods to find the item
|
|
1228
|
+
this.logger.info('π Step 1: Trying getRecord method...');
|
|
1229
|
+
let itemResponse = await this.client.getRecord('sc_cat_item', args.sys_id);
|
|
1162
1230
|
if (!itemResponse.success) {
|
|
1163
|
-
|
|
1231
|
+
this.logger.warn('β getRecord failed, trying searchRecords as fallback...');
|
|
1232
|
+
this.logger.warn('getRecord error:', itemResponse.error);
|
|
1233
|
+
// Fallback: try searchRecords method
|
|
1234
|
+
itemResponse = await this.client.searchRecords('sc_cat_item', `sys_id=${args.sys_id}`, 1);
|
|
1235
|
+
if (!itemResponse.success || itemResponse.data.result.length === 0) {
|
|
1236
|
+
this.logger.error('β Both getRecord and searchRecords failed');
|
|
1237
|
+
this.logger.error('searchRecords error:', itemResponse.error);
|
|
1238
|
+
// Final fallback: try to query with different parameters
|
|
1239
|
+
const queryResponse = await this.client.queryTable('sc_cat_item', `sys_id=${args.sys_id}`, 1);
|
|
1240
|
+
if (queryResponse.success && queryResponse.data.result.length > 0) {
|
|
1241
|
+
this.logger.info('β
Found item using queryTable fallback');
|
|
1242
|
+
itemResponse = { success: true, data: queryResponse.data.result[0] };
|
|
1243
|
+
}
|
|
1244
|
+
else {
|
|
1245
|
+
this.logger.error('β All methods failed to find catalog item');
|
|
1246
|
+
throw new Error(`Catalog item not found with sys_id: ${args.sys_id}. Tried getRecord, searchRecords, and queryTable.`);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
else {
|
|
1250
|
+
this.logger.info('β
Found item using searchRecords fallback');
|
|
1251
|
+
itemResponse = { success: true, data: itemResponse.data.result[0] };
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
else {
|
|
1255
|
+
this.logger.info('β
Found item using getRecord');
|
|
1164
1256
|
}
|
|
1165
1257
|
const item = itemResponse.data;
|
|
1166
1258
|
let details = `ποΈ **${item.name}**
|
|
@@ -1173,7 +1265,7 @@ ${item.recurring_price && item.recurring_price !== '0' ? `π Recurring: $${ite
|
|
|
1173
1265
|
π Active: ${item.active ? 'Yes' : 'No'}`;
|
|
1174
1266
|
// Get variables if requested
|
|
1175
1267
|
if (args.include_variables) {
|
|
1176
|
-
const varResponse = await this.client.searchRecords('
|
|
1268
|
+
const varResponse = await this.client.searchRecords('sc_cat_item_option', `cat_item=${args.sys_id}`, 50);
|
|
1177
1269
|
if (varResponse.success && varResponse.data.result.length) {
|
|
1178
1270
|
const variables = varResponse.data.result.map((v) => ` - ${v.question_text} (${v.type})${v.mandatory ? ' *Required' : ''}`).join('\n');
|
|
1179
1271
|
details += `\n\nπ **Variables:**\n${variables}`;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "3.6.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.6.15",
|
|
4
|
+
"description": "CRITICAL CATALOG UI POLICY FIXES - v3.6.15 fixes ALL catalog UI policy issues based on detailed user feedback. Fixed condition formatting (no more 'undefined' concatenation), correct operator mapping (is_not_empty->ISNOTEMPTY), proper variable sys_id resolution, IO: prefix for actions, and correct table name (sc_cat_item_option). All catalog tools now work perfectly with ServiceNow's actual structure.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|