snow-flow 3.6.14 β 3.6.16
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,7 +720,7 @@ ${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 {
|
|
@@ -752,7 +752,8 @@ ${args.recurring_price && args.recurring_price !== '0' ? `π Recurring: $${arg
|
|
|
752
752
|
tooltip: args.tooltip || ''
|
|
753
753
|
};
|
|
754
754
|
this.logger.info('π― Creating variable with payload:', variableData);
|
|
755
|
-
|
|
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);
|
|
756
757
|
if (!response.success) {
|
|
757
758
|
this.logger.error('β Variable creation failed:', {
|
|
758
759
|
error: response.error,
|
|
@@ -765,7 +766,7 @@ ${args.recurring_price && args.recurring_price !== '0' ? `π Recurring: $${arg
|
|
|
765
766
|
this.logger.info(`β
Variable created with sys_id: ${createdSysId}`);
|
|
766
767
|
// π VERIFICATION: Check if variable was actually created
|
|
767
768
|
this.logger.info('π Verifying variable creation...');
|
|
768
|
-
const verification = await this.client.searchRecords('
|
|
769
|
+
const verification = await this.client.searchRecords('sc_cat_item_option', `sys_id=${createdSysId}`, 1);
|
|
769
770
|
if (!verification.success || verification.data.result.length === 0) {
|
|
770
771
|
this.logger.error('β VERIFICATION FAILED: Variable not found after creation!');
|
|
771
772
|
throw new Error(`Variable creation verification failed - not found in database`);
|
|
@@ -806,19 +807,127 @@ ${args.help_text ? `β Help: ${args.help_text}` : ''}
|
|
|
806
807
|
async createCatalogUIPolicy(args) {
|
|
807
808
|
try {
|
|
808
809
|
this.logger.info('Creating comprehensive catalog UI policy...');
|
|
809
|
-
//
|
|
810
|
+
// First, let's fetch ALL variables for this catalog item for debugging
|
|
811
|
+
this.logger.info(`π Fetching all variables for catalog item ${args.cat_item} for debugging...`);
|
|
812
|
+
try {
|
|
813
|
+
const allVarsResponse = await this.client.searchRecords('sc_cat_item_option', `cat_item=${args.cat_item}`, 100);
|
|
814
|
+
if (allVarsResponse.success && allVarsResponse.data.result.length > 0) {
|
|
815
|
+
this.logger.info(`π Found ${allVarsResponse.data.result.length} variables for this catalog item:`);
|
|
816
|
+
allVarsResponse.data.result.forEach((v) => {
|
|
817
|
+
this.logger.info(` - Variable: name='${v.name}', sys_id='${v.sys_id}', question='${v.question_text}'`);
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
this.logger.warn(`β οΈ No variables found for catalog item ${args.cat_item} - this might be a problem!`);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
catch (error) {
|
|
825
|
+
this.logger.error(`β Failed to fetch variables for debugging:`, error);
|
|
826
|
+
}
|
|
827
|
+
// Helper function to resolve variable names to sys_ids with MULTIPLE FALLBACKS
|
|
810
828
|
const resolveVariableId = async (variableName, catalogItem) => {
|
|
811
829
|
// If already a sys_id, return as-is
|
|
812
830
|
if (variableName && variableName.match(/^[a-f0-9]{32}$/)) {
|
|
831
|
+
this.logger.info(`β
Using sys_id directly: ${variableName}`);
|
|
813
832
|
return variableName;
|
|
814
833
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
834
|
+
this.logger.info(`π Resolving variable name '${variableName}' to sys_id for catalog item ${catalogItem}...`);
|
|
835
|
+
// Try multiple search strategies for maximum compatibility
|
|
836
|
+
const searchStrategies = [
|
|
837
|
+
// Strategy 1: Search by name field
|
|
838
|
+
{
|
|
839
|
+
query: `cat_item=${catalogItem}^name=${variableName}`,
|
|
840
|
+
description: 'by name field'
|
|
841
|
+
},
|
|
842
|
+
// Strategy 2: Search by name with LIKE operator
|
|
843
|
+
{
|
|
844
|
+
query: `cat_item=${catalogItem}^nameLIKE${variableName}`,
|
|
845
|
+
description: 'by name with LIKE'
|
|
846
|
+
},
|
|
847
|
+
// Strategy 3: Search by question_text
|
|
848
|
+
{
|
|
849
|
+
query: `cat_item=${catalogItem}^question_text=${variableName}`,
|
|
850
|
+
description: 'by question_text field'
|
|
851
|
+
},
|
|
852
|
+
// Strategy 4: Search all variables for this item and match manually
|
|
853
|
+
{
|
|
854
|
+
query: `cat_item=${catalogItem}`,
|
|
855
|
+
description: 'all variables for manual matching'
|
|
856
|
+
}
|
|
857
|
+
];
|
|
858
|
+
for (const strategy of searchStrategies) {
|
|
859
|
+
this.logger.info(`π Trying strategy: ${strategy.description}`);
|
|
860
|
+
try {
|
|
861
|
+
const varResponse = await this.client.searchRecords('sc_cat_item_option', strategy.query, 50 // Get more results for manual matching
|
|
862
|
+
);
|
|
863
|
+
if (varResponse.success && varResponse.data.result.length > 0) {
|
|
864
|
+
// For the "all variables" strategy, try to match manually
|
|
865
|
+
if (strategy.description === 'all variables for manual matching') {
|
|
866
|
+
const match = varResponse.data.result.find((v) => v.name === variableName ||
|
|
867
|
+
v.question_text === variableName ||
|
|
868
|
+
v.name?.toLowerCase() === variableName.toLowerCase());
|
|
869
|
+
if (match) {
|
|
870
|
+
this.logger.info(`β
Found variable through manual matching: ${match.sys_id}`);
|
|
871
|
+
return match.sys_id;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
else {
|
|
875
|
+
// Direct match found
|
|
876
|
+
const sysId = varResponse.data.result[0].sys_id;
|
|
877
|
+
this.logger.info(`β
Resolved '${variableName}' to sys_id: ${sysId} (${strategy.description})`);
|
|
878
|
+
return sysId;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
catch (error) {
|
|
883
|
+
this.logger.warn(`β οΈ Strategy failed: ${strategy.description}`, error);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
// If all strategies fail, try alternate table names (just in case)
|
|
887
|
+
const alternateTables = ['item_option_new', 'io_set_item_option'];
|
|
888
|
+
for (const table of alternateTables) {
|
|
889
|
+
this.logger.info(`π Trying alternate table: ${table}`);
|
|
890
|
+
try {
|
|
891
|
+
const varResponse = await this.client.searchRecords(table, `cat_item=${catalogItem}^name=${variableName}`, 1);
|
|
892
|
+
if (varResponse.success && varResponse.data.result.length > 0) {
|
|
893
|
+
const sysId = varResponse.data.result[0].sys_id;
|
|
894
|
+
this.logger.info(`β
Found in alternate table ${table}: ${sysId}`);
|
|
895
|
+
return sysId;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
catch (error) {
|
|
899
|
+
this.logger.warn(`β οΈ Alternate table ${table} failed:`, error);
|
|
900
|
+
}
|
|
819
901
|
}
|
|
820
|
-
this.logger.
|
|
821
|
-
|
|
902
|
+
this.logger.error(`β CRITICAL: Variable '${variableName}' not found in any table for catalog item ${catalogItem}`);
|
|
903
|
+
this.logger.error(`β This will cause the action to fail! Please use the sys_id directly instead of the name.`);
|
|
904
|
+
// Return the name but log a warning that this will fail
|
|
905
|
+
return variableName;
|
|
906
|
+
};
|
|
907
|
+
// Helper function to map operations to correct ServiceNow format
|
|
908
|
+
const mapOperatorToServiceNow = (operator) => {
|
|
909
|
+
const opMap = {
|
|
910
|
+
'is': '=',
|
|
911
|
+
'equals': '=',
|
|
912
|
+
'is_not': '!=',
|
|
913
|
+
'is not': '!=',
|
|
914
|
+
'not equals': '!=',
|
|
915
|
+
'contains': 'LIKE',
|
|
916
|
+
'does_not_contain': 'NOT LIKE',
|
|
917
|
+
'does not contain': 'NOT LIKE',
|
|
918
|
+
'greater_than': '>',
|
|
919
|
+
'greater than': '>',
|
|
920
|
+
'less_than': '<',
|
|
921
|
+
'less than': '<',
|
|
922
|
+
'is_empty': 'ISEMPTY',
|
|
923
|
+
'is empty': 'ISEMPTY',
|
|
924
|
+
'is_not_empty': 'ISNOTEMPTY', // β
CRITICAL FIX: was missing!
|
|
925
|
+
'is not empty': 'ISNOTEMPTY'
|
|
926
|
+
};
|
|
927
|
+
const normalizedOp = operator.toLowerCase().trim();
|
|
928
|
+
const mapped = opMap[normalizedOp] || operator;
|
|
929
|
+
this.logger.info(`π― Mapped operator '${operator}' -> '${mapped}'`);
|
|
930
|
+
return mapped;
|
|
822
931
|
};
|
|
823
932
|
// Build condition string from conditions array
|
|
824
933
|
let conditionString = '';
|
|
@@ -834,47 +943,26 @@ ${args.help_text ? `β Help: ${args.help_text}` : ''}
|
|
|
834
943
|
for (const condition of args.conditions) {
|
|
835
944
|
// Resolve variable name to sys_id
|
|
836
945
|
const variableId = await resolveVariableId(condition.catalog_variable, args.cat_item);
|
|
837
|
-
//
|
|
838
|
-
|
|
839
|
-
const
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
switch (operator.toLowerCase()) {
|
|
844
|
-
case 'is':
|
|
845
|
-
case 'equals':
|
|
846
|
-
operatorSymbol = '=';
|
|
847
|
-
break;
|
|
848
|
-
case 'is not':
|
|
849
|
-
case 'not equals':
|
|
850
|
-
operatorSymbol = '!=';
|
|
851
|
-
break;
|
|
852
|
-
case 'contains':
|
|
853
|
-
operatorSymbol = 'CONTAINS';
|
|
854
|
-
break;
|
|
855
|
-
case 'greater than':
|
|
856
|
-
operatorSymbol = '>';
|
|
857
|
-
break;
|
|
858
|
-
case 'less than':
|
|
859
|
-
operatorSymbol = '<';
|
|
860
|
-
break;
|
|
861
|
-
case 'is empty':
|
|
862
|
-
operatorSymbol = 'ISEMPTY';
|
|
863
|
-
break;
|
|
864
|
-
default:
|
|
865
|
-
operatorSymbol = operator;
|
|
866
|
-
}
|
|
867
|
-
// Build the condition part
|
|
946
|
+
// Get the correct ServiceNow operator
|
|
947
|
+
const originalOperator = condition.operation || 'is';
|
|
948
|
+
const serviceNowOperator = mapOperatorToServiceNow(originalOperator);
|
|
949
|
+
// Safely get condition value (avoid undefined concatenation)
|
|
950
|
+
const conditionValue = condition.value || '';
|
|
951
|
+
// Build the condition part based on operator type
|
|
868
952
|
let conditionPart = '';
|
|
869
|
-
if (
|
|
870
|
-
|
|
953
|
+
if (serviceNowOperator === 'ISEMPTY' || serviceNowOperator === 'ISNOTEMPTY') {
|
|
954
|
+
// For empty/not empty checks, no value needed
|
|
955
|
+
conditionPart = `${variableId}${serviceNowOperator}`;
|
|
871
956
|
}
|
|
872
|
-
else if (
|
|
873
|
-
|
|
957
|
+
else if (serviceNowOperator === 'LIKE' || serviceNowOperator === 'NOT LIKE') {
|
|
958
|
+
// For LIKE operations, ensure value is wrapped properly
|
|
959
|
+
conditionPart = `${variableId}${serviceNowOperator}${conditionValue}`;
|
|
874
960
|
}
|
|
875
961
|
else {
|
|
876
|
-
|
|
962
|
+
// Standard operations (=, !=, >, <, etc.)
|
|
963
|
+
conditionPart = `${variableId}${serviceNowOperator}${conditionValue}`;
|
|
877
964
|
}
|
|
965
|
+
this.logger.info(`ποΈ Built condition part: ${conditionPart} (from ${originalOperator}: '${conditionValue}')`);
|
|
878
966
|
conditionParts.push(conditionPart);
|
|
879
967
|
}
|
|
880
968
|
// Join all conditions with ^ separator (ServiceNow query format)
|
|
@@ -917,16 +1005,26 @@ ${args.help_text ? `β Help: ${args.help_text}` : ''}
|
|
|
917
1005
|
// Resolve variable name to sys_id
|
|
918
1006
|
this.logger.info(`π Resolving variable: ${action.catalog_variable} for catalog item: ${args.cat_item}`);
|
|
919
1007
|
const variableId = await resolveVariableId(action.catalog_variable, args.cat_item);
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1008
|
+
// Check if resolution actually worked (should be a sys_id now)
|
|
1009
|
+
const isValidSysId = variableId && variableId.match(/^[a-f0-9]{32}$/);
|
|
1010
|
+
if (!isValidSysId) {
|
|
1011
|
+
this.logger.error(`β CRITICAL: Failed to resolve variable '${action.catalog_variable}' to sys_id!`);
|
|
1012
|
+
this.logger.error(`β Got: ${variableId} (this is not a valid sys_id)`);
|
|
1013
|
+
// Continue anyway but it will likely fail
|
|
1014
|
+
}
|
|
1015
|
+
else {
|
|
1016
|
+
this.logger.info(`β
Resolved to variable sys_id: ${variableId}`);
|
|
1017
|
+
}
|
|
1018
|
+
// β
CRITICAL FIX: Add "IO:" prefix as required by ServiceNow
|
|
1019
|
+
// BUT ONLY if we have a valid sys_id!
|
|
1020
|
+
const catalogVariableWithPrefix = isValidSysId ? `IO:${variableId}` : variableId;
|
|
1021
|
+
this.logger.info(`π― Using catalog_variable value: ${catalogVariableWithPrefix}`);
|
|
1022
|
+
// Actions structure in ServiceNow:
|
|
1023
|
+
// - catalog_ui_policy_action.catalog_variable -> "IO:" + variable_sys_id (required format)
|
|
1024
|
+
// - catalog_ui_policy_action.ui_policy -> catalog_ui_policy.sys_id
|
|
927
1025
|
const actionData = {
|
|
928
|
-
//
|
|
929
|
-
catalog_variable:
|
|
1026
|
+
// β
Main connection: to the variable with required IO: prefix (if valid sys_id)
|
|
1027
|
+
catalog_variable: catalogVariableWithPrefix
|
|
930
1028
|
};
|
|
931
1029
|
// NIET: catalog_ui_policy - deze veld bestaat NIET (volgens error log)
|
|
932
1030
|
// Probeer alleen ui_policy en policy als alternatief
|
|
@@ -1255,7 +1353,7 @@ ${item.recurring_price && item.recurring_price !== '0' ? `π Recurring: $${ite
|
|
|
1255
1353
|
π Active: ${item.active ? 'Yes' : 'No'}`;
|
|
1256
1354
|
// Get variables if requested
|
|
1257
1355
|
if (args.include_variables) {
|
|
1258
|
-
const varResponse = await this.client.searchRecords('
|
|
1356
|
+
const varResponse = await this.client.searchRecords('sc_cat_item_option', `cat_item=${args.sys_id}`, 50);
|
|
1259
1357
|
if (varResponse.success && varResponse.data.result.length) {
|
|
1260
1358
|
const variables = varResponse.data.result.map((v) => ` - ${v.question_text} (${v.type})${v.mandatory ? ' *Required' : ''}`).join('\n');
|
|
1261
1359
|
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.16",
|
|
4
|
+
"description": "ENHANCED VARIABLE RESOLUTION - v3.6.16 adds comprehensive multi-strategy variable resolution with 4 different search methods, automatic debugging that shows all available variables, better error handling when resolution fails, and support for alternate table names. Now properly handles cases where variable names can't be resolved to sys_ids and provides clear warnings.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|