Scripting

Integration Patterns

This guide covers common patterns for integrating Licentra into different types of SuiteScripts and various use cases.

See More: Licentra Wiki – Modules


Script Type Patterns

User Event Scripts

User Event scripts are ideal for controlling feature access at the record level.

Pattern: Conditional UI Elements

Code
/** * @NApiVersion 2.1 * @NScriptType UserEventScript * @NModuleScope SameAccount */ define( ['/SuiteBundles/Bundle 571165/licentra_lib'], (licentraLib) => { const beforeLoad = (context) => { const featureId = 'ADVANCED_VALIDATION'; try { const status = licentraLib.isFeatureEnabled(featureId); if (status.enabled) { // Add advanced validation button context.form.addButton({ id: 'custpage_advanced_validate', label: 'Advanced Validation', functionName: 'performAdvancedValidation' }); } else { // Add informational message context.form.addField({ id: 'custpage_upgrade_message', type: 'inlinehtml', label: 'Upgrade Available' }).setDefaultValue( `<div style="color: blue;">Upgrade to access advanced validation features</div>` ); } } catch (error) { log.error('Feature Check Error', error.message); } }; return { beforeLoad }; } );

Pattern: Conditional Field Display

Code
const beforeLoad = (context) => { const featureId = 'CUSTOM_FIELDS'; try { const status = licentraLib.isFeatureEnabled(featureId); if (!status.enabled) { // Hide custom fields when feature is disabled const customFields = [ 'custbody_custom_field_1', 'custbody_custom_field_2', 'custbody_custom_field_3' ]; customFields.forEach(fieldId => { const field = context.form.getField(fieldId); if (field) { field.setDisplayType('hidden'); } }); } } catch (error) { log.error('Field Display Error', error.message); } };

Client Scripts

Client Scripts are perfect for controlling UI behavior and user interactions.

Pattern: Dynamic Button States

Code
/** * @NApiVersion 2.1 * @NScriptType ClientScript * @NModuleScope SameAccount */ define( ['/SuiteBundles/Bundle 571165/licentra_lib'], (licentraLib) => { const pageInit = (context) => { const featureId = 'BULK_OPERATIONS'; try { const status = licentraLib.isFeatureEnabled(featureId); if (!status.enabled) { // Disable bulk operation buttons const bulkButtons = [ 'custpage_bulk_edit_btn', 'custpage_bulk_delete_btn', 'custpage_bulk_export_btn' ]; bulkButtons.forEach(buttonId => { const button = document.getElementById(buttonId); if (button) { button.disabled = true; button.title = `Feature not available: ${status.message}`; } }); } } catch (error) { console.error('Client Script Error:', error); } }; return { pageInit }; } );

Pattern: Feature Toggle with User Feedback

Code
const pageInit = (context) => { const featureId = 'REAL_TIME_SYNC'; try { const status = licentraLib.isFeatureEnabled(featureId); if (status.enabled) { // Enable real-time sync functionality enableRealTimeSync(); } else { // Show upgrade prompt showUpgradePrompt(status.message); } } catch (error) { console.error('Sync Feature Error:', error); // Fallback to manual sync enableManualSync(); } }; function showUpgradePrompt(message) { const prompt = document.createElement('div'); prompt.innerHTML = ` <div style="background: #fff3cd; border: 1px solid #ffeaa7; padding: 10px; margin: 10px 0; border-radius: 4px;"> <strong>Upgrade Available:</strong> ${message} <button onclick="upgradeFeature()" style="margin-left: 10px; padding: 5px 10px;">Upgrade Now</button> </div> `; document.body.insertBefore(prompt, document.body.firstChild); }

Suitelets

Suitelets are server-side scripts that can control access to custom pages and functionality.

Pattern: Access Control

Code
/** * @NApiVersion 2.1 * @NScriptType SuiteletScript * @NModuleScope SameAccount */ define( ['/SuiteBundles/Bundle 571165/licentra_lib'], (licentraLib) => { const onRequest = (context) => { const featureId = 'ADMIN_DASHBOARD'; try { const status = licentraLib.isFeatureEnabled(featureId); if (!status.enabled) { // Return access denied page context.response.write(` <html> <head><title>Access Denied</title></head> <body> <h1>Access Denied</h1> <p>This feature is not available: ${status.message}</p> <p><a href="/app/center/card.nl?sc=-29&whence=">Return to Dashboard</a></p> </body> </html> `); return; } // Render the admin dashboard renderAdminDashboard(context); } catch (error) { log.error('Suitelet Access Error', error.message); context.response.write('An error occurred while checking access permissions'); } }; return { onRequest }; } );

Pattern: Feature-Based Content

Code
const onRequest = (context) => { const features = { 'BASIC_REPORTS': false, 'ADVANCED_REPORTS': false, 'EXPORT_FEATURES': false }; try { // Check multiple features Object.keys(features).forEach(featureId => { const status = licentraLib.isFeatureEnabled(featureId); features[featureId] = status.enabled; }); // Render content based on available features renderFeatureBasedContent(context, features); } catch (error) { log.error('Feature Check Error', error.message); // Render basic content as fallback renderBasicContent(context); } };

Scheduled Scripts

Scheduled Scripts can use Licentra to control batch operations and automated processes.

Pattern: Conditional Processing

Code
/** * @NApiVersion 2.1 * @NScriptType ScheduledScript * @NModuleScope SameAccount */ define( ['/SuiteBundles/Bundle 571165/licentra_lib'], (licentraLib) => { const execute = (context) => { const featureId = 'AUTOMATED_CLEANUP'; try { const status = licentraLib.isFeatureEnabled(featureId); if (status.enabled) { // Perform automated cleanup performAutomatedCleanup(); log.audit('Cleanup Completed', 'Automated cleanup process completed successfully'); } else { log.audit('Cleanup Skipped', `Automated cleanup skipped: ${status.message}`); } } catch (error) { log.error('Scheduled Script Error', error.message); } }; return { execute }; } );

Use Case Patterns

Graceful Degradation

Provide alternative functionality when features are disabled.

Code
function handleFeatureWithFallback(featureId, premiumFunction, fallbackFunction) { try { const status = licentraLib.isFeatureEnabled(featureId); if (status.enabled) { premiumFunction(); } else { log.debug('Using Fallback', `Feature ${featureId} disabled, using fallback`); fallbackFunction(); } } catch (error) { log.error('Feature Error', error.message); fallbackFunction(); } } // Usage handleFeatureWithFallback( 'ADVANCED_SEARCH', () => performAdvancedSearch(), () => performBasicSearch() );

User Experience Enhancement

Provide clear feedback and upgrade paths to users.

Code
function enhanceUserExperience(featureId, elementId) { try { const status = licentraLib.isFeatureEnabled(featureId); if (!status.enabled) { const element = document.getElementById(elementId); if (element) { element.innerHTML = ` <div style="text-align: center; padding: 20px; background: #f8f9fa; border-radius: 8px;"> <h3>Upgrade Available</h3> <p>${status.message}</p> <button onclick="showUpgradeOptions()" class="btn btn-primary"> Learn More </button> </div> `; } } } catch (error) { console.error('UX Enhancement Error:', error); } }

Error Handling Patterns

Robust Error Handling

Code
function safeFeatureCheck(featureId, defaultValue = false) { try { const status = licentraLib.isFeatureEnabled(featureId); return status.enabled; } catch (error) { log.error('Feature Check Failed', { featureId: featureId, error: error.message, stack: error.stack }); return defaultValue; } } // Usage with fallback const isFeatureEnabled = safeFeatureCheck('MY_FEATURE', false);

Retry Pattern

Code
function checkFeatureWithRetry(featureId, maxRetries = 3) { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { const status = licentraLib.isFeatureEnabled(featureId); return status.enabled; } catch (error) { log.warning('Feature Check Attempt Failed', { attempt: attempt, featureId: featureId, error: error.message }); if (attempt === maxRetries) { log.error('Feature Check Failed After Retries', { featureId: featureId, maxRetries: maxRetries }); return false; } // Wait before retry (exponential backoff) const delay = Math.pow(2, attempt) * 1000; setTimeout(() => {}, delay); } } }

These patterns provide a solid foundation for integrating Licentra into your NetSuite solutions while ensuring robust error handling and excellent user experience.

Last modified on