#
tokens: 45650/50000 11/825 files (page 21/61)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 21 of 61. Use http://codebase.md/taurgis/sfcc-dev-mcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .DS_Store
├── .github
│   ├── dependabot.yml
│   ├── instructions
│   │   ├── mcp-node-tests.instructions.md
│   │   └── mcp-yml-tests.instructions.md
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   ├── documentation.yml
│   │   ├── feature_request.yml
│   │   └── question.yml
│   ├── PULL_REQUEST_TEMPLATE
│   │   ├── bug_fix.md
│   │   ├── documentation.md
│   │   └── new_tool.md
│   ├── pull_request_template.md
│   └── workflows
│       ├── ci.yml
│       ├── deploy-pages.yml
│       ├── publish.yml
│       └── update-docs.yml
├── .gitignore
├── .husky
│   └── pre-commit
├── aegis.config.docs-only.json
├── aegis.config.json
├── aegis.config.with-dw.json
├── AGENTS.md
├── ai-instructions
│   ├── claude-desktop
│   │   └── claude_custom_instructions.md
│   ├── cursor
│   │   └── .cursor
│   │       └── rules
│   │           ├── debugging-workflows.mdc
│   │           ├── hooks-development.mdc
│   │           ├── isml-templates.mdc
│   │           ├── job-framework.mdc
│   │           ├── performance-optimization.mdc
│   │           ├── scapi-endpoints.mdc
│   │           ├── security-patterns.mdc
│   │           ├── sfcc-development.mdc
│   │           ├── sfra-controllers.mdc
│   │           ├── sfra-models.mdc
│   │           ├── system-objects.mdc
│   │           └── testing-patterns.mdc
│   └── github-copilot
│       └── copilot-instructions.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── docs
│   ├── best-practices
│   │   ├── cartridge_creation.md
│   │   ├── isml_templates.md
│   │   ├── job_framework.md
│   │   ├── localserviceregistry.md
│   │   ├── ocapi_hooks.md
│   │   ├── performance.md
│   │   ├── scapi_custom_endpoint.md
│   │   ├── scapi_hooks.md
│   │   ├── security.md
│   │   ├── sfra_client_side_js.md
│   │   ├── sfra_controllers.md
│   │   ├── sfra_models.md
│   │   └── sfra_scss.md
│   ├── dw_campaign
│   │   ├── ABTest.md
│   │   ├── ABTestMgr.md
│   │   ├── ABTestSegment.md
│   │   ├── AmountDiscount.md
│   │   ├── ApproachingDiscount.md
│   │   ├── BonusChoiceDiscount.md
│   │   ├── BonusDiscount.md
│   │   ├── Campaign.md
│   │   ├── CampaignMgr.md
│   │   ├── CampaignStatusCodes.md
│   │   ├── Coupon.md
│   │   ├── CouponMgr.md
│   │   ├── CouponRedemption.md
│   │   ├── CouponStatusCodes.md
│   │   ├── Discount.md
│   │   ├── DiscountPlan.md
│   │   ├── FixedPriceDiscount.md
│   │   ├── FixedPriceShippingDiscount.md
│   │   ├── FreeDiscount.md
│   │   ├── FreeShippingDiscount.md
│   │   ├── PercentageDiscount.md
│   │   ├── PercentageOptionDiscount.md
│   │   ├── PriceBookPriceDiscount.md
│   │   ├── Promotion.md
│   │   ├── PromotionMgr.md
│   │   ├── PromotionPlan.md
│   │   ├── SlotContent.md
│   │   ├── SourceCodeGroup.md
│   │   ├── SourceCodeInfo.md
│   │   ├── SourceCodeStatusCodes.md
│   │   └── TotalFixedPriceDiscount.md
│   ├── dw_catalog
│   │   ├── Catalog.md
│   │   ├── CatalogMgr.md
│   │   ├── Category.md
│   │   ├── CategoryAssignment.md
│   │   ├── CategoryLink.md
│   │   ├── PriceBook.md
│   │   ├── PriceBookMgr.md
│   │   ├── Product.md
│   │   ├── ProductActiveData.md
│   │   ├── ProductAttributeModel.md
│   │   ├── ProductAvailabilityLevels.md
│   │   ├── ProductAvailabilityModel.md
│   │   ├── ProductInventoryList.md
│   │   ├── ProductInventoryMgr.md
│   │   ├── ProductInventoryRecord.md
│   │   ├── ProductLink.md
│   │   ├── ProductMgr.md
│   │   ├── ProductOption.md
│   │   ├── ProductOptionModel.md
│   │   ├── ProductOptionValue.md
│   │   ├── ProductPriceInfo.md
│   │   ├── ProductPriceModel.md
│   │   ├── ProductPriceTable.md
│   │   ├── ProductSearchHit.md
│   │   ├── ProductSearchModel.md
│   │   ├── ProductSearchRefinementDefinition.md
│   │   ├── ProductSearchRefinements.md
│   │   ├── ProductSearchRefinementValue.md
│   │   ├── ProductVariationAttribute.md
│   │   ├── ProductVariationAttributeValue.md
│   │   ├── ProductVariationModel.md
│   │   ├── Recommendation.md
│   │   ├── SearchModel.md
│   │   ├── SearchRefinementDefinition.md
│   │   ├── SearchRefinements.md
│   │   ├── SearchRefinementValue.md
│   │   ├── SortingOption.md
│   │   ├── SortingRule.md
│   │   ├── Store.md
│   │   ├── StoreGroup.md
│   │   ├── StoreInventoryFilter.md
│   │   ├── StoreInventoryFilterValue.md
│   │   ├── StoreMgr.md
│   │   ├── Variant.md
│   │   └── VariationGroup.md
│   ├── dw_content
│   │   ├── Content.md
│   │   ├── ContentMgr.md
│   │   ├── ContentSearchModel.md
│   │   ├── ContentSearchRefinementDefinition.md
│   │   ├── ContentSearchRefinements.md
│   │   ├── ContentSearchRefinementValue.md
│   │   ├── Folder.md
│   │   ├── Library.md
│   │   ├── MarkupText.md
│   │   └── MediaFile.md
│   ├── dw_crypto
│   │   ├── CertificateRef.md
│   │   ├── CertificateUtils.md
│   │   ├── Cipher.md
│   │   ├── Encoding.md
│   │   ├── JWE.md
│   │   ├── JWEHeader.md
│   │   ├── JWS.md
│   │   ├── JWSHeader.md
│   │   ├── KeyRef.md
│   │   ├── Mac.md
│   │   ├── MessageDigest.md
│   │   ├── SecureRandom.md
│   │   ├── Signature.md
│   │   ├── WeakCipher.md
│   │   ├── WeakMac.md
│   │   ├── WeakMessageDigest.md
│   │   ├── WeakSignature.md
│   │   └── X509Certificate.md
│   ├── dw_customer
│   │   ├── AddressBook.md
│   │   ├── AgentUserMgr.md
│   │   ├── AgentUserStatusCodes.md
│   │   ├── AuthenticationStatus.md
│   │   ├── Credentials.md
│   │   ├── Customer.md
│   │   ├── CustomerActiveData.md
│   │   ├── CustomerAddress.md
│   │   ├── CustomerCDPData.md
│   │   ├── CustomerContextMgr.md
│   │   ├── CustomerGroup.md
│   │   ├── CustomerList.md
│   │   ├── CustomerMgr.md
│   │   ├── CustomerPasswordConstraints.md
│   │   ├── CustomerPaymentInstrument.md
│   │   ├── CustomerStatusCodes.md
│   │   ├── EncryptedObject.md
│   │   ├── ExternalProfile.md
│   │   ├── OrderHistory.md
│   │   ├── ProductList.md
│   │   ├── ProductListItem.md
│   │   ├── ProductListItemPurchase.md
│   │   ├── ProductListMgr.md
│   │   ├── ProductListRegistrant.md
│   │   ├── Profile.md
│   │   └── Wallet.md
│   ├── dw_extensions.applepay
│   │   ├── ApplePayHookResult.md
│   │   └── ApplePayHooks.md
│   ├── dw_extensions.facebook
│   │   ├── FacebookFeedHooks.md
│   │   └── FacebookProduct.md
│   ├── dw_extensions.paymentrequest
│   │   ├── PaymentRequestHookResult.md
│   │   └── PaymentRequestHooks.md
│   ├── dw_extensions.payments
│   │   ├── SalesforceBancontactPaymentDetails.md
│   │   ├── SalesforceCardPaymentDetails.md
│   │   ├── SalesforceEpsPaymentDetails.md
│   │   ├── SalesforceIdealPaymentDetails.md
│   │   ├── SalesforceKlarnaPaymentDetails.md
│   │   ├── SalesforcePaymentDetails.md
│   │   ├── SalesforcePaymentIntent.md
│   │   ├── SalesforcePaymentMethod.md
│   │   ├── SalesforcePaymentRequest.md
│   │   ├── SalesforcePaymentsHooks.md
│   │   ├── SalesforcePaymentsMgr.md
│   │   ├── SalesforcePaymentsSiteConfiguration.md
│   │   ├── SalesforcePayPalOrder.md
│   │   ├── SalesforcePayPalOrderAddress.md
│   │   ├── SalesforcePayPalOrderPayer.md
│   │   ├── SalesforcePayPalPaymentDetails.md
│   │   ├── SalesforceSepaDebitPaymentDetails.md
│   │   └── SalesforceVenmoPaymentDetails.md
│   ├── dw_extensions.pinterest
│   │   ├── PinterestAvailability.md
│   │   ├── PinterestFeedHooks.md
│   │   ├── PinterestOrder.md
│   │   ├── PinterestOrderHooks.md
│   │   └── PinterestProduct.md
│   ├── dw_io
│   │   ├── CSVStreamReader.md
│   │   ├── CSVStreamWriter.md
│   │   ├── File.md
│   │   ├── FileReader.md
│   │   ├── FileWriter.md
│   │   ├── InputStream.md
│   │   ├── OutputStream.md
│   │   ├── PrintWriter.md
│   │   ├── RandomAccessFileReader.md
│   │   ├── Reader.md
│   │   ├── StringWriter.md
│   │   ├── Writer.md
│   │   ├── XMLIndentingStreamWriter.md
│   │   ├── XMLStreamConstants.md
│   │   ├── XMLStreamReader.md
│   │   └── XMLStreamWriter.md
│   ├── dw_job
│   │   ├── JobExecution.md
│   │   └── JobStepExecution.md
│   ├── dw_net
│   │   ├── FTPClient.md
│   │   ├── FTPFileInfo.md
│   │   ├── HTTPClient.md
│   │   ├── HTTPRequestPart.md
│   │   ├── Mail.md
│   │   ├── SFTPClient.md
│   │   ├── SFTPFileInfo.md
│   │   ├── WebDAVClient.md
│   │   └── WebDAVFileInfo.md
│   ├── dw_object
│   │   ├── ActiveData.md
│   │   ├── CustomAttributes.md
│   │   ├── CustomObject.md
│   │   ├── CustomObjectMgr.md
│   │   ├── Extensible.md
│   │   ├── ExtensibleObject.md
│   │   ├── Note.md
│   │   ├── ObjectAttributeDefinition.md
│   │   ├── ObjectAttributeGroup.md
│   │   ├── ObjectAttributeValueDefinition.md
│   │   ├── ObjectTypeDefinition.md
│   │   ├── PersistentObject.md
│   │   ├── SimpleExtensible.md
│   │   └── SystemObjectMgr.md
│   ├── dw_order
│   │   ├── AbstractItem.md
│   │   ├── AbstractItemCtnr.md
│   │   ├── Appeasement.md
│   │   ├── AppeasementItem.md
│   │   ├── Basket.md
│   │   ├── BasketMgr.md
│   │   ├── BonusDiscountLineItem.md
│   │   ├── CouponLineItem.md
│   │   ├── CreateAgentBasketLimitExceededException.md
│   │   ├── CreateBasketFromOrderException.md
│   │   ├── CreateCouponLineItemException.md
│   │   ├── CreateOrderException.md
│   │   ├── CreateTemporaryBasketLimitExceededException.md
│   │   ├── GiftCertificate.md
│   │   ├── GiftCertificateLineItem.md
│   │   ├── GiftCertificateMgr.md
│   │   ├── GiftCertificateStatusCodes.md
│   │   ├── Invoice.md
│   │   ├── InvoiceItem.md
│   │   ├── LineItem.md
│   │   ├── LineItemCtnr.md
│   │   ├── Order.md
│   │   ├── OrderAddress.md
│   │   ├── OrderItem.md
│   │   ├── OrderMgr.md
│   │   ├── OrderPaymentInstrument.md
│   │   ├── OrderProcessStatusCodes.md
│   │   ├── PaymentCard.md
│   │   ├── PaymentInstrument.md
│   │   ├── PaymentMethod.md
│   │   ├── PaymentMgr.md
│   │   ├── PaymentProcessor.md
│   │   ├── PaymentStatusCodes.md
│   │   ├── PaymentTransaction.md
│   │   ├── PriceAdjustment.md
│   │   ├── PriceAdjustmentLimitTypes.md
│   │   ├── ProductLineItem.md
│   │   ├── ProductShippingCost.md
│   │   ├── ProductShippingLineItem.md
│   │   ├── ProductShippingModel.md
│   │   ├── Return.md
│   │   ├── ReturnCase.md
│   │   ├── ReturnCaseItem.md
│   │   ├── ReturnItem.md
│   │   ├── Shipment.md
│   │   ├── ShipmentShippingCost.md
│   │   ├── ShipmentShippingModel.md
│   │   ├── ShippingLineItem.md
│   │   ├── ShippingLocation.md
│   │   ├── ShippingMethod.md
│   │   ├── ShippingMgr.md
│   │   ├── ShippingOrder.md
│   │   ├── ShippingOrderItem.md
│   │   ├── SumItem.md
│   │   ├── TaxGroup.md
│   │   ├── TaxItem.md
│   │   ├── TaxMgr.md
│   │   ├── TrackingInfo.md
│   │   └── TrackingRef.md
│   ├── dw_order.hooks
│   │   ├── CalculateHooks.md
│   │   ├── OrderHooks.md
│   │   ├── PaymentHooks.md
│   │   ├── ReturnHooks.md
│   │   └── ShippingOrderHooks.md
│   ├── dw_rpc
│   │   ├── SOAPUtil.md
│   │   ├── Stub.md
│   │   └── WebReference.md
│   ├── dw_suggest
│   │   ├── BrandSuggestions.md
│   │   ├── CategorySuggestions.md
│   │   ├── ContentSuggestions.md
│   │   ├── CustomSuggestions.md
│   │   ├── ProductSuggestions.md
│   │   ├── SearchPhraseSuggestions.md
│   │   ├── SuggestedCategory.md
│   │   ├── SuggestedContent.md
│   │   ├── SuggestedPhrase.md
│   │   ├── SuggestedProduct.md
│   │   ├── SuggestedTerm.md
│   │   ├── SuggestedTerms.md
│   │   ├── Suggestions.md
│   │   └── SuggestModel.md
│   ├── dw_svc
│   │   ├── FTPService.md
│   │   ├── FTPServiceDefinition.md
│   │   ├── HTTPFormService.md
│   │   ├── HTTPFormServiceDefinition.md
│   │   ├── HTTPService.md
│   │   ├── HTTPServiceDefinition.md
│   │   ├── LocalServiceRegistry.md
│   │   ├── Result.md
│   │   ├── Service.md
│   │   ├── ServiceCallback.md
│   │   ├── ServiceConfig.md
│   │   ├── ServiceCredential.md
│   │   ├── ServiceDefinition.md
│   │   ├── ServiceProfile.md
│   │   ├── ServiceRegistry.md
│   │   ├── SOAPService.md
│   │   └── SOAPServiceDefinition.md
│   ├── dw_system
│   │   ├── AgentUserStatusCodes.md
│   │   ├── Cache.md
│   │   ├── CacheMgr.md
│   │   ├── HookMgr.md
│   │   ├── InternalObject.md
│   │   ├── JobProcessMonitor.md
│   │   ├── Log.md
│   │   ├── Logger.md
│   │   ├── LogNDC.md
│   │   ├── OrganizationPreferences.md
│   │   ├── Pipeline.md
│   │   ├── PipelineDictionary.md
│   │   ├── RemoteInclude.md
│   │   ├── Request.md
│   │   ├── RequestHooks.md
│   │   ├── Response.md
│   │   ├── RESTErrorResponse.md
│   │   ├── RESTResponseMgr.md
│   │   ├── RESTSuccessResponse.md
│   │   ├── SearchStatus.md
│   │   ├── Session.md
│   │   ├── Site.md
│   │   ├── SitePreferences.md
│   │   ├── Status.md
│   │   ├── StatusItem.md
│   │   ├── System.md
│   │   └── Transaction.md
│   ├── dw_util
│   │   ├── ArrayList.md
│   │   ├── Assert.md
│   │   ├── BigInteger.md
│   │   ├── Bytes.md
│   │   ├── Calendar.md
│   │   ├── Collection.md
│   │   ├── Currency.md
│   │   ├── DateUtils.md
│   │   ├── Decimal.md
│   │   ├── FilteringCollection.md
│   │   ├── Geolocation.md
│   │   ├── HashMap.md
│   │   ├── HashSet.md
│   │   ├── Iterator.md
│   │   ├── LinkedHashMap.md
│   │   ├── LinkedHashSet.md
│   │   ├── List.md
│   │   ├── Locale.md
│   │   ├── Map.md
│   │   ├── MapEntry.md
│   │   ├── MappingKey.md
│   │   ├── MappingMgr.md
│   │   ├── PropertyComparator.md
│   │   ├── SecureEncoder.md
│   │   ├── SecureFilter.md
│   │   ├── SeekableIterator.md
│   │   ├── Set.md
│   │   ├── SortedMap.md
│   │   ├── SortedSet.md
│   │   ├── StringUtils.md
│   │   ├── Template.md
│   │   └── UUIDUtils.md
│   ├── dw_value
│   │   ├── EnumValue.md
│   │   ├── MimeEncodedText.md
│   │   ├── Money.md
│   │   └── Quantity.md
│   ├── dw_web
│   │   ├── ClickStream.md
│   │   ├── ClickStreamEntry.md
│   │   ├── Cookie.md
│   │   ├── Cookies.md
│   │   ├── CSRFProtection.md
│   │   ├── Form.md
│   │   ├── FormAction.md
│   │   ├── FormElement.md
│   │   ├── FormElementValidationResult.md
│   │   ├── FormField.md
│   │   ├── FormFieldOption.md
│   │   ├── FormFieldOptions.md
│   │   ├── FormGroup.md
│   │   ├── FormList.md
│   │   ├── FormListItem.md
│   │   ├── Forms.md
│   │   ├── HttpParameter.md
│   │   ├── HttpParameterMap.md
│   │   ├── LoopIterator.md
│   │   ├── PageMetaData.md
│   │   ├── PageMetaTag.md
│   │   ├── PagingModel.md
│   │   ├── Resource.md
│   │   ├── URL.md
│   │   ├── URLAction.md
│   │   ├── URLParameter.md
│   │   ├── URLRedirect.md
│   │   ├── URLRedirectMgr.md
│   │   └── URLUtils.md
│   ├── sfra
│   │   ├── account.md
│   │   ├── address.md
│   │   ├── billing.md
│   │   ├── cart.md
│   │   ├── categories.md
│   │   ├── content.md
│   │   ├── locale.md
│   │   ├── order.md
│   │   ├── payment.md
│   │   ├── price-default.md
│   │   ├── price-range.md
│   │   ├── price-tiered.md
│   │   ├── product-bundle.md
│   │   ├── product-full.md
│   │   ├── product-line-items.md
│   │   ├── product-search.md
│   │   ├── product-tile.md
│   │   ├── querystring.md
│   │   ├── render.md
│   │   ├── request.md
│   │   ├── response.md
│   │   ├── server.md
│   │   ├── shipping.md
│   │   ├── store.md
│   │   ├── stores.md
│   │   └── totals.md
│   └── TopLevel
│       ├── APIException.md
│       ├── arguments.md
│       ├── Array.md
│       ├── ArrayBuffer.md
│       ├── BigInt.md
│       ├── Boolean.md
│       ├── ConversionError.md
│       ├── DataView.md
│       ├── Date.md
│       ├── Error.md
│       ├── ES6Iterator.md
│       ├── EvalError.md
│       ├── Fault.md
│       ├── Float32Array.md
│       ├── Float64Array.md
│       ├── Function.md
│       ├── Generator.md
│       ├── global.md
│       ├── Int16Array.md
│       ├── Int32Array.md
│       ├── Int8Array.md
│       ├── InternalError.md
│       ├── IOError.md
│       ├── Iterable.md
│       ├── Iterator.md
│       ├── JSON.md
│       ├── Map.md
│       ├── Math.md
│       ├── Module.md
│       ├── Namespace.md
│       ├── Number.md
│       ├── Object.md
│       ├── QName.md
│       ├── RangeError.md
│       ├── ReferenceError.md
│       ├── RegExp.md
│       ├── Set.md
│       ├── StopIteration.md
│       ├── String.md
│       ├── Symbol.md
│       ├── SyntaxError.md
│       ├── SystemError.md
│       ├── TypeError.md
│       ├── Uint16Array.md
│       ├── Uint32Array.md
│       ├── Uint8Array.md
│       ├── Uint8ClampedArray.md
│       ├── URIError.md
│       ├── WeakMap.md
│       ├── WeakSet.md
│       ├── XML.md
│       ├── XMLList.md
│       └── XMLStreamError.md
├── docs-site
│   ├── .gitignore
│   ├── App.tsx
│   ├── components
│   │   ├── Badge.tsx
│   │   ├── BreadcrumbSchema.tsx
│   │   ├── CodeBlock.tsx
│   │   ├── Collapsible.tsx
│   │   ├── ConfigBuilder.tsx
│   │   ├── ConfigHero.tsx
│   │   ├── ConfigModeTabs.tsx
│   │   ├── icons.tsx
│   │   ├── Layout.tsx
│   │   ├── LightCodeContainer.tsx
│   │   ├── NewcomerCTA.tsx
│   │   ├── NextStepsStrip.tsx
│   │   ├── OnThisPage.tsx
│   │   ├── Search.tsx
│   │   ├── SEO.tsx
│   │   ├── Sidebar.tsx
│   │   ├── StructuredData.tsx
│   │   ├── ToolCard.tsx
│   │   ├── ToolFilters.tsx
│   │   ├── Typography.tsx
│   │   └── VersionBadge.tsx
│   ├── constants.tsx
│   ├── index.html
│   ├── main.tsx
│   ├── metadata.json
│   ├── package-lock.json
│   ├── package.json
│   ├── pages
│   │   ├── AIInterfacesPage.tsx
│   │   ├── ConfigurationPage.tsx
│   │   ├── DevelopmentPage.tsx
│   │   ├── ExamplesPage.tsx
│   │   ├── FeaturesPage.tsx
│   │   ├── HomePage.tsx
│   │   ├── SecurityPage.tsx
│   │   ├── ToolsPage.tsx
│   │   └── TroubleshootingPage.tsx
│   ├── postcss.config.js
│   ├── public
│   │   ├── .well-known
│   │   │   └── security.txt
│   │   ├── 404.html
│   │   ├── android-chrome-192x192.png
│   │   ├── android-chrome-512x512.png
│   │   ├── apple-touch-icon.png
│   │   ├── explain-product-pricing-methods-no-mcp.png
│   │   ├── explain-product-pricing-methods.png
│   │   ├── favicon-16x16.png
│   │   ├── favicon-32x32.png
│   │   ├── favicon.ico
│   │   ├── llms.txt
│   │   ├── robots.txt
│   │   ├── site.webmanifest
│   │   └── sitemap.xml
│   ├── README.md
│   ├── scripts
│   │   ├── generate-search-index.js
│   │   ├── generate-sitemap.js
│   │   └── search-dev.js
│   ├── src
│   │   └── styles
│   │       ├── input.css
│   │       └── prism-theme.css
│   ├── tailwind.config.js
│   ├── tsconfig.json
│   ├── types.ts
│   ├── utils
│   │   ├── search.ts
│   │   └── toolsData.ts
│   └── vite.config.ts
├── eslint.config.js
├── jest.config.js
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── scripts
│   └── convert-docs.js
├── SECURITY.md
├── server.json
├── src
│   ├── clients
│   │   ├── base
│   │   │   ├── http-client.ts
│   │   │   ├── oauth-token.ts
│   │   │   └── ocapi-auth-client.ts
│   │   ├── best-practices-client.ts
│   │   ├── cartridge-generation-client.ts
│   │   ├── docs
│   │   │   ├── class-content-parser.ts
│   │   │   ├── class-name-resolver.ts
│   │   │   ├── documentation-scanner.ts
│   │   │   ├── index.ts
│   │   │   └── referenced-types-extractor.ts
│   │   ├── docs-client.ts
│   │   ├── log-client.ts
│   │   ├── logs
│   │   │   ├── index.ts
│   │   │   ├── log-analyzer.ts
│   │   │   ├── log-client.ts
│   │   │   ├── log-constants.ts
│   │   │   ├── log-file-discovery.ts
│   │   │   ├── log-file-reader.ts
│   │   │   ├── log-formatter.ts
│   │   │   ├── log-processor.ts
│   │   │   ├── log-types.ts
│   │   │   └── webdav-client-manager.ts
│   │   ├── ocapi
│   │   │   ├── code-versions-client.ts
│   │   │   ├── site-preferences-client.ts
│   │   │   └── system-objects-client.ts
│   │   ├── ocapi-client.ts
│   │   └── sfra-client.ts
│   ├── config
│   │   ├── configuration-factory.ts
│   │   └── dw-json-loader.ts
│   ├── core
│   │   ├── handlers
│   │   │   ├── abstract-log-tool-handler.ts
│   │   │   ├── base-handler.ts
│   │   │   ├── best-practices-handler.ts
│   │   │   ├── cartridge-handler.ts
│   │   │   ├── client-factory.ts
│   │   │   ├── code-version-handler.ts
│   │   │   ├── docs-handler.ts
│   │   │   ├── job-log-handler.ts
│   │   │   ├── job-log-tool-config.ts
│   │   │   ├── log-handler.ts
│   │   │   ├── log-tool-config.ts
│   │   │   ├── sfra-handler.ts
│   │   │   ├── system-object-handler.ts
│   │   │   └── validation-helpers.ts
│   │   ├── server.ts
│   │   └── tool-definitions.ts
│   ├── index.ts
│   ├── main.ts
│   ├── services
│   │   ├── file-system-service.ts
│   │   ├── index.ts
│   │   └── path-service.ts
│   ├── tool-configs
│   │   ├── best-practices-tool-config.ts
│   │   ├── cartridge-tool-config.ts
│   │   ├── code-version-tool-config.ts
│   │   ├── docs-tool-config.ts
│   │   ├── job-log-tool-config.ts
│   │   ├── log-tool-config.ts
│   │   ├── sfra-tool-config.ts
│   │   └── system-object-tool-config.ts
│   ├── types
│   │   └── types.ts
│   └── utils
│       ├── cache.ts
│       ├── job-log-tool-config.ts
│       ├── job-log-utils.ts
│       ├── log-cache.ts
│       ├── log-tool-config.ts
│       ├── log-tool-constants.ts
│       ├── log-tool-utils.ts
│       ├── logger.ts
│       ├── ocapi-url-builder.ts
│       ├── path-resolver.ts
│       ├── query-builder.ts
│       ├── utils.ts
│       └── validator.ts
├── tests
│   ├── __mocks__
│   │   ├── docs-client.ts
│   │   ├── src
│   │   │   └── clients
│   │   │       └── base
│   │   │           └── http-client.js
│   │   └── webdav.js
│   ├── base-handler.test.ts
│   ├── base-http-client.test.ts
│   ├── best-practices-handler.test.ts
│   ├── cache.test.ts
│   ├── cartridge-handler.test.ts
│   ├── class-content-parser.test.ts
│   ├── class-name-resolver.test.ts
│   ├── client-factory.test.ts
│   ├── code-version-handler.test.ts
│   ├── code-versions-client.test.ts
│   ├── config.test.ts
│   ├── configuration-factory.test.ts
│   ├── docs-handler.test.ts
│   ├── documentation-scanner.test.ts
│   ├── file-system-service.test.ts
│   ├── job-log-handler.test.ts
│   ├── job-log-utils.test.ts
│   ├── log-client.test.ts
│   ├── log-handler.test.ts
│   ├── log-processor.test.ts
│   ├── logger.test.ts
│   ├── mcp
│   │   ├── AGENTS.md
│   │   ├── node
│   │   │   ├── activate-code-version-advanced.full-mode.programmatic.test.js
│   │   │   ├── code-versions.full-mode.programmatic.test.js
│   │   │   ├── generate-cartridge-structure.docs-only.programmatic.test.js
│   │   │   ├── get-available-best-practice-guides.docs-only.programmatic.test.js
│   │   │   ├── get-available-sfra-documents.programmatic.test.js
│   │   │   ├── get-best-practice-guide.docs-only.programmatic.test.js
│   │   │   ├── get-hook-reference.docs-only.programmatic.test.js
│   │   │   ├── get-job-execution-summary.full-mode.programmatic.test.js
│   │   │   ├── get-job-log-entries.full-mode.programmatic.test.js
│   │   │   ├── get-latest-debug.full-mode.programmatic.test.js
│   │   │   ├── get-latest-error.full-mode.programmatic.test.js
│   │   │   ├── get-latest-info.full-mode.programmatic.test.js
│   │   │   ├── get-latest-job-log-files.full-mode.programmatic.test.js
│   │   │   ├── get-latest-warn.full-mode.programmatic.test.js
│   │   │   ├── get-log-file-contents.full-mode.programmatic.test.js
│   │   │   ├── get-sfcc-class-documentation.docs-only.programmatic.test.js
│   │   │   ├── get-sfcc-class-info.docs-only.programmatic.test.js
│   │   │   ├── get-sfra-categories.docs-only.programmatic.test.js
│   │   │   ├── get-sfra-document.programmatic.test.js
│   │   │   ├── get-sfra-documents-by-category.docs-only.programmatic.test.js
│   │   │   ├── get-system-object-definition.full-mode.programmatic.test.js
│   │   │   ├── get-system-object-definitions.docs-only.programmatic.test.js
│   │   │   ├── get-system-object-definitions.full-mode.programmatic.test.js
│   │   │   ├── list-log-files.full-mode.programmatic.test.js
│   │   │   ├── list-sfcc-classes.docs-only.programmatic.test.js
│   │   │   ├── search-best-practices.docs-only.programmatic.test.js
│   │   │   ├── search-custom-object-attribute-definitions.full-mode.programmatic.test.js
│   │   │   ├── search-job-logs-by-name.full-mode.programmatic.test.js
│   │   │   ├── search-job-logs.full-mode.programmatic.test.js
│   │   │   ├── search-logs.full-mode.programmatic.test.js
│   │   │   ├── search-sfcc-classes.docs-only.programmatic.test.js
│   │   │   ├── search-sfcc-methods.docs-only.programmatic.test.js
│   │   │   ├── search-sfra-documentation.docs-only.programmatic.test.js
│   │   │   ├── search-site-preferences.full-mode.programmatic.test.js
│   │   │   ├── search-system-object-attribute-definitions.full-mode.programmatic.test.js
│   │   │   ├── search-system-object-attribute-groups.full-mode.programmatic.test.js
│   │   │   ├── summarize-logs.full-mode.programmatic.test.js
│   │   │   ├── tools.docs-only.programmatic.test.js
│   │   │   └── tools.full-mode.programmatic.test.js
│   │   ├── README.md
│   │   ├── test-fixtures
│   │   │   └── dw.json
│   │   └── yaml
│   │       ├── activate-code-version.docs-only.test.mcp.yml
│   │       ├── activate-code-version.full-mode.test.mcp.yml
│   │       ├── get_latest_error.test.mcp.yml
│   │       ├── get-available-best-practice-guides.docs-only.test.mcp.yml
│   │       ├── get-available-best-practice-guides.full-mode.test.mcp.yml
│   │       ├── get-available-sfra-documents.docs-only.test.mcp.yml
│   │       ├── get-available-sfra-documents.full-mode.test.mcp.yml
│   │       ├── get-best-practice-guide.docs-only.test.mcp.yml
│   │       ├── get-best-practice-guide.full-mode.test.mcp.yml
│   │       ├── get-code-versions.docs-only.test.mcp.yml
│   │       ├── get-code-versions.full-mode.test.mcp.yml
│   │       ├── get-hook-reference.docs-only.test.mcp.yml
│   │       ├── get-hook-reference.full-mode.test.mcp.yml
│   │       ├── get-job-execution-summary.full-mode.test.mcp.yml
│   │       ├── get-job-log-entries.full-mode.test.mcp.yml
│   │       ├── get-latest-debug.full-mode.test.mcp.yml
│   │       ├── get-latest-error.full-mode.test.mcp.yml
│   │       ├── get-latest-info.full-mode.test.mcp.yml
│   │       ├── get-latest-job-log-files.full-mode.test.mcp.yml
│   │       ├── get-latest-warn.full-mode.test.mcp.yml
│   │       ├── get-log-file-contents.full-mode.test.mcp.yml
│   │       ├── get-sfcc-class-documentation.docs-only.test.mcp.yml
│   │       ├── get-sfcc-class-documentation.full-mode.test.mcp.yml
│   │       ├── get-sfcc-class-info.docs-only.test.mcp.yml
│   │       ├── get-sfcc-class-info.full-mode.test.mcp.yml
│   │       ├── get-sfra-categories.docs-only.test.mcp.yml
│   │       ├── get-sfra-categories.full-mode.test.mcp.yml
│   │       ├── get-sfra-document.docs-only.test.mcp.yml
│   │       ├── get-sfra-document.full-mode.test.mcp.yml
│   │       ├── get-sfra-documents-by-category.docs-only.test.mcp.yml
│   │       ├── get-sfra-documents-by-category.full-mode.test.mcp.yml
│   │       ├── get-system-object-definition.docs-only.test.mcp.yml
│   │       ├── get-system-object-definition.full-mode.test.mcp.yml
│   │       ├── get-system-object-definitions.docs-only.test.mcp.yml
│   │       ├── get-system-object-definitions.full-mode.test.mcp.yml
│   │       ├── list-log-files.full-mode.test.mcp.yml
│   │       ├── list-sfcc-classes.docs-only.test.mcp.yml
│   │       ├── list-sfcc-classes.full-mode.test.mcp.yml
│   │       ├── search-best-practices.docs-only.test.mcp.yml
│   │       ├── search-best-practices.full-mode.test.mcp.yml
│   │       ├── search-custom-object-attribute-definitions.docs-only.test.mcp.yml
│   │       ├── search-custom-object-attribute-definitions.test.mcp.yml
│   │       ├── search-job-logs-by-name.full-mode.test.mcp.yml
│   │       ├── search-job-logs.full-mode.test.mcp.yml
│   │       ├── search-logs.full-mode.test.mcp.yml
│   │       ├── search-sfcc-classes.docs-only.test.mcp.yml
│   │       ├── search-sfcc-classes.full-mode.test.mcp.yml
│   │       ├── search-sfcc-methods.docs-only.test.mcp.yml
│   │       ├── search-sfcc-methods.full-mode.test.mcp.yml
│   │       ├── search-sfra-documentation.docs-only.test.mcp.yml
│   │       ├── search-sfra-documentation.full-mode.test.mcp.yml
│   │       ├── search-site-preferences.docs-only.test.mcp.yml
│   │       ├── search-site-preferences.full-mode.test.mcp.yml
│   │       ├── search-system-object-attribute-definitions.docs-only.test.mcp.yml
│   │       ├── search-system-object-attribute-definitions.full-mode.test.mcp.yml
│   │       ├── search-system-object-attribute-groups.docs-only.test.mcp.yml
│   │       ├── search-system-object-attribute-groups.full-mode.test.mcp.yml
│   │       ├── summarize-logs.full-mode.test.mcp.yml
│   │       ├── tools.docs-only.test.mcp.yml
│   │       └── tools.full-mode.test.mcp.yml
│   ├── oauth-token.test.ts
│   ├── ocapi-auth-client.test.ts
│   ├── ocapi-client.test.ts
│   ├── path-service.test.ts
│   ├── query-builder.test.ts
│   ├── referenced-types-extractor.test.ts
│   ├── servers
│   │   ├── sfcc-mock-server
│   │   │   ├── mock-data
│   │   │   │   └── ocapi
│   │   │   │       ├── code-versions.json
│   │   │   │       ├── custom-object-attributes-customapi.json
│   │   │   │       ├── custom-object-attributes-globalsettings.json
│   │   │   │       ├── custom-object-attributes-versionhistory.json
│   │   │   │       ├── site-preferences-ccv.json
│   │   │   │       ├── site-preferences-fastforward.json
│   │   │   │       ├── site-preferences-sfra.json
│   │   │   │       ├── site-preferences-storefront.json
│   │   │   │       ├── site-preferences-system.json
│   │   │   │       ├── system-object-attribute-groups-campaign.json
│   │   │   │       ├── system-object-attribute-groups-category.json
│   │   │   │       ├── system-object-attribute-groups-order.json
│   │   │   │       ├── system-object-attribute-groups-product.json
│   │   │   │       ├── system-object-attribute-groups-sitepreferences.json
│   │   │   │       ├── system-object-attributes-customeraddress.json
│   │   │   │       ├── system-object-attributes-product-expanded.json
│   │   │   │       ├── system-object-attributes-product.json
│   │   │   │       ├── system-object-definition-category.json
│   │   │   │       ├── system-object-definition-customer.json
│   │   │   │       ├── system-object-definition-customeraddress.json
│   │   │   │       ├── system-object-definition-order.json
│   │   │   │       ├── system-object-definition-product.json
│   │   │   │       ├── system-object-definitions-old.json
│   │   │   │       └── system-object-definitions.json
│   │   │   ├── package-lock.json
│   │   │   ├── package.json
│   │   │   ├── README.md
│   │   │   ├── scripts
│   │   │   │   └── setup-logs.js
│   │   │   ├── server.js
│   │   │   └── src
│   │   │       ├── app.js
│   │   │       ├── config
│   │   │       │   └── server-config.js
│   │   │       ├── middleware
│   │   │       │   ├── auth.js
│   │   │       │   ├── cors.js
│   │   │       │   └── logging.js
│   │   │       ├── routes
│   │   │       │   ├── ocapi
│   │   │       │   │   ├── code-versions-handler.js
│   │   │       │   │   ├── oauth-handler.js
│   │   │       │   │   ├── ocapi-error-utils.js
│   │   │       │   │   ├── ocapi-utils.js
│   │   │       │   │   ├── site-preferences-handler.js
│   │   │       │   │   └── system-objects-handler.js
│   │   │       │   ├── ocapi.js
│   │   │       │   └── webdav.js
│   │   │       └── utils
│   │   │           ├── mock-data-loader.js
│   │   │           └── webdav-xml.js
│   │   └── sfcc-mock-server-manager.ts
│   ├── sfcc-mock-server.test.ts
│   ├── site-preferences-client.test.ts
│   ├── system-objects-client.test.ts
│   ├── utils.test.ts
│   ├── validation-helpers.test.ts
│   └── validator.test.ts
├── tsconfig.json
└── tsconfig.test.json
```

# Files

--------------------------------------------------------------------------------
/docs/dw_order.hooks/ReturnHooks.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.order.hooks
  2 | 
  3 | # Class ReturnHooks
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - dw.order.hooks.ReturnHooks
  8 | 
  9 | ## Description
 10 | 
 11 | This interface represents all script hooks that can be registered to customizing the order center return resource. It contains the extension points (hook names), and the functions that are called by each extension point. A function must be defined inside a JavaScript source and must be exported. The script with the exported hook function must be located inside a site cartridge. Inside the site cartridge a 'package.json' file with a 'hooks' entry must exist. "hooks": "./hooks.json" The hooks entry links to a json file, relative to the 'package.json' file. This file lists all registered hooks inside the hooks property: "hooks": [ {"name": "dw.order.return.createReturn", "script": "./returns.ds"}, {"name": "dw.order.return.addReturnItem", "script": "./returns.ds"}, {"name": "dw.order.return.changeStatus", "script": "./returns.ds"}, ] A hook entry has a 'name' and a 'script' property. The 'name' contains the extension point, the hook name. The 'script' contains the script relative to the hooks file, with the exported hook function. Overview Return Functionality Business objects ReturnCase All returns exist in the context of a ReturnCase, each Order can have any number of ReturnCases. A ReturnCase has ReturnCaseItems, each of which is associated with an OrderItem (an extension to either a ProductLineItem or a ShippingLineItem). Each ReturnCaseItem defines an ReturnCaseItem.getAuthorizedQuantity() representing the maximum quantity expected to be returned. A ReturnCaseItem may be associated with 0..n ReturnItems - ReturnItems are added to the ReturnCaseItem when Returns are created. Either - a ReturnCase may be used as an RMA, in which case they are created when a customer first shows a wish to return item(s). The customer then includes the RMA number with the returned item(s). The Return created as a result is then associated with the existing ReturnCase. Or - a ReturnCase is automatically created as part of the return creation, i.e. the customer returns some item(s) leading to a creation of both a Return and an associated ReturnCase. The scripting api allows access to the ReturnCases, whether the ReturnCase is an RMA or not, and the ReturnCase status. Both the ReturnCaseItems and any Returns associated with the ReturnCase can be accessed. A ReturnCase has one of these status values: New - the ReturnCase has been created and can be edited previous to its authorization CONFIRMED - the ReturnCase is CONFIRMED, can no longer be edited, no Returns have been associated with it. Only an New- ReturnCase can be CONFIRMED PARTIAL_RETURNED - the ReturnCase has been associated with at least one Return, but is not yet complete. Only an CONFIRMED- ReturnCase can be set to PARTIAL_RETURNED RETURNED - the ReturnCase has been associated with Returns which match the expected authorized quantity. Only an CONFIRMED- or PARTIAL_RETURNED- return-case can be set to RETURNED Cancelled - the ReturnCase has been cancelled (only a New- or CONFIRMED- ReturnCase can be cancelled) Return A Return represents a physical customer return, and contains 1..n ReturnItems. A Return is associated with one ReturnCase, and each ReturnItem is associated with one ReturnCaseItem and (via the ReturnCaseItem) a single OrderItem usually representing an Order ProductLineItem. A ReturnItem records the quantity returned. A Return can have one of these status values: NEW - the Return is new, i.e. needs to undergo a check before it can be marked as COMPLETED COMPLETED - the return is complete, this is a precondition for refunding the customer for a return. Credit Invoice As a result of making a Return, the customer may be refunded. The refund amount is held in a credit Invoice which may be associated either with one Return or with one ReturnCase. The Invoice is passed to the refund payment hook allowing custom code to handle the payment refund. Process overview Create ReturnCase The creation of ReturnCases is supported using the data-api. The api supports, within the context of an Order, the specification of an (optional) RMA-number and addition of ReturnCaseItems for a given order-item and quantity. Authorize ReturnCase Following its creation, a ReturnCase needs to be CONFIRMED - an CONFIRMED ReturnCase cannot be modified. Cancel ReturnCase Following its creation or authorization, a ReturnCase may be cancelled. Create Return Returns may be imported or created via the data-api. These apis specify an (optional) RMA allowing a Return to be associated with a ReturnCase, and ReturnItems with a quantity and a key allowing them to be associated with an order-item. The process is delegated to custom scripts which control the creation of the Return and the addition of the ReturnItems: Hook extensionPointCreateReturn The creation of the new Return is delegated to the custom script when this hook is called, passing the order, and details of the Return to be created to the script. Typically the script accesses the ReturnCase from the order and creates the return with the provided return-number. It may also update the Order, ReturnCase or Return using custom values passed in the Return details. exports.createReturn = function (order:Order, returnDetails) { var returnNumber=returnDetails.returnNumber; var returnCase = order.getReturnCase(returnDetails.returnCaseNumber); var newReturn = returnCase.createReturn(returnNumber); return newReturn; } Hook extensionPointAddReturnItem This call delegates the creation of individual ReturnItems to a custom script, passing the Order, returnNumber, returnCaseItemId and return-item-details. Typically the script will access the ReturnCaseItem from the order and create a new ReturnItem for it. exports.addReturnItem = function (retrn:Return, returnItemDetails) { var returnCaseItem = order.getReturnCaseItem(returnCaseItemId); var item = returnCaseItem.createReturnItem(returnNr); Hook extensionPointChangeStatus This call delegates the update of the return-status to a custom script, passing the Order, returnNumber and new status. The custom script is responsible for setting the status and taking any other actions necessary, including the possibility of creating a credit invoice: changeStatus = function (retrn:Return, status) { retrn.status=status; Hook extensionPointAfterStatusChange This call delegates the update of the return-status to a custom script, passing the Order, returnNumber and new status. The custom script is responsible for setting the status and taking any other actions necessary, including the possibility of creating a credit invoice: changeStatus = function (retrn:Return, status) { retrn.status=status; Order post-processing APIs (gillian) are now inactive by default and will throw an exception if accessed. Activation needs preliminary approval by Product Management. Please contact support in this case. Existing customers using these APIs are not affected by this change and can use the APIs until further notice.
 12 | 
 13 | ## Constants
 14 | 
 15 | ## Properties
 16 | 
 17 | ## Constructor Summary
 18 | 
 19 | ## Method Summary
 20 | 
 21 | ### addReturnItem
 22 | 
 23 | **Signature:** `addReturnItem(retrn : Return, inputData : ReturnItem) : Status`
 24 | 
 25 | The hook provides customization in the process of assigning the returned amount, quantity etc.
 26 | 
 27 | ### afterStatusChange
 28 | 
 29 | **Signature:** `afterStatusChange(retrn : Return) : Status`
 30 | 
 31 | Called after method changeStatus(Return, ReturnWO) returns Status.OK.
 32 | 
 33 | ### changeStatus
 34 | 
 35 | **Signature:** `changeStatus(retrn : Return, inputData : Return) : Status`
 36 | 
 37 | Responsible to change the status of a Return: the custom script is responsible for setting the new status using Return.setStatus(String).
 38 | 
 39 | ### createReturn
 40 | 
 41 | **Signature:** `createReturn(inputData : Return) : Return`
 42 | 
 43 | This hook is responsible for creating a new Return, based on a ReturnCase.
 44 | 
 45 | ### notifyStatusChange
 46 | 
 47 | **Signature:** `notifyStatusChange(retrn : Return) : Status`
 48 | 
 49 | Called after method changeStatus(Return, ReturnWO) returns Status.OK (and after method afterStatusChange(Return)) to inform of a successful status change.
 50 | 
 51 | ## Method Detail
 52 | 
 53 | ## Method Details
 54 | 
 55 | ### addReturnItem
 56 | 
 57 | **Signature:** `addReturnItem(retrn : Return, inputData : ReturnItem) : Status`
 58 | 
 59 | **Description:** The hook provides customization in the process of assigning the returned amount, quantity etc. Here it is possible to refund differently based on the return reason code for example. Also one could correct the inventory based on the return information. Utilize ReturnCaseItem.createReturnItem(String) to create a new ReturnItem.
 60 | 
 61 | **Parameters:**
 62 | 
 63 | - `retrn`: the return for which an return item should be created
 64 | - `inputData`: the return item
 65 | 
 66 | **Returns:**
 67 | 
 68 | Status.OK return item is successfully added Status.ERROR return item addition failed.
 69 | 
 70 | ---
 71 | 
 72 | ### afterStatusChange
 73 | 
 74 | **Signature:** `afterStatusChange(retrn : Return) : Status`
 75 | 
 76 | **Description:** Called after method changeStatus(Return, ReturnWO) returns Status.OK. The call is made in a separate database transaction allowing the script implementation to make an independent remote call if desired.
 77 | 
 78 | **Parameters:**
 79 | 
 80 | - `retrn`: the return
 81 | 
 82 | **Returns:**
 83 | 
 84 | Status.OK status successful Status.ERROR on failure
 85 | 
 86 | ---
 87 | 
 88 | ### changeStatus
 89 | 
 90 | **Signature:** `changeStatus(retrn : Return, inputData : Return) : Status`
 91 | 
 92 | **Description:** Responsible to change the status of a Return: the custom script is responsible for setting the new status using Return.setStatus(String). The invoice handling should be implemented here using Return.createInvoice(String) or ReturnCase.createInvoice(String). For example create an Invoice for a Return moving to status Return.STATUS_COMPLETED.
 93 | 
 94 | **Parameters:**
 95 | 
 96 | - `retrn`: the return which status should change
 97 | - `inputData`: the data in which the new status is included
 98 | 
 99 | **Returns:**
100 | 
101 | Status.OK status successfully changed Status.ERROR status not changed.
102 | 
103 | ---
104 | 
105 | ### createReturn
106 | 
107 | **Signature:** `createReturn(inputData : Return) : Return`
108 | 
109 | **Description:** This hook is responsible for creating a new Return, based on a ReturnCase. 2 basic workflows are supported: On-the-fly return: create the parent ReturnCase using Order.createReturnCase(String, Boolean). Return-merchandise-authorization (RMA) workflow: resolve an existing ReturnCase using Order.getReturnCase(String). In both cases use this method to create the Return based on the inputData. Additional functionality like creating history entry, handling the return fees or the shipping cost credit can be implemented in the hook after the Return is created.
110 | 
111 | **Parameters:**
112 | 
113 | - `inputData`: the return
114 | 
115 | **Returns:**
116 | 
117 | the created return
118 | 
119 | ---
120 | 
121 | ### notifyStatusChange
122 | 
123 | **Signature:** `notifyStatusChange(retrn : Return) : Status`
124 | 
125 | **Description:** Called after method changeStatus(Return, ReturnWO) returns Status.OK (and after method afterStatusChange(Return)) to inform of a successful status change. The call is made outside any database transaction. This is the best hook in which to send customer notifications as the status change has already been successfully written to the database
126 | 
127 | **Parameters:**
128 | 
129 | - `retrn`: the return
130 | 
131 | **Returns:**
132 | 
133 | Status.OK status successful Status.ERROR on failure
134 | 
135 | ---
```

--------------------------------------------------------------------------------
/docs/dw_customer/ProductListMgr.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.customer
  2 | 
  3 | # Class ProductListMgr
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.customer.ProductListMgr
  9 | 
 10 | ## Description
 11 | 
 12 | ProductListMgr provides methods for retrieving, creating, searching for, and removing product lists.
 13 | 
 14 | ## Constructor Summary
 15 | 
 16 | ## Method Summary
 17 | 
 18 | ### createProductList
 19 | 
 20 | **Signature:** `static createProductList(customer : Customer, type : Number) : ProductList`
 21 | 
 22 | Creates a new instance of a product list, of the specified type.
 23 | 
 24 | ### getProductList
 25 | 
 26 | **Signature:** `static getProductList(ID : String) : ProductList`
 27 | 
 28 | Gets the product list by its ID.
 29 | 
 30 | ### getProductList
 31 | 
 32 | **Signature:** `static getProductList(profile : Profile, type : Number) : ProductList`
 33 | 
 34 | Returns the first product list belonging to the customer with the specified profile.
 35 | 
 36 | ### getProductLists
 37 | 
 38 | **Signature:** `static getProductLists(customer : Customer, type : Number) : Collection`
 39 | 
 40 | Retrieve all product lists of the specified type owned by the specified customer.
 41 | 
 42 | ### getProductLists
 43 | 
 44 | **Signature:** `static getProductLists(customer : Customer, type : Number, eventType : String) : Collection`
 45 | 
 46 | Retrieve all the product lists of the specified type and event type belonging to the specified customer.
 47 | 
 48 | ### getProductLists
 49 | 
 50 | **Signature:** `static getProductLists(customerAddress : CustomerAddress) : Collection`
 51 | 
 52 | Returns the collection of product lists that have the specified address as the shipping address.
 53 | 
 54 | ### queryProductLists
 55 | 
 56 | **Signature:** `static queryProductLists(queryAttributes : Map, sortString : String) : SeekableIterator`
 57 | 
 58 | Searches for product list instances.
 59 | 
 60 | ### queryProductLists
 61 | 
 62 | **Signature:** `static queryProductLists(queryString : String, sortString : String, args : Object...) : SeekableIterator`
 63 | 
 64 | Searches for product list instances.
 65 | 
 66 | ### removeProductList
 67 | 
 68 | **Signature:** `static removeProductList(productList : ProductList) : void`
 69 | 
 70 | Removes the specified product list from the system.
 71 | 
 72 | ## Method Detail
 73 | 
 74 | ## Method Details
 75 | 
 76 | ### createProductList
 77 | 
 78 | **Signature:** `static createProductList(customer : Customer, type : Number) : ProductList`
 79 | 
 80 | **Description:** Creates a new instance of a product list, of the specified type.
 81 | 
 82 | **Parameters:**
 83 | 
 84 | - `customer`: The customer owning the product list, must not be null.
 85 | - `type`: The type of list (e.g. wish list, gift registry). The types are defined as constants within ProductList.
 86 | 
 87 | **Returns:**
 88 | 
 89 | the new list instance.
 90 | 
 91 | ---
 92 | 
 93 | ### getProductList
 94 | 
 95 | **Signature:** `static getProductList(ID : String) : ProductList`
 96 | 
 97 | **Description:** Gets the product list by its ID.
 98 | 
 99 | **Parameters:**
100 | 
101 | - `ID`: The product list ID.
102 | 
103 | **Returns:**
104 | 
105 | the ProductList instance, or null if a list with the specified UUID doesn't exist.
106 | 
107 | ---
108 | 
109 | ### getProductList
110 | 
111 | **Signature:** `static getProductList(profile : Profile, type : Number) : ProductList`
112 | 
113 | **Description:** Returns the first product list belonging to the customer with the specified profile.
114 | 
115 | **Deprecated:**
116 | 
117 | Use getProductLists(Customer, Number) or getProductLists(Customer, Number, String) instead.
118 | 
119 | **Parameters:**
120 | 
121 | - `profile`: The profile of the customer whose product list is to be retrieved.
122 | - `type`: The type of list (e.g. wish list, gift registry). The types are defined as constants within ProductList.
123 | 
124 | **Returns:**
125 | 
126 | the product list, or null if none exists.
127 | 
128 | ---
129 | 
130 | ### getProductLists
131 | 
132 | **Signature:** `static getProductLists(customer : Customer, type : Number) : Collection`
133 | 
134 | **Description:** Retrieve all product lists of the specified type owned by the specified customer.
135 | 
136 | **Parameters:**
137 | 
138 | - `customer`: The customer used for the query, must not be null.
139 | - `type`: The type of list used for the query. The types are defined as constants within ProductList.
140 | 
141 | **Returns:**
142 | 
143 | the unsorted collection of ProductList instances of the specified type belonging to the specified customer.
144 | 
145 | ---
146 | 
147 | ### getProductLists
148 | 
149 | **Signature:** `static getProductLists(customer : Customer, type : Number, eventType : String) : Collection`
150 | 
151 | **Description:** Retrieve all the product lists of the specified type and event type belonging to the specified customer.
152 | 
153 | **Parameters:**
154 | 
155 | - `customer`: The customer used for the query, must not be null.
156 | - `type`: The type of list used for the query. The types are defined as constants within ProductList.
157 | - `eventType`: The event type used for the query, must not be null.
158 | 
159 | **Returns:**
160 | 
161 | the unsorted collection of ProductList instances of the specified type and event type belonging to the specified customer.
162 | 
163 | ---
164 | 
165 | ### getProductLists
166 | 
167 | **Signature:** `static getProductLists(customerAddress : CustomerAddress) : Collection`
168 | 
169 | **Description:** Returns the collection of product lists that have the specified address as the shipping address.
170 | 
171 | **Parameters:**
172 | 
173 | - `customerAddress`: the address to test, must not be null.
174 | 
175 | **Returns:**
176 | 
177 | the unsorted collection of ProductList instances using this address.
178 | 
179 | ---
180 | 
181 | ### queryProductLists
182 | 
183 | **Signature:** `static queryProductLists(queryAttributes : Map, sortString : String) : SeekableIterator`
184 | 
185 | **Description:** Searches for product list instances. The search can be configured with a map, which key-value pairs are converted into a query expression. The key-value pairs are turned into a sequence of '=' or 'like' conditions, which are combined with AND statements. Example: A map with the key/value pairs: 'name'/'tom*', 'age'/66 will be converted as follows: "name like 'tom*' and age = 66" The identifier for an attribute to use in a query condition is always the ID of the attribute as defined in the type definition. For custom defined attributes the prefix custom is required in the search term (e.g. custom.color = {1}), while for system attributes no prefix is used (e.g. name = {4}). Supported attribute value types with sample expression values: String 'String', 'Str*', 'Strin?' Integer 1, 3E4 Number 1.0, 3.99E5 Date yyyy-MM-dd e.g. 2007-05-31 (Default TimeZone = UTC) DateTime yyyy-MM-dd'T'hh:mm:ss+Z e.g. 2007-05-31T00:00+Z (Z TimeZone = UTC) or 2007-05-31T00:00:00 Boolean true, false Email '[email protected]', '*@demandware.com' Set of String 'String', 'Str*', 'Strin?' Set of Integer 1, 3E4 Set of Number 1.0, 3.99E5 Enum of String 'String', 'Str*', 'Strin?' Enum of Integer 1, 3E4 The following types of attributes are not queryable: Image HTML Text Quantity Password Note, that some system attributes are not queryable by default regardless of the actual value type code. The sorting parameter is optional and may contain a comma separated list of attribute names to sort by. Each sort attribute name may be followed by an optional sort direction specifier ('asc' | 'desc'). Default sorting directions is ascending, if no direction was specified. Example: age desc, name Please note that specifying a localized custom attribute as the sorting attribute is currently not supported. It is strongly recommended to call close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources.
186 | 
187 | **Parameters:**
188 | 
189 | - `queryAttributes`: key-value pairs, which define the query.
190 | - `sortString`: an optional sorting or null if no sorting is necessary.
191 | 
192 | **Returns:**
193 | 
194 | SeekableIterator containing the result set of the query.
195 | 
196 | **See Also:**
197 | 
198 | SeekableIterator.close()
199 | 
200 | ---
201 | 
202 | ### queryProductLists
203 | 
204 | **Signature:** `static queryProductLists(queryString : String, sortString : String, args : Object...) : SeekableIterator`
205 | 
206 | **Description:** Searches for product list instances. The search can be configured using a simple query language, which provides most common filter and operator functionality. The identifier for an attribute to use in a query condition is always the ID of the attribute as defined in the type definition. For custom defined attributes the prefix custom is required in the search term (e.g. custom.color = {1}), while for system attributes no prefix is used (e.g. name = {4}). Supported attribute value types with sample expression values: String 'String', 'Str*', 'Strin?' Integer 1, 3E4 Number 1.0, 3.99E5 Date yyyy-MM-dd e.g. 2007-05-31 (Default TimeZone = UTC) DateTime yyyy-MM-dd'T'hh:mm:ss+Z e.g. 2007-05-31T00:00+Z (Z TimeZone = UTC) or 2007-05-31T00:00:00 Boolean true, false Email '[email protected]', '*@demandware.com' Set of String 'String', 'Str*', 'Strin?' Set of Integer 1, 3E4 Set of Number 1.0, 3.99E5 Enum of String 'String', 'Str*', 'Strin?' Enum of Integer 1, 3E4 The following types of attributes are not queryable: Image HTML Text Quantity Password Note, that some system attributes are not queryable by default regardless of the actual value type code. The following operators are supported in a condition: = Equals - All types; supports NULL value (thumbnail = NULL) != Not equals - All types; supports NULL value (thumbnail != NULL) < Less than - Integer, Number and Date types only > Greater than - Integer, Number and Date types only <= Less or equals than - Integer, Number and Date types only >= Greater or equals than - Integer, Number and Date types only LIKE Like - String types and Email only; use if leading or trailing wildcards will be used to support substring search(custom.country LIKE 'US*') ILIKE Caseindependent Like - String types and Email only, use to support case insensitive query (custom.country ILIKE 'usa'), does also support wildcards for substring matching Conditions can be combined using logical expressions 'AND', 'OR' and 'NOT' and nested using parenthesis e.g. gender = {1} AND (age >= {2} OR (NOT profession LIKE {3})). The query language provides a placeholder syntax to pass objects as additional search parameters. Each passed object is related to a placeholder in the query string. The placeholder must be an Integer that is surrounded by braces. The first Integer value must be '0', the second '1' and so on, e.g. querySystemObjects("sample", "age = {0} or creationDate >= {1}", 18, date) The sorting parameter is optional and may contain a comma separated list of attribute names to sort by. Each sort attribute name may be followed by an optional sort direction specifier ('asc' | 'desc'). Default sorting directions is ascending, if no direction was specified. Example: age desc, name Please note that specifying a localized custom attribute as the sorting attribute is currently not supported. Sometimes it is desired to get all instances with a special sorting condition. This can be easily done by providing the 'sortString' in combination with an empty 'queryString', e.g. querySystemObjects("sample", "", "ID asc") It is strongly recommended to call close() on the returned SeekableIterator if not all of its elements are being retrieved. This will ensure the proper cleanup of system resources.
207 | 
208 | **Parameters:**
209 | 
210 | - `queryString`: the actual query.
211 | - `sortString`: an optional sorting or null if no sorting is necessary.
212 | - `args`: optional parameters for the queryString.
213 | 
214 | **Returns:**
215 | 
216 | SeekableIterator containing the result set of the query.
217 | 
218 | **See Also:**
219 | 
220 | SeekableIterator.close()
221 | 
222 | ---
223 | 
224 | ### removeProductList
225 | 
226 | **Signature:** `static removeProductList(productList : ProductList) : void`
227 | 
228 | **Description:** Removes the specified product list from the system.
229 | 
230 | **Parameters:**
231 | 
232 | - `productList`: The list to remove, must not be null.
233 | 
234 | ---
```

--------------------------------------------------------------------------------
/docs/dw_campaign/DiscountPlan.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.campaign
  2 | 
  3 | # Class DiscountPlan
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.campaign.DiscountPlan
  9 | 
 10 | ## Description
 11 | 
 12 | DiscountPlan represents a set of Discounts. Instances of the class are returned by the PromotionMgr when requesting applicable discounts for a specified set of promotions and a line item container (see PromotionMgr.getDiscounts(LineItemCtnr, PromotionPlan)). DiscountPlan provides methods to access the discounts contained in the plan, add additional discounts to the plan (future) or remove discounts from the plan.
 13 | 
 14 | ## Properties
 15 | 
 16 | ### approachingOrderDiscounts
 17 | 
 18 | **Type:** Collection (Read Only)
 19 | 
 20 | Get the collection of order discounts that the LineItemCtnr "almost"
 21 |  qualifies for based on the merchandise total in the cart. Nearness is
 22 |  controlled by thresholds configured at the promotion level.
 23 |  
 24 |  The collection of returned approaching discounts is ordered by the
 25 |  condition threshold of the promotion (e.g. "spend $100 and get 10% off"
 26 |  discount is returned before "spend $150 and get 15% off" discount.) A
 27 |  discount is not returned if it would be prevented from applying (because
 28 |  of compatibility rules) by an order discount already in the DiscountPlan
 29 |  or an approaching order discount with a lower condition threshold.
 30 | 
 31 | ### bonusDiscounts
 32 | 
 33 | **Type:** Collection (Read Only)
 34 | 
 35 | All bonus discounts contained in the discount plan.
 36 | 
 37 | ### lineItemCtnr
 38 | 
 39 | **Type:** LineItemCtnr (Read Only)
 40 | 
 41 | Returns line item container associated with discount plan. 
 42 |  A discount plan is created from and associated with a line item container.
 43 |  This method returns the line item container associated with this discount plan.
 44 | 
 45 | ### orderDiscounts
 46 | 
 47 | **Type:** Collection (Read Only)
 48 | 
 49 | The percentage and amount order discounts contained in the
 50 |  discount plan.
 51 | 
 52 | ## Constructor Summary
 53 | 
 54 | ## Method Summary
 55 | 
 56 | ### getApproachingOrderDiscounts
 57 | 
 58 | **Signature:** `getApproachingOrderDiscounts() : Collection`
 59 | 
 60 | Get the collection of order discounts that the LineItemCtnr "almost" qualifies for based on the merchandise total in the cart.
 61 | 
 62 | ### getApproachingShippingDiscounts
 63 | 
 64 | **Signature:** `getApproachingShippingDiscounts(shipment : Shipment) : Collection`
 65 | 
 66 | Get the collection of shipping discounts that the passed shipment "almost" qualifies for based on the merchandise total in the shipment.
 67 | 
 68 | ### getApproachingShippingDiscounts
 69 | 
 70 | **Signature:** `getApproachingShippingDiscounts(shipment : Shipment, shippingMethod : ShippingMethod) : Collection`
 71 | 
 72 | Get the collection of shipping discounts that the passed shipment "almost" qualifies for based on the merchandise total in the shipment.
 73 | 
 74 | ### getApproachingShippingDiscounts
 75 | 
 76 | **Signature:** `getApproachingShippingDiscounts(shipment : Shipment, shippingMethods : Collection) : Collection`
 77 | 
 78 | Get the collection of shipping discounts that the passed shipment "almost" qualifies for based on the merchandise total in the shipment.
 79 | 
 80 | ### getBonusDiscounts
 81 | 
 82 | **Signature:** `getBonusDiscounts() : Collection`
 83 | 
 84 | Returns all bonus discounts contained in the discount plan.
 85 | 
 86 | ### getLineItemCtnr
 87 | 
 88 | **Signature:** `getLineItemCtnr() : LineItemCtnr`
 89 | 
 90 | Returns line item container associated with discount plan.
 91 | 
 92 | ### getOrderDiscounts
 93 | 
 94 | **Signature:** `getOrderDiscounts() : Collection`
 95 | 
 96 | Returns the percentage and amount order discounts contained in the discount plan.
 97 | 
 98 | ### getProductDiscounts
 99 | 
100 | **Signature:** `getProductDiscounts(productLineItem : ProductLineItem) : Collection`
101 | 
102 | Returns the percentage, amount and fix price discounts associated with the specified product line item.
103 | 
104 | ### getProductShippingDiscounts
105 | 
106 | **Signature:** `getProductShippingDiscounts(productLineItem : ProductLineItem) : Collection`
107 | 
108 | Returns the product-shipping discounts associated with the specified product line item.
109 | 
110 | ### getShippingDiscounts
111 | 
112 | **Signature:** `getShippingDiscounts(shipment : Shipment) : Collection`
113 | 
114 | Returns the percentage, amount and fix price discounts associated with the specified shipment.
115 | 
116 | ### removeDiscount
117 | 
118 | **Signature:** `removeDiscount(discount : Discount) : void`
119 | 
120 | Removes the specified discount from the discount plan.
121 | 
122 | ## Method Detail
123 | 
124 | ## Method Details
125 | 
126 | ### getApproachingOrderDiscounts
127 | 
128 | **Signature:** `getApproachingOrderDiscounts() : Collection`
129 | 
130 | **Description:** Get the collection of order discounts that the LineItemCtnr "almost" qualifies for based on the merchandise total in the cart. Nearness is controlled by thresholds configured at the promotion level. The collection of returned approaching discounts is ordered by the condition threshold of the promotion (e.g. "spend $100 and get 10% off" discount is returned before "spend $150 and get 15% off" discount.) A discount is not returned if it would be prevented from applying (because of compatibility rules) by an order discount already in the DiscountPlan or an approaching order discount with a lower condition threshold.
131 | 
132 | **Returns:**
133 | 
134 | Collection of approaching order discounts ordered by the condition threshold of the promotion ascending.
135 | 
136 | ---
137 | 
138 | ### getApproachingShippingDiscounts
139 | 
140 | **Signature:** `getApproachingShippingDiscounts(shipment : Shipment) : Collection`
141 | 
142 | **Description:** Get the collection of shipping discounts that the passed shipment "almost" qualifies for based on the merchandise total in the shipment. Nearness is controlled by thresholds configured at the promotion level. The collection of returned approaching discounts is ordered by the condition threshold of the promotion (e.g. "spend $100 and get free standard shipping" discount is returned before "spend $150 and get free standard shipping" discount.) A discount is not returned if it would be prevented from applying (because of compatibility rules) by a shipping discount already in the DiscountPlan or an approaching shipping discount with a lower condition threshold.
143 | 
144 | **Parameters:**
145 | 
146 | - `shipment`: The shipment to calculate approaching discounts for.
147 | 
148 | **Returns:**
149 | 
150 | Collection of approaching shipping discounts ordered by the condition threshold of the promotion ascending.
151 | 
152 | ---
153 | 
154 | ### getApproachingShippingDiscounts
155 | 
156 | **Signature:** `getApproachingShippingDiscounts(shipment : Shipment, shippingMethod : ShippingMethod) : Collection`
157 | 
158 | **Description:** Get the collection of shipping discounts that the passed shipment "almost" qualifies for based on the merchandise total in the shipment. Here "almost" is controlled by thresholds configured at the promotion level. This method only returns discounts for shipping promotions which apply to the passed shipping method. The collection of returned approaching discounts is ordered by the condition threshold of the promotion (e.g. "spend $100 and get free standard shipping" discount is returned before "spend $150 and get free standard shipping" discount.) A discount is not returned if it would be prevented from applying (because of compatibility rules) by a shipping discount already in the DiscountPlan or an approaching shipping discount with a lower condition threshold.
159 | 
160 | **Parameters:**
161 | 
162 | - `shipment`: The shipment to calculate approaching discounts for.
163 | - `shippingMethod`: The shipping method to filter by.
164 | 
165 | **Returns:**
166 | 
167 | Collection of approaching shipping discounts ordered by the condition threshold of the promotion, ascending.
168 | 
169 | ---
170 | 
171 | ### getApproachingShippingDiscounts
172 | 
173 | **Signature:** `getApproachingShippingDiscounts(shipment : Shipment, shippingMethods : Collection) : Collection`
174 | 
175 | **Description:** Get the collection of shipping discounts that the passed shipment "almost" qualifies for based on the merchandise total in the shipment. Here "almost" is controlled by thresholds configured at the promotion level. This method only returns discounts for shipping promotions which apply to one of the passed shipping methods. The collection of returned approaching discounts is ordered by the condition threshold of the promotion (e.g. "spend $100 and get free standard shipping" discount is returned before "spend $150 and get free standard shipping" discount.) A discount is not returned if it would be prevented from applying (because of compatibility rules) by a shipping discount already in the DiscountPlan or an approaching shipping discount with a lower condition threshold.
176 | 
177 | **Parameters:**
178 | 
179 | - `shipment`: The shipment to calculate approaching discounts for.
180 | - `shippingMethods`: The shipping methods to filter by.
181 | 
182 | **Returns:**
183 | 
184 | Collection of approaching shipping discounts ordered by the condition threshold of the promotion ascending.
185 | 
186 | ---
187 | 
188 | ### getBonusDiscounts
189 | 
190 | **Signature:** `getBonusDiscounts() : Collection`
191 | 
192 | **Description:** Returns all bonus discounts contained in the discount plan.
193 | 
194 | **Returns:**
195 | 
196 | All bonus discounts contained in discount plan
197 | 
198 | ---
199 | 
200 | ### getLineItemCtnr
201 | 
202 | **Signature:** `getLineItemCtnr() : LineItemCtnr`
203 | 
204 | **Description:** Returns line item container associated with discount plan. A discount plan is created from and associated with a line item container. This method returns the line item container associated with this discount plan.
205 | 
206 | **Returns:**
207 | 
208 | Line item container associated with plan
209 | 
210 | ---
211 | 
212 | ### getOrderDiscounts
213 | 
214 | **Signature:** `getOrderDiscounts() : Collection`
215 | 
216 | **Description:** Returns the percentage and amount order discounts contained in the discount plan.
217 | 
218 | **Returns:**
219 | 
220 | Order discounts contained in the discount plan
221 | 
222 | ---
223 | 
224 | ### getProductDiscounts
225 | 
226 | **Signature:** `getProductDiscounts(productLineItem : ProductLineItem) : Collection`
227 | 
228 | **Description:** Returns the percentage, amount and fix price discounts associated with the specified product line item. If the specified product line item is not contained in the discount plan, an empty collection is returned.
229 | 
230 | **Parameters:**
231 | 
232 | - `productLineItem`: Product line item
233 | 
234 | **Returns:**
235 | 
236 | Discounts associated with specified product line item
237 | 
238 | ---
239 | 
240 | ### getProductShippingDiscounts
241 | 
242 | **Signature:** `getProductShippingDiscounts(productLineItem : ProductLineItem) : Collection`
243 | 
244 | **Description:** Returns the product-shipping discounts associated with the specified product line item. If the specified product line item is not contained in the discount plan, an empty collection is returned.
245 | 
246 | **Parameters:**
247 | 
248 | - `productLineItem`: Product line item
249 | 
250 | **Returns:**
251 | 
252 | Product-shipping discounts associated with specified product line item
253 | 
254 | ---
255 | 
256 | ### getShippingDiscounts
257 | 
258 | **Signature:** `getShippingDiscounts(shipment : Shipment) : Collection`
259 | 
260 | **Description:** Returns the percentage, amount and fix price discounts associated with the specified shipment. If the specified shipment is not contained in the discount plan, an empty collection is returned.
261 | 
262 | **Parameters:**
263 | 
264 | - `shipment`: the shipment for which to fetch discounts.
265 | 
266 | **Returns:**
267 | 
268 | Discounts associated with specified shipment
269 | 
270 | ---
271 | 
272 | ### removeDiscount
273 | 
274 | **Signature:** `removeDiscount(discount : Discount) : void`
275 | 
276 | **Description:** Removes the specified discount from the discount plan. This method should only be used for very simple discount scenarios. It is not recommended to use the method in case of stacked discounts (i.e. multiple order or product discounts), or complex discount types like Buy X Get Y or Total Fixed Price, since correct re-calculation of the discount plan based on the promotion rules is not guaranteed.
277 | 
278 | **Parameters:**
279 | 
280 | - `discount`: Discount to be removed
281 | 
282 | ---
```

--------------------------------------------------------------------------------
/docs/dw_customer/ProductListItem.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.customer
  2 | 
  3 | # Class ProductListItem
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.object.PersistentObject
  9 |   - dw.object.ExtensibleObject
 10 |     - dw.customer.ProductListItem
 11 | 
 12 | ## Description
 13 | 
 14 | An item in a product list. Types of items are: An item that references a product via the product's SKU. An item that represents a gift certificate.
 15 | 
 16 | ## Constants
 17 | 
 18 | ### TYPE_GIFT_CERTIFICATE
 19 | 
 20 | **Type:** Number = 2
 21 | 
 22 | Constant representing a gift certificate list item type.
 23 | 
 24 | ### TYPE_PRODUCT
 25 | 
 26 | **Type:** Number = 1
 27 | 
 28 | Constant representing a product list item type.
 29 | 
 30 | ## Properties
 31 | 
 32 | ### ID
 33 | 
 34 | **Type:** String (Read Only)
 35 | 
 36 | The unique system generated ID of the object.
 37 | 
 38 | ### list
 39 | 
 40 | **Type:** ProductList (Read Only)
 41 | 
 42 | The product list that this item belongs to.
 43 | 
 44 | ### priority
 45 | 
 46 | **Type:** Number
 47 | 
 48 | Specify the priority level for the item.  Typically the lower the
 49 |  number, the higher the priority. This can be used by the owner of the product list
 50 |  to express which items he/she likes to get purchased first.
 51 | 
 52 | ### product
 53 | 
 54 | **Type:** Product
 55 | 
 56 | The referenced product for this item.  The reference is made
 57 |  via the product ID attribute.  This method returns null if there is
 58 |  no such product in the system or if the product exists but is not
 59 |  assigned to the site catalog.
 60 | 
 61 | ### productID
 62 | 
 63 | **Type:** String (Read Only)
 64 | 
 65 | The ID of the product referenced by this item.
 66 |  This attribute is set when a product is assigned via setProduct().
 67 |  It is possible for the ID to reference a product that doesn't exist
 68 |  anymore.  In this case getProduct() would return null.
 69 | 
 70 | ### productOptionModel
 71 | 
 72 | **Type:** ProductOptionModel
 73 | 
 74 | The ProductOptionModel for the product associated with this item,
 75 |  or null if there is no valid product associated with this item.
 76 | 
 77 | ### public
 78 | 
 79 | **Type:** boolean
 80 | 
 81 | A flag, typically used to determine whether the item should display
 82 |  in a customer's view of the list (as opposed to the list owner's view).
 83 | 
 84 | ### purchasedQuantity
 85 | 
 86 | **Type:** Quantity (Read Only)
 87 | 
 88 | The sum of the quantities of all the individual purchase records
 89 |  for this item.
 90 | 
 91 | ### purchasedQuantityValue
 92 | 
 93 | **Type:** Number (Read Only)
 94 | 
 95 | The value part of the underlying purchased quantity object, as distinct
 96 |  from the unit.
 97 | 
 98 | ### purchases
 99 | 
100 | **Type:** Collection (Read Only)
101 | 
102 | All purchases made for this item.
103 | 
104 | ### quantity
105 | 
106 | **Type:** Quantity
107 | 
108 | The quantity of the item.
109 |  The quantity is the number of products or gift certificates
110 |  that get shipped when purchasing this product list item.
111 | 
112 | ### quantityValue
113 | 
114 | **Type:** Number
115 | 
116 | The value part of the underlying quantity object, as distinct
117 |  from the unit.
118 | 
119 | ### type
120 | 
121 | **Type:** Number (Read Only)
122 | 
123 | The type of this product list item.
124 | 
125 | ## Constructor Summary
126 | 
127 | ## Method Summary
128 | 
129 | ### createPurchase
130 | 
131 | **Signature:** `createPurchase(quantity : Number, purchaserName : String) : ProductListItemPurchase`
132 | 
133 | Create a purchase record for this item.
134 | 
135 | ### getID
136 | 
137 | **Signature:** `getID() : String`
138 | 
139 | Returns the unique system generated ID of the object.
140 | 
141 | ### getList
142 | 
143 | **Signature:** `getList() : ProductList`
144 | 
145 | Returns the product list that this item belongs to.
146 | 
147 | ### getPriority
148 | 
149 | **Signature:** `getPriority() : Number`
150 | 
151 | Specify the priority level for the item.
152 | 
153 | ### getProduct
154 | 
155 | **Signature:** `getProduct() : Product`
156 | 
157 | Returns the referenced product for this item.
158 | 
159 | ### getProductID
160 | 
161 | **Signature:** `getProductID() : String`
162 | 
163 | Returns the ID of the product referenced by this item.
164 | 
165 | ### getProductOptionModel
166 | 
167 | **Signature:** `getProductOptionModel() : ProductOptionModel`
168 | 
169 | Returns the ProductOptionModel for the product associated with this item, or null if there is no valid product associated with this item.
170 | 
171 | ### getPurchasedQuantity
172 | 
173 | **Signature:** `getPurchasedQuantity() : Quantity`
174 | 
175 | Returns the sum of the quantities of all the individual purchase records for this item.
176 | 
177 | ### getPurchasedQuantityValue
178 | 
179 | **Signature:** `getPurchasedQuantityValue() : Number`
180 | 
181 | Returns the value part of the underlying purchased quantity object, as distinct from the unit.
182 | 
183 | ### getPurchases
184 | 
185 | **Signature:** `getPurchases() : Collection`
186 | 
187 | Returns all purchases made for this item.
188 | 
189 | ### getQuantity
190 | 
191 | **Signature:** `getQuantity() : Quantity`
192 | 
193 | Returns the quantity of the item.
194 | 
195 | ### getQuantityValue
196 | 
197 | **Signature:** `getQuantityValue() : Number`
198 | 
199 | Returns the value part of the underlying quantity object, as distinct from the unit.
200 | 
201 | ### getType
202 | 
203 | **Signature:** `getType() : Number`
204 | 
205 | Returns the type of this product list item.
206 | 
207 | ### isPublic
208 | 
209 | **Signature:** `isPublic() : boolean`
210 | 
211 | A flag, typically used to determine whether the item should display in a customer's view of the list (as opposed to the list owner's view).
212 | 
213 | ### setPriority
214 | 
215 | **Signature:** `setPriority(priority : Number) : void`
216 | 
217 | Specify the priority level for the item.
218 | 
219 | ### setProduct
220 | 
221 | **Signature:** `setProduct(product : Product) : void`
222 | 
223 | Sets the referenced product for this item by storing the product's id.
224 | 
225 | ### setProductOptionModel
226 | 
227 | **Signature:** `setProductOptionModel(productOptionModel : ProductOptionModel) : void`
228 | 
229 | Store a product option model with this object.
230 | 
231 | ### setPublic
232 | 
233 | **Signature:** `setPublic(flag : boolean) : void`
234 | 
235 | Typically used to determine if the item is visible to other customers.
236 | 
237 | ### setQuantity
238 | 
239 | **Signature:** `setQuantity(value : Quantity) : void`
240 | 
241 | Sets the quantity of the item.
242 | 
243 | ### setQuantityValue
244 | 
245 | **Signature:** `setQuantityValue(value : Number) : void`
246 | 
247 | Set the value part of the underlying quantity object, as distinct from the unit.
248 | 
249 | ## Method Detail
250 | 
251 | ## Method Details
252 | 
253 | ### createPurchase
254 | 
255 | **Signature:** `createPurchase(quantity : Number, purchaserName : String) : ProductListItemPurchase`
256 | 
257 | **Description:** Create a purchase record for this item.
258 | 
259 | **Parameters:**
260 | 
261 | - `quantity`: The number of items purchased.
262 | - `purchaserName`: The name of the purchaser.
263 | 
264 | **Returns:**
265 | 
266 | the purchase record.
267 | 
268 | ---
269 | 
270 | ### getID
271 | 
272 | **Signature:** `getID() : String`
273 | 
274 | **Description:** Returns the unique system generated ID of the object.
275 | 
276 | **Returns:**
277 | 
278 | the ID of object.
279 | 
280 | ---
281 | 
282 | ### getList
283 | 
284 | **Signature:** `getList() : ProductList`
285 | 
286 | **Description:** Returns the product list that this item belongs to.
287 | 
288 | **Returns:**
289 | 
290 | the list.
291 | 
292 | ---
293 | 
294 | ### getPriority
295 | 
296 | **Signature:** `getPriority() : Number`
297 | 
298 | **Description:** Specify the priority level for the item. Typically the lower the number, the higher the priority. This can be used by the owner of the product list to express which items he/she likes to get purchased first.
299 | 
300 | **Returns:**
301 | 
302 | the specified priority level.
303 | 
304 | ---
305 | 
306 | ### getProduct
307 | 
308 | **Signature:** `getProduct() : Product`
309 | 
310 | **Description:** Returns the referenced product for this item. The reference is made via the product ID attribute. This method returns null if there is no such product in the system or if the product exists but is not assigned to the site catalog.
311 | 
312 | **Returns:**
313 | 
314 | the product referenced by this item, or null.
315 | 
316 | ---
317 | 
318 | ### getProductID
319 | 
320 | **Signature:** `getProductID() : String`
321 | 
322 | **Description:** Returns the ID of the product referenced by this item. This attribute is set when a product is assigned via setProduct(). It is possible for the ID to reference a product that doesn't exist anymore. In this case getProduct() would return null.
323 | 
324 | **Returns:**
325 | 
326 | the product ID, or null if none exists.
327 | 
328 | ---
329 | 
330 | ### getProductOptionModel
331 | 
332 | **Signature:** `getProductOptionModel() : ProductOptionModel`
333 | 
334 | **Description:** Returns the ProductOptionModel for the product associated with this item, or null if there is no valid product associated with this item.
335 | 
336 | **Returns:**
337 | 
338 | the associated ProductOptionModel or null.
339 | 
340 | ---
341 | 
342 | ### getPurchasedQuantity
343 | 
344 | **Signature:** `getPurchasedQuantity() : Quantity`
345 | 
346 | **Description:** Returns the sum of the quantities of all the individual purchase records for this item.
347 | 
348 | **Returns:**
349 | 
350 | the sum of the quantities of all the individual purchase records for this item.
351 | 
352 | ---
353 | 
354 | ### getPurchasedQuantityValue
355 | 
356 | **Signature:** `getPurchasedQuantityValue() : Number`
357 | 
358 | **Description:** Returns the value part of the underlying purchased quantity object, as distinct from the unit.
359 | 
360 | **Returns:**
361 | 
362 | the value part of the underlying purchased quantity object, as distinct from the unit.
363 | 
364 | ---
365 | 
366 | ### getPurchases
367 | 
368 | **Signature:** `getPurchases() : Collection`
369 | 
370 | **Description:** Returns all purchases made for this item.
371 | 
372 | **Returns:**
373 | 
374 | the collection of purchase records for this item. Returns an empty list if this item has not been purchased yet.
375 | 
376 | ---
377 | 
378 | ### getQuantity
379 | 
380 | **Signature:** `getQuantity() : Quantity`
381 | 
382 | **Description:** Returns the quantity of the item. The quantity is the number of products or gift certificates that get shipped when purchasing this product list item.
383 | 
384 | **Returns:**
385 | 
386 | the quantity of the item.
387 | 
388 | ---
389 | 
390 | ### getQuantityValue
391 | 
392 | **Signature:** `getQuantityValue() : Number`
393 | 
394 | **Description:** Returns the value part of the underlying quantity object, as distinct from the unit.
395 | 
396 | **Returns:**
397 | 
398 | the value part of the underlying quantity object, as distinct from the unit.
399 | 
400 | ---
401 | 
402 | ### getType
403 | 
404 | **Signature:** `getType() : Number`
405 | 
406 | **Description:** Returns the type of this product list item.
407 | 
408 | **Returns:**
409 | 
410 | a code that specifies the type of item (i.e. product or gift certificate).
411 | 
412 | ---
413 | 
414 | ### isPublic
415 | 
416 | **Signature:** `isPublic() : boolean`
417 | 
418 | **Description:** A flag, typically used to determine whether the item should display in a customer's view of the list (as opposed to the list owner's view).
419 | 
420 | **Returns:**
421 | 
422 | true if the item is public.
423 | 
424 | ---
425 | 
426 | ### setPriority
427 | 
428 | **Signature:** `setPriority(priority : Number) : void`
429 | 
430 | **Description:** Specify the priority level for the item. Typically the lower the number, the higher the priority. This can be used by the owner of the product list to express which items he/she likes to get purchased first.
431 | 
432 | **Parameters:**
433 | 
434 | - `priority`: The new priority level.
435 | 
436 | ---
437 | 
438 | ### setProduct
439 | 
440 | **Signature:** `setProduct(product : Product) : void`
441 | 
442 | **Description:** Sets the referenced product for this item by storing the product's id. If null is specified, then the id is set to null.
443 | 
444 | **Deprecated:**
445 | 
446 | Use ProductList.createProductItem(Product) instead.
447 | 
448 | **Parameters:**
449 | 
450 | - `product`: The referenced product for this item.
451 | 
452 | ---
453 | 
454 | ### setProductOptionModel
455 | 
456 | **Signature:** `setProductOptionModel(productOptionModel : ProductOptionModel) : void`
457 | 
458 | **Description:** Store a product option model with this object. This stores a copy of the specified model, rather than an assocation to the same instance.
459 | 
460 | **Parameters:**
461 | 
462 | - `productOptionModel`: The object to store.
463 | 
464 | ---
465 | 
466 | ### setPublic
467 | 
468 | **Signature:** `setPublic(flag : boolean) : void`
469 | 
470 | **Description:** Typically used to determine if the item is visible to other customers.
471 | 
472 | **Parameters:**
473 | 
474 | - `flag`: If true, this product list becomes visible to other customers. If false, this product list can only be seen by the owner of the product list.
475 | 
476 | ---
477 | 
478 | ### setQuantity
479 | 
480 | **Signature:** `setQuantity(value : Quantity) : void`
481 | 
482 | **Description:** Sets the quantity of the item.
483 | 
484 | **Deprecated:**
485 | 
486 | Use setQuantityValue(Number) instead.
487 | 
488 | **Parameters:**
489 | 
490 | - `value`: the new quantity of the item.
491 | 
492 | ---
493 | 
494 | ### setQuantityValue
495 | 
496 | **Signature:** `setQuantityValue(value : Number) : void`
497 | 
498 | **Description:** Set the value part of the underlying quantity object, as distinct from the unit.
499 | 
500 | **Parameters:**
501 | 
502 | - `value`: the value to use.
503 | 
504 | ---
```

--------------------------------------------------------------------------------
/docs/dw_order.hooks/PaymentHooks.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.order.hooks
  2 | 
  3 | # Class PaymentHooks
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - dw.order.hooks.PaymentHooks
  8 | 
  9 | ## Description
 10 | 
 11 | This interface represents all script hooks that can be registered to customize the order center payment functionality. It contains the extension points (hook names), and the functions that are called by each extension point. A function must be defined inside a JavaScript source and must be exported. The script with the exported hook function must be located inside a site cartridge. Inside the site cartridge a 'package.json' file with a 'hooks' entry must exist. "hooks": "./hooks.json" The hooks entry links to a json file, relative to the 'package.json' file. This file lists all registered hooks inside the hooks property: "hooks": [ {"name": "dw.order.payment.authorize", "script": "./authorize.js"}, {"name": "dw.order.payment.validateAuthorization", "script": "./validateAuthorization.js"}, ] A hook entry has a 'name' and a 'script' property. The 'name' contains the extension point, the hook name. The 'script' contains the script relative to the hooks file, with the exported hook function.
 12 | 
 13 | ## Constants
 14 | 
 15 | ## Properties
 16 | 
 17 | ## Constructor Summary
 18 | 
 19 | ## Method Summary
 20 | 
 21 | ### authorize
 22 | 
 23 | **Signature:** `authorize(order : Order, paymentDetails : OrderPaymentInstrument) : Status`
 24 | 
 25 | The function is called by extension point extensionPointAuthorize.
 26 | 
 27 | ### authorizeCreditCard
 28 | 
 29 | **Signature:** `authorizeCreditCard(order : Order, paymentDetails : OrderPaymentInstrument, cvn : String) : Status`
 30 | 
 31 | The function is called by extension point extensionPointAuthorizeCreditCard.
 32 | 
 33 | ### capture
 34 | 
 35 | **Signature:** `capture(invoice : Invoice) : Status`
 36 | 
 37 | The function is called by extension point extensionPointCapture.
 38 | 
 39 | ### reauthorize
 40 | 
 41 | **Signature:** `reauthorize(order : Order) : Status`
 42 | 
 43 | The function is called by extension point extensionPointReauthorize.
 44 | 
 45 | ### refund
 46 | 
 47 | **Signature:** `refund(invoice : Invoice) : Status`
 48 | 
 49 | The function is called by extension point extensionPointRefund.
 50 | 
 51 | ### releaseAuthorization
 52 | 
 53 | **Signature:** `releaseAuthorization(order : Order) : Status`
 54 | 
 55 | The function is called by extension point extensionPointReleaseAuthorization.
 56 | 
 57 | ### validateAuthorization
 58 | 
 59 | **Signature:** `validateAuthorization(order : Order) : Status`
 60 | 
 61 | The function is called by extension point extensionPointValidateAuthorization.
 62 | 
 63 | ## Method Detail
 64 | 
 65 | ## Method Details
 66 | 
 67 | ### authorize
 68 | 
 69 | **Signature:** `authorize(order : Order, paymentDetails : OrderPaymentInstrument) : Status`
 70 | 
 71 | **Description:** The function is called by extension point extensionPointAuthorize. Custom payment authorization - modify the order as needed. Prerequisite: An order has been created using the data api or via the storefront. Return Status.OK: Corresponding payment transaction is marked as authorized (usually a custom property is used for this). Return Status.ERROR: Order is held, authorization needs to be repeated.
 72 | 
 73 | **Parameters:**
 74 | 
 75 | - `order`: the order
 76 | - `paymentDetails`: specified payment details
 77 | 
 78 | **Returns:**
 79 | 
 80 | Status.OK successful authorization. Status.ERROR authorization failed.
 81 | 
 82 | ---
 83 | 
 84 | ### authorizeCreditCard
 85 | 
 86 | **Signature:** `authorizeCreditCard(order : Order, paymentDetails : OrderPaymentInstrument, cvn : String) : Status`
 87 | 
 88 | **Description:** The function is called by extension point extensionPointAuthorizeCreditCard. Custom payment authorization of a credit card - modify the order as needed. Prerequisite: An order has been created using the data api or via the storefront. Return Status.OK: Corresponding payment transaction is marked as authorized (usually a custom property is used for this). Return Status.ERROR: Order is held, authorization needs to be repeated.
 89 | 
 90 | **Parameters:**
 91 | 
 92 | - `order`: the order
 93 | - `paymentDetails`: specified payment details
 94 | - `cvn`: the credit card verification number
 95 | 
 96 | **Returns:**
 97 | 
 98 | Status.OK successful authorization. Status.ERROR authorization failed.
 99 | 
100 | ---
101 | 
102 | ### capture
103 | 
104 | **Signature:** `capture(invoice : Invoice) : Status`
105 | 
106 | **Description:** The function is called by extension point extensionPointCapture. Custom payment capture - modify the order as needed. Prerequisite: [ either ] As a result of shipping (or part-shipping) a shipping -order the warehouse updates the status of the shipping-order resulting in the creation of an unpaid debit invoice (the creation of the invoice is usually handled in ShippingOrderHooks.changeStatus(ShippingOrder, ShippingOrderWO)). [ or ] A unpaid debit invoice has been created using the data api. Context: An unpaid debit invoice is passed to the payment system for capture. The capture attempt can either succeed (complete invoice amount captured) or fail. As a result the invoice status is updated by ordercenter for further processing. See Invoice. Hook responsibility: The hook should attempt to capture the amount located in invoice.grandTotal.grossPrice. When successful, the capture hook should also update the invoice by calling Invoice.addCaptureTransaction(OrderPaymentInstrument, Money) which serves to record the capturedAmount and associate the invoice with the payment-transaction. Return Status.OK: Indicates capture succeeded: Order Center sets the Invoice status to Invoice.STATUS_PAID. Return Status.ERROR: Indicates capture failed: Order Center sets the Invoice status to Invoice.STATUS_FAILED for further processing. Post processing: When the capture hook returns with success, order center not only sets the relevant invoice status, but also sets the relevant capturedAmount values on the invoice item. Returning success means the entire invoice total has been captured, so each item within the invoice can also be marked as completely captured. Note the script implementing the hook can take responsibility for this if desired order center will not overwrite existing values, but normally the standard implementation fits. As a result each invoice item and the related order item can return a capturedAmount, useful for calculating possible refunds.
107 | 
108 | **Parameters:**
109 | 
110 | - `invoice`: the invoice
111 | 
112 | **Returns:**
113 | 
114 | Status.OK for successful capture of entire invoice amount. Status.ERROR capture failed
115 | 
116 | ---
117 | 
118 | ### reauthorize
119 | 
120 | **Signature:** `reauthorize(order : Order) : Status`
121 | 
122 | **Description:** The function is called by extension point extensionPointReauthorize. Custom payment authorization - modify the order as needed. Prerequisite: [ either ] Based on a selected Order, a ShippingOrder (which represents the whole or part of the order which can be shipped) is to be created ready for export to the warehouse system. [ or ] A ShippingOrder is to be directly created using the data api. Context: The related order is passed to the payment hook to check its authorization has not become invalid. Two hooks are called: a. validateAuthorization(Order) is used to check the orders authorization is still valid b. reauthorize(Order) is called if step a. returns Error Return Status.OK: Corresponding payment transaction is marked as authorized (usually a custom property is used for this). If the order had been previously authorized, the custom property values may be overwritten during reauthorization. Return Status.ERROR: Order is held, authorization needs to be repeated.
123 | 
124 | **Parameters:**
125 | 
126 | - `order`: the order
127 | 
128 | **Returns:**
129 | 
130 | Status.OK successful authorization. Status.ERROR authorization failed
131 | 
132 | ---
133 | 
134 | ### refund
135 | 
136 | **Signature:** `refund(invoice : Invoice) : Status`
137 | 
138 | **Description:** The function is called by extension point extensionPointRefund. Custom payment refund - modify the order as needed. Prerequisite: [ either ] Goods returned by the customer result in the creation of one or more return documents, resulting in the creation of an unpaid customer credit invoice (the creation of the invoice is usually handled in ReturnHooks.changeStatus(Return, ReturnWO)). [ or ] An unpaid customer credit invoice is created using the data api (perhaps as a result of the creation of a customer appeasement). Context: An unpaid credit invoice is passed to the payment system for refund. The refund attempt can either succeed (complete invoice amount refunded) or fail. As a result the invoice status is updated by ordercenter for further processing. See Invoice. Hook responsibility: The hook should attempt to refund the amount located in invoice.grandTotal.grossPrice. When successful, the refund hook should also update the invoice by calling Invoice.addRefundTransaction(OrderPaymentInstrument, Money) which serves to record the refundedAmount and associate the invoice with the payment-transaction. Return Status.OK: Indicates refund succeeded: Order Center sets the Invoice status to Invoice.STATUS_PAID. Return Status.ERROR: Indicates refund failed: Order Center sets the Invoice status to Invoice.STATUS_FAILED for further processing. Post processing: When the refund hook returns with success, order center not only sets the relevant invoice status, but also sets the relevant refundAmount values on the invoice item. Returning success means the entire invoice total has been refunded, so each item within the invoice can also be marked as completely refunded. Note the script implementing the hook can take responsibility for this if desired order center will not overwrite existing values, but normally the standard implementation fits. As a result each invoice item and the related order item can return a refundedAmount, useful for calculating further possible refunds.
139 | 
140 | **Parameters:**
141 | 
142 | - `invoice`: the invoice
143 | 
144 | **Returns:**
145 | 
146 | Status.OK for successful refund of entire invoice amount. Status.ERROR refund failed
147 | 
148 | ---
149 | 
150 | ### releaseAuthorization
151 | 
152 | **Signature:** `releaseAuthorization(order : Order) : Status`
153 | 
154 | **Description:** The function is called by extension point extensionPointReleaseAuthorization. Custom payment release authorization - modify the order as needed. Prerequisite: an authorized order is updated resulting in a need to release the remaining authorization. This happens when: - order is cancelled - order is complete after remaining order items are cancelled. Return Status.OK - successful release authorization Return Status.ERROR - failed release authorization
155 | 
156 | **Parameters:**
157 | 
158 | - `order`: the order
159 | 
160 | **Returns:**
161 | 
162 | Status.OK for successful release authorization. Status.ERROR failed release authorization
163 | 
164 | ---
165 | 
166 | ### validateAuthorization
167 | 
168 | **Signature:** `validateAuthorization(order : Order) : Status`
169 | 
170 | **Description:** The function is called by extension point extensionPointValidateAuthorization. Custom payment authorization - modify the order as needed. Context: This hook is called to validate whether a payment authorization exists for the order. It should usually check: - Whether the authorize or reauthorize hook was previously successfully executed for the order, e.g. by checking whether custom property has been previously set. - Whether an existing authorization has expired e.g. by comparing a timestamp set on authorization with the current time. Return Status.OK: indicates the order has a valid payment authorization. Return Status.ERROR: indicates reauthorize(Order) should be called. See reauthorize(Order) for more details.
171 | 
172 | **Parameters:**
173 | 
174 | - `order`: the order
175 | 
176 | **Returns:**
177 | 
178 | Status.OK order has a valid payment authorization. Status.ERROR order has no valid payment authorization, reauthorize(Order) should be called
179 | 
180 | ---
```

--------------------------------------------------------------------------------
/docs-site/pages/ToolsPage.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import React from 'react';
  2 | import { NavLink } from 'react-router-dom';
  3 | import SEO from '../components/SEO';
  4 | import BreadcrumbSchema from '../components/BreadcrumbSchema';
  5 | import StructuredData from '../components/StructuredData';
  6 | import { H1, PageSubtitle } from '../components/Typography';
  7 | import ToolFilters from '../components/ToolFilters';
  8 | import ToolCard from '../components/ToolCard';
  9 | import { tools, popularTools } from '../utils/toolsData';
 10 | import { SITE_DATES } from '../constants';
 11 | 
 12 | const ToolsPage: React.FC = () => {
 13 |   const [activeCategory, setActiveCategory] = React.useState('All');
 14 |   const [search, setSearch] = React.useState('');
 15 |   const [showPopularExpanded, setShowPopularExpanded] = React.useState(true);
 16 | 
 17 |   const filtered = tools.filter(t => {
 18 |     const inCat = activeCategory === 'All' || t.category === activeCategory;
 19 |     if (!inCat) return false;
 20 |     if (!search) return true;
 21 |     const q = search.toLowerCase();
 22 |     return (
 23 |       t.name.toLowerCase().includes(q) ||
 24 |       t.description.toLowerCase().includes(q) ||
 25 |       t.examples?.some(e => e.toLowerCase().includes(q)) ||
 26 |       t.params?.some(p => p.name.toLowerCase().includes(q)) ||
 27 |       t.tags?.some(tag => tag.toLowerCase().includes(q))
 28 |     );
 29 |   });
 30 | 
 31 |   const toolsStructuredData = {
 32 |     "@context": "https://schema.org",
 33 |     "@type": "TechArticle",
 34 |     "headline": "Available Tools & APIs - SFCC Development MCP Server",
 35 |     "description": "Interactive reference of SFCC Development MCP Server tools with filtering, search, examples, and quick start actions.",
 36 |     "author": {
 37 |       "@type": "Person",
 38 |       "name": "Thomas Theunen"
 39 |     },
 40 |     "publisher": {
 41 |       "@type": "Person",
 42 |       "name": "Thomas Theunen"
 43 |     },
 44 |     "datePublished": SITE_DATES.PUBLISHED,
 45 |     "dateModified": SITE_DATES.MODIFIED,
 46 |     "url": "https://sfcc-mcp-dev.rhino-inquisitor.com/tools/",
 47 |     "mainEntity": {
 48 |       "@type": "SoftwareApplication",
 49 |       "name": "SFCC Development MCP Server",
 50 |       "applicationCategory": "DeveloperApplication",
 51 |       "operatingSystem": "Node.js",
 52 |       "description": "Interactive API reference and tools catalog",
 53 |       "offers": {
 54 |         "@type": "Offer",
 55 |         "price": "0",
 56 |         "priceCurrency": "USD",
 57 |         "availability": "https://schema.org/InStock"
 58 |       }
 59 |     }
 60 |   };
 61 | 
 62 |   return (
 63 |     <div className="max-w-7xl mx-auto px-6 py-10">
 64 |       <SEO 
 65 |         title="Available Tools & APIs"
 66 |         description="Interactive reference of SFCC Development MCP Server tools with filtering, search, examples, and quick start actions."
 67 |         keywords="SFCC MCP tools, Commerce Cloud APIs, log analysis, system objects, cartridge generation, best practices"
 68 |         canonical="/tools/"
 69 |         ogType="article"
 70 |       />
 71 |       <BreadcrumbSchema items={[
 72 |         { name: "Home", url: "/" },
 73 |         { name: "Tools", url: "/tools/" }
 74 |       ]} />
 75 |       <StructuredData data={toolsStructuredData} />
 76 |       
 77 |       {/* Hero */}
 78 |       <div className="text-center mb-14">
 79 |         <div className="inline-flex items-center gap-2 bg-gradient-to-r from-blue-600 to-purple-600 text-white px-4 py-2 rounded-full text-sm font-medium mb-6">
 80 |           <span>🛠️</span> Available Tools
 81 |         </div>
 82 |         <H1 id="available-tools" className="text-4xl md:text-5xl font-extrabold bg-gradient-to-r from-gray-900 via-blue-900 to-purple-900 bg-clip-text text-transparent mb-6">Interactive Tool Explorer</H1>
 83 |         <PageSubtitle className="text-lg md:text-xl text-gray-600 max-w-3xl mx-auto leading-relaxed">
 84 |           36+ specialized tools. Filter by category, search prompts, copy examples, and get productive in seconds.
 85 |         </PageSubtitle>
 86 |       </div>
 87 | 
 88 |       {/* Quick Actions / Popular */}
 89 |       <section className="mb-16 bg-gradient-to-r from-blue-50 via-indigo-50 to-purple-50 rounded-2xl p-6 md:p-8 shadow-xl border border-blue-100">
 90 |           <div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6 mb-6">
 91 |             <div>
 92 |               <h2 id="quick-actions" className="text-2xl font-bold text-gray-900 mb-1">🚀 Quick Actions</h2>
 93 |               <p className="text-sm text-gray-600">Most common starting points – copy and ask your AI now.</p>
 94 |             </div>
 95 |             <button onClick={() => setShowPopularExpanded(e=>!e)} className="text-xs font-medium text-blue-700 hover:text-blue-900 bg-blue-50 border border-blue-200 px-3 py-1.5 rounded-lg transition">
 96 |               {showPopularExpanded ? 'Collapse' : 'Expand'}
 97 |             </button>
 98 |           </div>
 99 |           {showPopularExpanded && (
100 |             <div className="grid sm:grid-cols-2 lg:grid-cols-2 gap-4">
101 |               {popularTools.map(tool => (
102 |                 <div key={tool.id} className="relative rounded-xl border border-gray-200 bg-white/90 p-4 shadow-sm group">
103 |                   <div className="flex items-center justify-between mb-2">
104 |                     <p className="font-mono text-xs font-semibold text-gray-800">{tool.name}</p>
105 |                     <button
106 |                       onClick={() => {
107 |                         const ex = tool.examples?.[0];
108 |                         if (ex) navigator.clipboard.writeText(ex);
109 |                       }}
110 |                       className="text-[10px] bg-gray-100 hover:bg-gray-200 text-gray-700 px-2 py-0.5 rounded transition"
111 |                     >Copy</button>
112 |                   </div>
113 |                   <p className="text-[11px] text-gray-600 line-clamp-2 group-hover:line-clamp-none transition-all">{tool.description}</p>
114 |                   {tool.examples && tool.examples.length > 0 && (
115 |                     <p className="mt-2 text-[11px] text-gray-500 italic">{tool.examples[0]}</p>
116 |                   )}
117 |                   <a href={`#${tool.id}`} className="absolute inset-0" aria-label={`Jump to ${tool.name}`}></a>
118 |                 </div>
119 |               ))}
120 |               {/* Added Hook Reference Quick Action */}
121 |               <div className="relative rounded-xl border border-amber-300 bg-gradient-to-br from-amber-50 to-orange-50 p-4 shadow-sm group">
122 |                 <div className="flex items-center justify-between mb-2">
123 |                   <p className="font-mono text-xs font-semibold text-amber-700">get_hook_reference</p>
124 |                   <button
125 |                     onClick={() => navigator.clipboard.writeText('Ask: "List available SCAPI hook extension points for product search"')}
126 |                     className="text-[10px] bg-amber-100 hover:bg-amber-200 text-amber-700 px-2 py-0.5 rounded transition"
127 |                   >Copy</button>
128 |                 </div>
129 |                 <p className="text-[11px] text-amber-800 line-clamp-2 group-hover:line-clamp-none transition-all">
130 |                   Discover all available OCAPI or SCAPI hook extension points to select the correct customization surface.
131 |                 </p>
132 |                 <p className="mt-2 text-[11px] text-amber-600 italic">Ask: "List available SCAPI hook extension points for product search"</p>
133 |                 <a href="#get_hook_reference" className="absolute inset-0" aria-label="Jump to get_hook_reference"></a>
134 |               </div>
135 |             </div>
136 |           )}
137 |       </section>
138 | 
139 |       {/* Filters */}
140 |       <div className="mb-10">
141 |         <ToolFilters activeCategory={activeCategory} setActiveCategory={setActiveCategory} search={search} setSearch={setSearch} />
142 |       </div>
143 | 
144 |       {/* Legend */}
145 |       <div className="flex flex-wrap gap-3 items-center text-[11px] text-gray-600 mb-6">
146 |         <span className="flex items-center gap-1"><span className="bg-blue-100 text-blue-700 px-2 py-0.5 rounded-full font-semibold">Full</span> Requires credentials</span>
147 |         <span className="flex items-center gap-1"><span className="bg-gradient-to-r from-blue-600 to-purple-600 text-white px-2 py-0.5 rounded-full font-semibold">Docs + Full</span> Both modes</span>
148 |       </div>
149 | 
150 |       {/* Results */}
151 |       <div className="space-y-14">
152 |         {filtered.length === 0 && (
153 |           <div className="text-center py-16 border border-dashed border-gray-300 rounded-xl">
154 |             <p className="text-sm text-gray-600 mb-4">No tools match that search.</p>
155 |             <p className="text-xs text-gray-500">Tip: Try a simpler keyword like <strong>log</strong>, <strong>class</strong>, or <strong>version</strong>.</p>
156 |           </div>
157 |         )}
158 |         {filtered.length > 0 && (
159 |           <div className="grid md:grid-cols-2 xl:grid-cols-2 gap-5">
160 |             {filtered.map(tool => <ToolCard key={tool.id} tool={tool} />)}
161 |           </div>
162 |         )}
163 |       </div>
164 | 
165 |       {/* Getting Started Hint */}
166 |       <div className="mt-20 bg-blue-50 border border-blue-200 rounded-xl p-6">
167 |         <h3 className="text-sm font-semibold text-blue-800 mb-2">💡 Mode Recommendation</h3>
168 |   <p className="text-xs text-blue-800 leading-relaxed">Explore freely in Documentation Mode first. Add <code className="font-mono bg-blue-100 px-1 py-0.5 rounded">--dw-json</code> later to unlock log analysis, system & custom object exploration, job log insights, and code version management without changing any other configuration.</p>
169 |       </div>
170 | 
171 |       {/* Next Steps */}
172 |       <section className="mt-24 mb-12 text-center" aria-labelledby="next-steps">
173 |         <h2 id="next-steps" className="text-2xl md:text-3xl font-bold text-gray-900 mb-4">🔗 Next Steps</h2>
174 |         <p className="text-sm md:text-base text-gray-600 max-w-2xl mx-auto mb-8">Move from raw tool surface into practical flows or reinforce secure patterns before enabling full-mode capabilities.</p>
175 |         <div className="flex flex-col sm:flex-row gap-4 justify-center mb-10">
176 |           <NavLink
177 |             to="/examples/"
178 |             className="group bg-gradient-to-r from-blue-600 to-purple-600 text-white px-8 py-4 rounded-xl font-semibold text-lg shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1 no-underline hover:no-underline focus:no-underline"
179 |           >
180 |             Examples & Use Cases
181 |             <span className="ml-2 group-hover:translate-x-1 inline-block transition-transform">→</span>
182 |           </NavLink>
183 |           <NavLink
184 |             to="/security/"
185 |             className="border-2 border-gray-300 text-gray-700 px-8 py-4 rounded-xl font-semibold text-lg hover:border-blue-500 hover:text-blue-600 transition-all duration-300 no-underline hover:no-underline focus:no-underline"
186 |           >
187 |             Security Guidance
188 |           </NavLink>
189 |         </div>
190 |         <div className="grid md:grid-cols-2 gap-6 max-w-4xl mx-auto mb-4 text-left">
191 |           <div className="rounded-xl border border-gray-200 bg-white p-5">
192 |             <h3 className="font-semibold text-sm mb-2">Why start with examples?</h3>
193 |             <p className="text-xs text-gray-600">Shortens prompt iteration by showing multi-step sequences that combine docs lookup, log inspection, and object introspection.</p>
194 |           </div>
195 |           <div className="rounded-xl border border-blue-200 bg-blue-50 p-5">
196 |             <h3 className="font-semibold text-sm mb-2 text-blue-800">Why review security now?</h3>
197 |             <p className="text-xs text-blue-700">Prevents leaking credentials, encourages safe log handling, and sets a baseline for principle-of-least-privilege tokens before automation.</p>
198 |           </div>
199 |         </div>
200 |       </section>
201 |     </div>
202 |   );
203 | };
204 | 
205 | export default ToolsPage;
206 | 
```

--------------------------------------------------------------------------------
/docs/dw_order/GiftCertificate.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.order
  2 | 
  3 | # Class GiftCertificate
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.object.PersistentObject
  9 |   - dw.object.ExtensibleObject
 10 |     - dw.order.GiftCertificate
 11 | 
 12 | ## Description
 13 | 
 14 | Represents a Gift Certificate that can be used to purchase products.
 15 | 
 16 | ## Constants
 17 | 
 18 | ### STATUS_ISSUED
 19 | 
 20 | **Type:** Number = 1
 21 | 
 22 | Represents a status of 'issued', which indicates that the Gift Certificate has been created and that it can be used to purchase products.
 23 | 
 24 | ### STATUS_PARTIALLY_REDEEMED
 25 | 
 26 | **Type:** Number = 2
 27 | 
 28 | Represents a status of 'partially redeemed', which indicates that the Gift Certificate has been used to purchase products, but that there is still a balance on the gift certificate.
 29 | 
 30 | ### STATUS_PENDING
 31 | 
 32 | **Type:** Number = 0
 33 | 
 34 | Represents a status of 'pending', which indicates that the Gift Certificate has been created but that it cannot be used yet.
 35 | 
 36 | ### STATUS_REDEEMED
 37 | 
 38 | **Type:** Number = 3
 39 | 
 40 | Represents a status of 'redeemed', which indicates that the Gift Certificate has been used and no longer contains a balance.
 41 | 
 42 | ## Properties
 43 | 
 44 | ### amount
 45 | 
 46 | **Type:** Money (Read Only)
 47 | 
 48 | The original amount on the gift certificate.
 49 | 
 50 | ### balance
 51 | 
 52 | **Type:** Money (Read Only)
 53 | 
 54 | The balance on the gift certificate.
 55 | 
 56 | ### description
 57 | 
 58 | **Type:** String
 59 | 
 60 | The description string.
 61 | 
 62 | ### enabled
 63 | 
 64 | **Type:** boolean
 65 | 
 66 | Returns true if the Gift Certificate is enabled, false otherwise.
 67 | 
 68 | ### giftCertificateCode
 69 | 
 70 | **Type:** String (Read Only)
 71 | 
 72 | The code of the gift certificate. This redemption code is send to
 73 |  gift certificate recipient.
 74 | 
 75 | ### ID
 76 | 
 77 | **Type:** String (Read Only)
 78 | 
 79 | The code of the gift certificate. This redemption code is send to
 80 |  gift certificate recipient.
 81 | 
 82 | ### maskedGiftCertificateCode
 83 | 
 84 | **Type:** String (Read Only)
 85 | 
 86 | The masked gift certificate code with
 87 |  all but the last 4 characters replaced with a '*' character.
 88 | 
 89 | ### merchantID
 90 | 
 91 | **Type:** String (Read Only)
 92 | 
 93 | The merchant ID of the gift certificate.
 94 | 
 95 | ### message
 96 | 
 97 | **Type:** String
 98 | 
 99 | The message to include in the email of the person receiving
100 |  the gift certificate.
101 | 
102 | ### orderNo
103 | 
104 | **Type:** String
105 | 
106 | The order number
107 | 
108 | ### recipientEmail
109 | 
110 | **Type:** String
111 | 
112 | The email address of the person receiving
113 |  the gift certificate.
114 | 
115 | ### recipientName
116 | 
117 | **Type:** String
118 | 
119 | The name of the person receiving
120 |  the gift certificate.
121 | 
122 | ### senderName
123 | 
124 | **Type:** String
125 | 
126 | The name of the person or organization that
127 |  sent the gift certificate or null if undefined.
128 | 
129 | ### status
130 | 
131 | **Type:** Number
132 | 
133 | The status where the possible values are
134 |  STATUS_PENDING, STATUS_ISSUED, STATUS_PARTIALLY_REDEEMED
135 |  or STATUS_REDEEMED.
136 | 
137 | ## Constructor Summary
138 | 
139 | ## Method Summary
140 | 
141 | ### getAmount
142 | 
143 | **Signature:** `getAmount() : Money`
144 | 
145 | Returns the original amount on the gift certificate.
146 | 
147 | ### getBalance
148 | 
149 | **Signature:** `getBalance() : Money`
150 | 
151 | Returns the balance on the gift certificate.
152 | 
153 | ### getDescription
154 | 
155 | **Signature:** `getDescription() : String`
156 | 
157 | Returns the description string.
158 | 
159 | ### getGiftCertificateCode
160 | 
161 | **Signature:** `getGiftCertificateCode() : String`
162 | 
163 | Returns the code of the gift certificate.
164 | 
165 | ### getID
166 | 
167 | **Signature:** `getID() : String`
168 | 
169 | Returns the code of the gift certificate.
170 | 
171 | ### getMaskedGiftCertificateCode
172 | 
173 | **Signature:** `getMaskedGiftCertificateCode() : String`
174 | 
175 | Returns the masked gift certificate code with all but the last 4 characters replaced with a '*' character.
176 | 
177 | ### getMaskedGiftCertificateCode
178 | 
179 | **Signature:** `getMaskedGiftCertificateCode(ignore : Number) : String`
180 | 
181 | Returns the masked gift certificate code with all but the specified number of characters replaced with a '*' character.
182 | 
183 | ### getMerchantID
184 | 
185 | **Signature:** `getMerchantID() : String`
186 | 
187 | Returns the merchant ID of the gift certificate.
188 | 
189 | ### getMessage
190 | 
191 | **Signature:** `getMessage() : String`
192 | 
193 | Returns the message to include in the email of the person receiving the gift certificate.
194 | 
195 | ### getOrderNo
196 | 
197 | **Signature:** `getOrderNo() : String`
198 | 
199 | Returns the order number
200 | 
201 | ### getRecipientEmail
202 | 
203 | **Signature:** `getRecipientEmail() : String`
204 | 
205 | Returns the email address of the person receiving the gift certificate.
206 | 
207 | ### getRecipientName
208 | 
209 | **Signature:** `getRecipientName() : String`
210 | 
211 | Returns the name of the person receiving the gift certificate.
212 | 
213 | ### getSenderName
214 | 
215 | **Signature:** `getSenderName() : String`
216 | 
217 | Returns the name of the person or organization that sent the gift certificate or null if undefined.
218 | 
219 | ### getStatus
220 | 
221 | **Signature:** `getStatus() : Number`
222 | 
223 | Returns the status where the possible values are STATUS_PENDING, STATUS_ISSUED, STATUS_PARTIALLY_REDEEMED or STATUS_REDEEMED.
224 | 
225 | ### isEnabled
226 | 
227 | **Signature:** `isEnabled() : boolean`
228 | 
229 | Returns true if the Gift Certificate is enabled, false otherwise.
230 | 
231 | ### setDescription
232 | 
233 | **Signature:** `setDescription(description : String) : void`
234 | 
235 | An optional description that you can use to categorize the gift certificate.
236 | 
237 | ### setEnabled
238 | 
239 | **Signature:** `setEnabled(enabled : boolean) : void`
240 | 
241 | Controls if the Gift Certificate is enabled.
242 | 
243 | ### setMessage
244 | 
245 | **Signature:** `setMessage(message : String) : void`
246 | 
247 | Sets the message to include in the email of the person receiving the gift certificate.
248 | 
249 | ### setOrderNo
250 | 
251 | **Signature:** `setOrderNo(orderNo : String) : void`
252 | 
253 | Sets the order number
254 | 
255 | ### setRecipientEmail
256 | 
257 | **Signature:** `setRecipientEmail(recipientEmail : String) : void`
258 | 
259 | Sets the email address of the person receiving the gift certificate.
260 | 
261 | ### setRecipientName
262 | 
263 | **Signature:** `setRecipientName(recipient : String) : void`
264 | 
265 | Sets the name of the person receiving the gift certificate.
266 | 
267 | ### setSenderName
268 | 
269 | **Signature:** `setSenderName(sender : String) : void`
270 | 
271 | Sets the name of the person or organization that sent the gift certificate.
272 | 
273 | ### setStatus
274 | 
275 | **Signature:** `setStatus(status : Number) : void`
276 | 
277 | Sets the status of the gift certificate.
278 | 
279 | ## Method Detail
280 | 
281 | ## Method Details
282 | 
283 | ### getAmount
284 | 
285 | **Signature:** `getAmount() : Money`
286 | 
287 | **Description:** Returns the original amount on the gift certificate.
288 | 
289 | **Returns:**
290 | 
291 | the original amount on the gift certificate.
292 | 
293 | ---
294 | 
295 | ### getBalance
296 | 
297 | **Signature:** `getBalance() : Money`
298 | 
299 | **Description:** Returns the balance on the gift certificate.
300 | 
301 | **Returns:**
302 | 
303 | the balance on the gift certificate.
304 | 
305 | ---
306 | 
307 | ### getDescription
308 | 
309 | **Signature:** `getDescription() : String`
310 | 
311 | **Description:** Returns the description string.
312 | 
313 | **Returns:**
314 | 
315 | the description.
316 | 
317 | ---
318 | 
319 | ### getGiftCertificateCode
320 | 
321 | **Signature:** `getGiftCertificateCode() : String`
322 | 
323 | **Description:** Returns the code of the gift certificate. This redemption code is send to gift certificate recipient.
324 | 
325 | **Returns:**
326 | 
327 | the code of the gift certificate.
328 | 
329 | ---
330 | 
331 | ### getID
332 | 
333 | **Signature:** `getID() : String`
334 | 
335 | **Description:** Returns the code of the gift certificate. This redemption code is send to gift certificate recipient.
336 | 
337 | **Deprecated:**
338 | 
339 | Use getGiftCertificateCode()
340 | 
341 | **Returns:**
342 | 
343 | the code of the gift certificate.
344 | 
345 | ---
346 | 
347 | ### getMaskedGiftCertificateCode
348 | 
349 | **Signature:** `getMaskedGiftCertificateCode() : String`
350 | 
351 | **Description:** Returns the masked gift certificate code with all but the last 4 characters replaced with a '*' character.
352 | 
353 | **Returns:**
354 | 
355 | the masked gift certificate code.
356 | 
357 | ---
358 | 
359 | ### getMaskedGiftCertificateCode
360 | 
361 | **Signature:** `getMaskedGiftCertificateCode(ignore : Number) : String`
362 | 
363 | **Description:** Returns the masked gift certificate code with all but the specified number of characters replaced with a '*' character.
364 | 
365 | **Parameters:**
366 | 
367 | - `ignore`: the number of characters to leave unmasked.
368 | 
369 | **Returns:**
370 | 
371 | the masked gift certificate code.
372 | 
373 | **Throws:**
374 | 
375 | IllegalArgumentException - if ignore is negative.
376 | 
377 | ---
378 | 
379 | ### getMerchantID
380 | 
381 | **Signature:** `getMerchantID() : String`
382 | 
383 | **Description:** Returns the merchant ID of the gift certificate.
384 | 
385 | **Returns:**
386 | 
387 | the merchant ID of the gift certificate.
388 | 
389 | ---
390 | 
391 | ### getMessage
392 | 
393 | **Signature:** `getMessage() : String`
394 | 
395 | **Description:** Returns the message to include in the email of the person receiving the gift certificate.
396 | 
397 | **Returns:**
398 | 
399 | the message to include in the email of the person receiving the gift certificate.
400 | 
401 | ---
402 | 
403 | ### getOrderNo
404 | 
405 | **Signature:** `getOrderNo() : String`
406 | 
407 | **Description:** Returns the order number
408 | 
409 | **Returns:**
410 | 
411 | the order number
412 | 
413 | ---
414 | 
415 | ### getRecipientEmail
416 | 
417 | **Signature:** `getRecipientEmail() : String`
418 | 
419 | **Description:** Returns the email address of the person receiving the gift certificate.
420 | 
421 | **Returns:**
422 | 
423 | the email address of the person receiving the gift certificate.
424 | 
425 | ---
426 | 
427 | ### getRecipientName
428 | 
429 | **Signature:** `getRecipientName() : String`
430 | 
431 | **Description:** Returns the name of the person receiving the gift certificate.
432 | 
433 | **Returns:**
434 | 
435 | the name of the person receiving the gift certificate.
436 | 
437 | ---
438 | 
439 | ### getSenderName
440 | 
441 | **Signature:** `getSenderName() : String`
442 | 
443 | **Description:** Returns the name of the person or organization that sent the gift certificate or null if undefined.
444 | 
445 | **Returns:**
446 | 
447 | the name of the person or organization that sent the gift certificate or null if undefined.
448 | 
449 | ---
450 | 
451 | ### getStatus
452 | 
453 | **Signature:** `getStatus() : Number`
454 | 
455 | **Description:** Returns the status where the possible values are STATUS_PENDING, STATUS_ISSUED, STATUS_PARTIALLY_REDEEMED or STATUS_REDEEMED.
456 | 
457 | **Returns:**
458 | 
459 | the status.
460 | 
461 | ---
462 | 
463 | ### isEnabled
464 | 
465 | **Signature:** `isEnabled() : boolean`
466 | 
467 | **Description:** Returns true if the Gift Certificate is enabled, false otherwise.
468 | 
469 | **Returns:**
470 | 
471 | true if the Gift Certificate is enabled, false otherwise.
472 | 
473 | ---
474 | 
475 | ### setDescription
476 | 
477 | **Signature:** `setDescription(description : String) : void`
478 | 
479 | **Description:** An optional description that you can use to categorize the gift certificate.
480 | 
481 | **Parameters:**
482 | 
483 | - `description`: additional description.
484 | 
485 | ---
486 | 
487 | ### setEnabled
488 | 
489 | **Signature:** `setEnabled(enabled : boolean) : void`
490 | 
491 | **Description:** Controls if the Gift Certificate is enabled.
492 | 
493 | **Parameters:**
494 | 
495 | - `enabled`: if true, enables the Gift Certificate.
496 | 
497 | ---
498 | 
499 | ### setMessage
500 | 
501 | **Signature:** `setMessage(message : String) : void`
502 | 
503 | **Description:** Sets the message to include in the email of the person receiving the gift certificate.
504 | 
505 | **Parameters:**
506 | 
507 | - `message`: the message to include in the email of the person receiving the gift certificate.
508 | 
509 | ---
510 | 
511 | ### setOrderNo
512 | 
513 | **Signature:** `setOrderNo(orderNo : String) : void`
514 | 
515 | **Description:** Sets the order number
516 | 
517 | **Parameters:**
518 | 
519 | - `orderNo`: the order number to be set
520 | 
521 | ---
522 | 
523 | ### setRecipientEmail
524 | 
525 | **Signature:** `setRecipientEmail(recipientEmail : String) : void`
526 | 
527 | **Description:** Sets the email address of the person receiving the gift certificate.
528 | 
529 | **Parameters:**
530 | 
531 | - `recipientEmail`: the email address of the person receiving the gift certificate.
532 | 
533 | ---
534 | 
535 | ### setRecipientName
536 | 
537 | **Signature:** `setRecipientName(recipient : String) : void`
538 | 
539 | **Description:** Sets the name of the person receiving the gift certificate.
540 | 
541 | **Parameters:**
542 | 
543 | - `recipient`: the name of the person receiving the gift certificate.
544 | 
545 | ---
546 | 
547 | ### setSenderName
548 | 
549 | **Signature:** `setSenderName(sender : String) : void`
550 | 
551 | **Description:** Sets the name of the person or organization that sent the gift certificate.
552 | 
553 | **Parameters:**
554 | 
555 | - `sender`: the name of the person or organization that sent the gift certificate.
556 | 
557 | ---
558 | 
559 | ### setStatus
560 | 
561 | **Signature:** `setStatus(status : Number) : void`
562 | 
563 | **Description:** Sets the status of the gift certificate. Possible values are: STATUS_ISSUED, STATUS_PENDING, STATUS_PARTIALLY_REDEEMED and STATUS_REDEEMED.
564 | 
565 | **Parameters:**
566 | 
567 | - `status`: Gift certificate status
568 | 
569 | ---
```

--------------------------------------------------------------------------------
/src/clients/docs-client.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * SFCC Documentation Client (Refactored)
  3 |  *
  4 |  * This module provides functionality to query and retrieve SFCC class documentation
  5 |  * from converted Markdown files. It orchestrates specialized modules to handle
  6 |  * different aspects of documentation processing.
  7 |  *
  8 |  * Responsibilities:
  9 |  * - Orchestrating specialized modules
 10 |  * - Managing initialization and caching
 11 |  * - Providing public API for documentation access
 12 |  * - Applying filters and search functionality
 13 |  */
 14 | 
 15 | import { PathResolver } from '../utils/path-resolver.js';
 16 | import { CacheManager } from '../utils/cache.js';
 17 | import { Logger } from '../utils/logger.js';
 18 | import { DocumentationScanner, SFCCClassInfo } from './docs/documentation-scanner.js';
 19 | import { ClassContentParser, SFCCClassDetails, SFCCMethod } from './docs/class-content-parser.js';
 20 | import { ClassNameResolver } from './docs/class-name-resolver.js';
 21 | import { ReferencedTypesExtractor } from './docs/referenced-types-extractor.js';
 22 | 
 23 | // Re-export types for backward compatibility
 24 | export { SFCCClassInfo, SFCCMethod, SFCCClassDetails };
 25 | export type { SFCCProperty, SFCCConstant } from './docs/class-content-parser.js';
 26 | 
 27 | export interface ClassDetailsFilterOptions {
 28 |   includeDescription?: boolean;
 29 |   includeConstants?: boolean;
 30 |   includeProperties?: boolean;
 31 |   includeMethods?: boolean;
 32 |   includeInheritance?: boolean;
 33 |   search?: string;
 34 | }
 35 | 
 36 | export class SFCCDocumentationClient {
 37 |   private docsPath: string;
 38 |   private classCache: Map<string, SFCCClassInfo> = new Map();
 39 |   private cacheManager: CacheManager;
 40 |   private initialized = false;
 41 |   private logger: Logger;
 42 |   private documentationScanner: DocumentationScanner;
 43 |   private classContentParser: ClassContentParser;
 44 | 
 45 |   constructor() {
 46 |     this.docsPath = PathResolver.getDocsPath();
 47 |     this.cacheManager = new CacheManager();
 48 |     this.logger = Logger.getChildLogger('DocsClient');
 49 |     this.documentationScanner = new DocumentationScanner();
 50 |     this.classContentParser = new ClassContentParser();
 51 |   }
 52 | 
 53 |   /**
 54 |    * Initialize the documentation client by scanning all available classes
 55 |    */
 56 |   async initialize(): Promise<void> {
 57 |     if (this.initialized) {
 58 |       return;
 59 |     }
 60 | 
 61 |     try {
 62 |       this.classCache = await this.documentationScanner.scanDocumentation(this.docsPath);
 63 |       this.initialized = true;
 64 |     } catch (error) {
 65 |       throw new Error(`Failed to initialize SFCC documentation: ${error}`);
 66 |     }
 67 |   }
 68 | 
 69 |   /**
 70 |    * Get a list of all available SFCC classes
 71 |    */
 72 |   async getAvailableClasses(): Promise<string[]> {
 73 |     await this.initialize();
 74 |     return Array.from(this.classCache.keys())
 75 |       .sort()
 76 |       .map(className => ClassNameResolver.toOfficialFormat(className));
 77 |   }
 78 | 
 79 |   /**
 80 |    * Search for classes by name (partial matching)
 81 |    */
 82 |   async searchClasses(query: string): Promise<string[]> {
 83 |     await this.initialize();
 84 | 
 85 |     // Check cache first
 86 |     const cacheKey = `search:classes:${query.toLowerCase()}`;
 87 |     const cachedResult = this.cacheManager.getSearchResults(cacheKey);
 88 |     if (cachedResult) {
 89 |       return cachedResult;
 90 |     }
 91 | 
 92 |     const lowercaseQuery = query.toLowerCase();
 93 |     const results = Array.from(this.classCache.keys())
 94 |       .filter(className => className.toLowerCase().includes(lowercaseQuery))
 95 |       .sort()
 96 |       .map(className => ClassNameResolver.toOfficialFormat(className));
 97 | 
 98 |     // Cache the results
 99 |     this.cacheManager.setSearchResults(cacheKey, results);
100 |     return results;
101 |   }
102 | 
103 |   /**
104 |    * Get the raw documentation content for a class
105 |    */
106 |   async getClassDocumentation(className: string): Promise<string | null> {
107 |     await this.initialize();
108 | 
109 |     // Check cache first
110 |     const normalizedClassName = ClassNameResolver.normalizeClassName(className);
111 |     const cacheKey = `content:${normalizedClassName}`;
112 |     const cachedContent = this.cacheManager.getFileContent(cacheKey);
113 |     if (cachedContent !== undefined) {
114 |       return cachedContent || null;
115 |     }
116 | 
117 |     // Resolve class name with fallback logic
118 |     const resolved = ClassNameResolver.resolveClassName(normalizedClassName, this.classCache);
119 |     const content = resolved ? resolved.info.content : null;
120 | 
121 |     // Cache the result (including null results to avoid repeated lookups)
122 |     this.cacheManager.setFileContent(cacheKey, content ?? '');
123 | 
124 |     return content;
125 |   }
126 | 
127 |   /**
128 |    * Parse class documentation and extract structured information
129 |    */
130 |   async getClassDetails(className: string): Promise<SFCCClassDetails | null> {
131 |     // Check cache first
132 |     const cacheKey = `details:${className}`;
133 |     const cachedDetails = this.cacheManager.getClassDetails(cacheKey);
134 |     if (cachedDetails !== undefined) {
135 |       return cachedDetails;
136 |     }
137 | 
138 |     const content = await this.getClassDocumentation(className);
139 |     if (!content) {
140 |       // Cache null results to avoid repeated parsing attempts
141 |       this.cacheManager.setClassDetails(cacheKey, null);
142 |       return null;
143 |     }
144 | 
145 |     const details = this.classContentParser.parseClassContent(content);
146 | 
147 |     // Cache the parsed details
148 |     this.cacheManager.setClassDetails(cacheKey, details);
149 | 
150 |     return details;
151 |   }
152 | 
153 |   /**
154 |    * Get class details with optional expansion of referenced types and filtering
155 |    */
156 |   async getClassDetailsExpanded(
157 |     className: string,
158 |     expand: boolean = false,
159 |     filterOptions?: ClassDetailsFilterOptions,
160 |   ): Promise<SFCCClassDetails & { referencedTypes?: SFCCClassDetails[] } | null> {
161 |     // Set default filter options
162 |     const filters = {
163 |       includeDescription: filterOptions?.includeDescription ?? true,
164 |       includeConstants: filterOptions?.includeConstants ?? true,
165 |       includeProperties: filterOptions?.includeProperties ?? true,
166 |       includeMethods: filterOptions?.includeMethods ?? true,
167 |       includeInheritance: filterOptions?.includeInheritance ?? true,
168 |       search: filterOptions?.search,
169 |     };
170 | 
171 |     // Check cache first for expanded details with filter options
172 |     const cacheKey = `details-expanded:${className}:${expand}:${JSON.stringify(filters)}`;
173 |     const cachedResult = this.cacheManager.getClassDetails(cacheKey);
174 |     if (cachedResult !== undefined) {
175 |       return cachedResult;
176 |     }
177 | 
178 |     const classDetails = await this.getClassDetails(className);
179 |     if (!classDetails) {
180 |       this.cacheManager.setClassDetails(cacheKey, null);
181 |       return null;
182 |     }
183 | 
184 |     // Apply filtering and search to the class details
185 |     const filteredDetails = this.applyFiltersAndSearch(classDetails, filters);
186 | 
187 |     if (!expand) {
188 |       this.cacheManager.setClassDetails(cacheKey, filteredDetails);
189 |       return filteredDetails;
190 |     }
191 | 
192 |     // Get the raw content to extract referenced types
193 |     const content = await this.getClassDocumentation(className);
194 |     if (!content) {
195 |       this.cacheManager.setClassDetails(cacheKey, filteredDetails);
196 |       return filteredDetails;
197 |     }
198 | 
199 |     const referencedTypeNames = ReferencedTypesExtractor.extractFilteredReferencedTypes(content, className);
200 |     const referencedTypes: SFCCClassDetails[] = [];
201 | 
202 |     // Get details for each referenced type
203 |     for (const typeName of referencedTypeNames) {
204 |       try {
205 |         const typeDetails = await this.getClassDetails(typeName);
206 |         if (typeDetails) {
207 |           referencedTypes.push(typeDetails);
208 |         }
209 |       } catch {
210 |         // Silently skip types that can't be found
211 |         this.logger.warn(`Could not find details for referenced type: ${typeName}`);
212 |       }
213 |     }
214 | 
215 |     const result = {
216 |       ...filteredDetails,
217 |       referencedTypes: referencedTypes.length > 0 ? referencedTypes : undefined,
218 |     };
219 | 
220 |     // Cache the result
221 |     this.cacheManager.setClassDetails(cacheKey, result);
222 | 
223 |     return result;
224 |   }
225 | 
226 |   /**
227 |    * Apply filters and search to class details
228 |    */
229 |   private applyFiltersAndSearch(
230 |     classDetails: SFCCClassDetails,
231 |     filters: {
232 |       includeDescription: boolean;
233 |       includeConstants: boolean;
234 |       includeProperties: boolean;
235 |       includeMethods: boolean;
236 |       includeInheritance: boolean;
237 |       search?: string;
238 |     },
239 |   ): SFCCClassDetails {
240 |     const result: SFCCClassDetails = {
241 |       className: classDetails.className,
242 |       packageName: classDetails.packageName,
243 |       description: filters.includeDescription ? classDetails.description : '',
244 |       constants: [],
245 |       properties: [],
246 |       methods: [],
247 |       inheritance: filters.includeInheritance ? classDetails.inheritance : undefined,
248 |       constructorInfo: classDetails.constructorInfo,
249 |     };
250 | 
251 |     // Apply search filter to constants
252 |     if (filters.includeConstants) {
253 |       result.constants = filters.search
254 |         ? classDetails.constants.filter(constant =>
255 |           this.matchesSearch(constant.name, constant.description, filters.search!),
256 |         )
257 |         : classDetails.constants;
258 |     }
259 | 
260 |     // Apply search filter to properties
261 |     if (filters.includeProperties) {
262 |       result.properties = filters.search
263 |         ? classDetails.properties.filter(property =>
264 |           this.matchesSearch(property.name, property.description, filters.search!),
265 |         )
266 |         : classDetails.properties;
267 |     }
268 | 
269 |     // Apply search filter to methods
270 |     if (filters.includeMethods) {
271 |       result.methods = filters.search
272 |         ? classDetails.methods.filter(method =>
273 |           this.matchesSearch(method.name, method.description, filters.search!) ||
274 |           this.matchesSearch(method.signature, '', filters.search!),
275 |         )
276 |         : classDetails.methods;
277 |     }
278 | 
279 |     // Apply search filter to inheritance
280 |     if (filters.includeInheritance && filters.search && result.inheritance) {
281 |       result.inheritance = result.inheritance.filter(inheritanceItem =>
282 |         this.matchesSearch(inheritanceItem, '', filters.search!),
283 |       );
284 |     }
285 | 
286 |     return result;
287 |   }
288 | 
289 |   /**
290 |    * Check if a name or description matches the search term (case-insensitive)
291 |    */
292 |   private matchesSearch(name: string, description: string, searchTerm: string): boolean {
293 |     const search = searchTerm.toLowerCase();
294 |     return (
295 |       name.toLowerCase().includes(search) ||
296 |       description.toLowerCase().includes(search)
297 |     );
298 |   }
299 | 
300 |   /**
301 |    * Search for methods across all classes
302 |    */
303 |   async searchMethods(methodName: string): Promise<{ className: string; method: SFCCMethod }[]> {
304 |     await this.initialize();
305 | 
306 |     // Check cache first
307 |     const cacheKey = `search:methods:${methodName.toLowerCase()}`;
308 |     const cachedResult = this.cacheManager.getMethodSearch(cacheKey);
309 |     if (cachedResult) {
310 |       return cachedResult;
311 |     }
312 | 
313 |     const results: { className: string; method: SFCCMethod }[] = [];
314 | 
315 |     for (const [fullClassName] of this.classCache) {
316 |       const details = await this.getClassDetails(fullClassName);
317 |       const methods = details?.methods ?? [];
318 |       for (const method of methods) {
319 |         if (method.name.toLowerCase().includes(methodName.toLowerCase())) {
320 |           results.push({
321 |             className: fullClassName,
322 |             method,
323 |           });
324 |         }
325 |       }
326 |     }
327 | 
328 |     // Cache the search results
329 |     this.cacheManager.setMethodSearch(cacheKey, results);
330 |     return results;
331 |   }
332 | 
333 |   /**
334 |    * Get cache statistics for monitoring performance
335 |    */
336 |   getCacheStats(): ReturnType<CacheManager['getAllStats']> {
337 |     return this.cacheManager.getAllStats();
338 |   }
339 | 
340 |   /**
341 |    * Clear all caches
342 |    */
343 |   clearCache(): void {
344 |     this.cacheManager.clearAll();
345 |   }
346 | 
347 |   /**
348 |    * Cleanup resources and destroy caches
349 |    */
350 |   destroy(): void {
351 |     this.cacheManager.destroy();
352 |   }
353 | }
354 | 
```

--------------------------------------------------------------------------------
/docs/dw_campaign/PromotionPlan.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Package: dw.campaign
  2 | 
  3 | # Class PromotionPlan
  4 | 
  5 | ## Inheritance Hierarchy
  6 | 
  7 | - Object
  8 |   - dw.campaign.PromotionPlan
  9 | 
 10 | ## Description
 11 | 
 12 | PromotionPlan represents a set of Promotion instances and is used to display active or upcoming promotions on storefront pages, or to pass it to the PromotionMgr to calculate a DiscountPlan and subsequently apply discounts to a line item container. Instances of the class are returned by the PromotionMgr.getActivePromotions(), PromotionMgr.getActiveCustomerPromotions() and PromotionMgr.getUpcomingPromotions(Number). PromotionPlan provides methods to access the promotions in the plan and to remove promotions from the plan. All methods which return a collection of promotions sort them by the following ordered criteria: Exclusivity: GLOBAL exclusive promotions first, followed by CLASS exclusive promotions, and NO exclusive promotions last. Rank: sorted ascending Promotion Class: PRODUCT promotions first, followed by ORDER promotions, and SHIPPING promotions last. Discount type: Fixed price promotions first, followed by free, amount-off, percentage-off, and bonus product promotions last. Best discount: Sorted descending. For example, 30% off comes before 20% off. ID: alphanumeric ascending.
 13 | 
 14 | ## Constants
 15 | 
 16 | ### SORT_BY_EXCLUSIVITY
 17 | 
 18 | **Type:** Number = 1
 19 | 
 20 | Constant indicating that a collection of promotions should be sorted first by exclusivity, then rank, promotion class, etc. See class-level javadoc for details. This is the default sort order for methods that return a collection of promotions.
 21 | 
 22 | ### SORT_BY_START_DATE
 23 | 
 24 | **Type:** Number = 2
 25 | 
 26 | Constant indicating that a collection of promotions should be sorted by start date ascending. If there is no explicit start date for a promotion the start date of its containing Campaign or AB-test is used instead. Promotions without a start date are sorted before promotions with a start date in the future and after promotions with a start date in the past. In case two promotion assignments have the same start date, they are sorted by their ID.
 27 | 
 28 | ## Properties
 29 | 
 30 | ### orderPromotions
 31 | 
 32 | **Type:** Collection (Read Only)
 33 | 
 34 | All order promotions contained in this plan.
 35 | 
 36 | ### productPromotions
 37 | 
 38 | **Type:** Collection (Read Only)
 39 | 
 40 | All product promotions contained in this plan.
 41 | 
 42 | ### promotions
 43 | 
 44 | **Type:** Collection (Read Only)
 45 | 
 46 | All promotions contained in this plan sorted by exclusivity.
 47 | 
 48 | ### shippingPromotions
 49 | 
 50 | **Type:** Collection (Read Only)
 51 | 
 52 | All shipping promotions contained in this plan.
 53 | 
 54 | ## Constructor Summary
 55 | 
 56 | ## Method Summary
 57 | 
 58 | ### getOrderPromotions
 59 | 
 60 | **Signature:** `getOrderPromotions() : Collection`
 61 | 
 62 | Returns all order promotions contained in this plan.
 63 | 
 64 | ### getPaymentCardPromotions
 65 | 
 66 | **Signature:** `getPaymentCardPromotions(paymentCard : PaymentCard) : Collection`
 67 | 
 68 | Returns the order promotions explicitly associated to the specified discounted payment card.
 69 | 
 70 | ### getPaymentMethodPromotions
 71 | 
 72 | **Signature:** `getPaymentMethodPromotions(paymentMethod : PaymentMethod) : Collection`
 73 | 
 74 | Returns the order promotions explicitly associated to the specified discounted payment method.
 75 | 
 76 | ### getProductPromotions
 77 | 
 78 | **Signature:** `getProductPromotions() : Collection`
 79 | 
 80 | Returns all product promotions contained in this plan.
 81 | 
 82 | ### getProductPromotions
 83 | 
 84 | **Signature:** `getProductPromotions(product : Product) : Collection`
 85 | 
 86 | Returns the promotions related to the specified product.
 87 | 
 88 | ### getProductPromotionsForDiscountedProduct
 89 | 
 90 | **Signature:** `getProductPromotionsForDiscountedProduct(product : Product) : Collection`
 91 | 
 92 | Returns the product promotions for which the specified product is a discounted (and possibly also a qualifying) product.
 93 | 
 94 | ### getProductPromotionsForQualifyingProduct
 95 | 
 96 | **Signature:** `getProductPromotionsForQualifyingProduct(product : Product) : Collection`
 97 | 
 98 | Returns the product promotions for which the specified product is a qualifying but NOT a discounted product.
 99 | 
100 | ### getPromotions
101 | 
102 | **Signature:** `getPromotions() : Collection`
103 | 
104 | Returns all promotions contained in this plan sorted by exclusivity.
105 | 
106 | ### getPromotions
107 | 
108 | **Signature:** `getPromotions(sortOrder : Number) : Collection`
109 | 
110 | Returns all promotions contained in this plan sorted according to the specified sort order.
111 | 
112 | ### getPromotions
113 | 
114 | **Signature:** `getPromotions(product : Product) : Collection`
115 | 
116 | Returns the promotions related to the specified product.
117 | 
118 | ### getShippingPromotions
119 | 
120 | **Signature:** `getShippingPromotions() : Collection`
121 | 
122 | Returns all shipping promotions contained in this plan.
123 | 
124 | ### getShippingPromotions
125 | 
126 | **Signature:** `getShippingPromotions(shippingMethod : ShippingMethod) : Collection`
127 | 
128 | Returns the shipping promotions related to the specified discounted shipping method, i.e.
129 | 
130 | ### removePromotion
131 | 
132 | **Signature:** `removePromotion(promotion : Promotion) : void`
133 | 
134 | Remove promotion from promotion plan.
135 | 
136 | ## Method Detail
137 | 
138 | ## Method Details
139 | 
140 | ### getOrderPromotions
141 | 
142 | **Signature:** `getOrderPromotions() : Collection`
143 | 
144 | **Description:** Returns all order promotions contained in this plan.
145 | 
146 | **Returns:**
147 | 
148 | The sorted collection of order promotions contained in the promotion plan.
149 | 
150 | ---
151 | 
152 | ### getPaymentCardPromotions
153 | 
154 | **Signature:** `getPaymentCardPromotions(paymentCard : PaymentCard) : Collection`
155 | 
156 | **Description:** Returns the order promotions explicitly associated to the specified discounted payment card. This method is usually used to display order promotions along with payment card choices.
157 | 
158 | **Parameters:**
159 | 
160 | - `paymentCard`: Discounted payment card
161 | 
162 | **Returns:**
163 | 
164 | The sorted collection of order promotions associated with the specified payment card.
165 | 
166 | ---
167 | 
168 | ### getPaymentMethodPromotions
169 | 
170 | **Signature:** `getPaymentMethodPromotions(paymentMethod : PaymentMethod) : Collection`
171 | 
172 | **Description:** Returns the order promotions explicitly associated to the specified discounted payment method. This method is usually used to display order promotions along with payment method choices.
173 | 
174 | **Parameters:**
175 | 
176 | - `paymentMethod`: Discounted payment method
177 | 
178 | **Returns:**
179 | 
180 | The sorted collection of order promotions associated with the specified payment method.
181 | 
182 | ---
183 | 
184 | ### getProductPromotions
185 | 
186 | **Signature:** `getProductPromotions() : Collection`
187 | 
188 | **Description:** Returns all product promotions contained in this plan.
189 | 
190 | **Returns:**
191 | 
192 | The sorted collection of product promotions contained in the promotion plan.
193 | 
194 | ---
195 | 
196 | ### getProductPromotions
197 | 
198 | **Signature:** `getProductPromotions(product : Product) : Collection`
199 | 
200 | **Description:** Returns the promotions related to the specified product. The method returns all promotions where the product is either a qualifying product, or a discounted product, or both. It also returns promotions where the specified product is a bonus product. This method is usually used to display product promotions on a product details page. If a master product is passed, then this method will return promotions which are relevant for the master itself or at least one of its variants.
201 | 
202 | **Parameters:**
203 | 
204 | - `product`: Product associated with promotion
205 | 
206 | **Returns:**
207 | 
208 | The sorted collection of promotions related to specified discounted product.
209 | 
210 | ---
211 | 
212 | ### getProductPromotionsForDiscountedProduct
213 | 
214 | **Signature:** `getProductPromotionsForDiscountedProduct(product : Product) : Collection`
215 | 
216 | **Description:** Returns the product promotions for which the specified product is a discounted (and possibly also a qualifying) product. It also returns promotions where the specified product is a bonus product. This method is usually used to display product promotions on a product details page when separate callout messages are defined depending on if the product is a qualifying or discounted product for the promotion. If a master product is passed, then this method will return promotions for which the master product itself or at least one of its product's variants is a discounted product.
217 | 
218 | **Parameters:**
219 | 
220 | - `product`: The discounted product.
221 | 
222 | **Returns:**
223 | 
224 | Product promotions related to the specified discounted product.
225 | 
226 | ---
227 | 
228 | ### getProductPromotionsForQualifyingProduct
229 | 
230 | **Signature:** `getProductPromotionsForQualifyingProduct(product : Product) : Collection`
231 | 
232 | **Description:** Returns the product promotions for which the specified product is a qualifying but NOT a discounted product. This method is usually used to display product promotions on a product details page when separate callout messages are defined depending on if the product is a qualifying or discounted product for the promotion. If a master product is passed, then this method will return promotions for which the master product itself or at least one of its product's variants is a qualifying product.
233 | 
234 | **Parameters:**
235 | 
236 | - `product`: The qualifying product.
237 | 
238 | **Returns:**
239 | 
240 | Product promotions related to the specified qualifying product.
241 | 
242 | ---
243 | 
244 | ### getPromotions
245 | 
246 | **Signature:** `getPromotions() : Collection`
247 | 
248 | **Description:** Returns all promotions contained in this plan sorted by exclusivity.
249 | 
250 | **Returns:**
251 | 
252 | The sorted collection of promotions contained in the promotion plan.
253 | 
254 | ---
255 | 
256 | ### getPromotions
257 | 
258 | **Signature:** `getPromotions(sortOrder : Number) : Collection`
259 | 
260 | **Description:** Returns all promotions contained in this plan sorted according to the specified sort order. If the passed sort order is invalid, then the returned promotions will be sorted by exclusivity.
261 | 
262 | **Parameters:**
263 | 
264 | - `sortOrder`: the sort order to use. Must be SORT_BY_EXCLUSIVITY or SORT_BY_START_DATE. If an invalid value is passed, SORT_BY_EXCLUSIVITY is used.
265 | 
266 | **Returns:**
267 | 
268 | The sorted collection of promotions contained in the promotion plan.
269 | 
270 | ---
271 | 
272 | ### getPromotions
273 | 
274 | **Signature:** `getPromotions(product : Product) : Collection`
275 | 
276 | **Description:** Returns the promotions related to the specified product. The method returns all promotions where the product is either a qualifying product, or a discounted product, or both. It also returns promotions where the specified product is a bonus product. This method is usually used to display product promotions on a product details page.
277 | 
278 | **Deprecated:**
279 | 
280 | Use getProductPromotions(Product)
281 | 
282 | **Parameters:**
283 | 
284 | - `product`: Product associated with promotion
285 | 
286 | **Returns:**
287 | 
288 | The sorted collection of promotions related to the specified discounted product.
289 | 
290 | ---
291 | 
292 | ### getShippingPromotions
293 | 
294 | **Signature:** `getShippingPromotions() : Collection`
295 | 
296 | **Description:** Returns all shipping promotions contained in this plan.
297 | 
298 | **Returns:**
299 | 
300 | The sorted collection of shipping promotions contained in promotion plan.
301 | 
302 | ---
303 | 
304 | ### getShippingPromotions
305 | 
306 | **Signature:** `getShippingPromotions(shippingMethod : ShippingMethod) : Collection`
307 | 
308 | **Description:** Returns the shipping promotions related to the specified discounted shipping method, i.e. the returned promotions apply a discount on the specified shipping method. This method is usually used to display shipping promotions along with shipping methods.
309 | 
310 | **Parameters:**
311 | 
312 | - `shippingMethod`: Discounted shipping method
313 | 
314 | **Returns:**
315 | 
316 | The sorted collection of shipping promotions with specified method as discounted method.
317 | 
318 | ---
319 | 
320 | ### removePromotion
321 | 
322 | **Signature:** `removePromotion(promotion : Promotion) : void`
323 | 
324 | **Description:** Remove promotion from promotion plan. Please note that this is the only way to remove promotions from the plan, i.e. removing promotions from the collections returned by methods such as getProductPromotions() has no effect on the promotion plan.
325 | 
326 | **Parameters:**
327 | 
328 | - `promotion`: Promotion to remove from promotion plan
329 | 
330 | ---
```

--------------------------------------------------------------------------------
/tests/mcp/node/get-available-sfra-documents.programmatic.test.js:
--------------------------------------------------------------------------------

```javascript
  1 | import { test, describe, before, after, beforeEach } from 'node:test';
  2 | import { strict as assert } from 'node:assert';
  3 | import { connect } from 'mcp-aegis';
  4 | 
  5 | /**
  6 |  * Programmatic tests for the MCP tool: get_available_sfra_documents
  7 |  * Mirrors YAML tests but adds deeper JSON parsing & resilience checks.
  8 |  *
  9 |  * Validates:
 10 |  * 1. Tool is registered
 11 |  * 2. Basic successful invocation returns non-empty array JSON string
 12 |  * 3. JSON parse yields objects with required keys (id, name, category, filename)
 13 |  * 4. Category coverage (expects at least: core, product, order, customer, pricing, store, other)
 14 |  * 5. Extraneous argument tolerance (should ignore unexpected params)
 15 |  * 6. Negative invalid method error path via raw JSON-RPC call
 16 |  */
 17 | 
 18 | describe('get_available_sfra_documents (programmatic)', () => {
 19 |   let client;
 20 |   const CONFIG = './aegis.config.docs-only.json';
 21 | 
 22 |   before(async () => {
 23 |     client = await connect(CONFIG);
 24 |   });
 25 | 
 26 |   after(async () => {
 27 |     if (client?.connected) await client.disconnect();
 28 |   });
 29 | 
 30 |   beforeEach(() => {
 31 |     client.clearAllBuffers(); // Recommended - comprehensive protection
 32 |   });
 33 | 
 34 |   const TOOL_NAME = 'get_available_sfra_documents';
 35 |   const REQUIRED_CATEGORIES = ['core', 'product', 'order', 'customer', 'pricing', 'store', 'other'];
 36 |   // Actual response objects do NOT include an explicit 'id' field; we validate name/category/filename
 37 |   const REQUIRED_KEYS = ['name', 'category', 'filename'];
 38 | 
 39 |   test('tool should be registered', async () => {
 40 |     const tools = await client.listTools();
 41 |     const names = tools.map(t => t.name);
 42 |     assert.ok(names.includes(TOOL_NAME), 'Tool not found in listTools');
 43 |   });
 44 | 
 45 |   async function invoke(extraArgs = {}) {
 46 |     const result = await client.callTool(TOOL_NAME, { ...extraArgs });
 47 |     assert.equal(result.isError, false, 'Tool invocation should not be error');
 48 |     assert.ok(result.content && Array.isArray(result.content) && result.content.length > 0, 'Content array expected');
 49 |     const textBlocks = result.content.filter(c => c.type === 'text');
 50 |     assert.ok(textBlocks.length > 0, 'At least one text block expected');
 51 |     const raw = textBlocks.map(t => t.text).join('\n');
 52 |     return { raw, result };
 53 |   }
 54 | 
 55 |   function safeParseDocuments(raw) {
 56 |     let docs;
 57 |     try {
 58 |       docs = JSON.parse(raw);
 59 |   } catch {
 60 |       // Attempt to extract JSON array via regex fallback if wrapping noise present
 61 |       const match = raw.match(/\[[\s\S]*\]/);
 62 |       assert.ok(match, 'Could not locate JSON array in content');
 63 |       docs = JSON.parse(match[0]);
 64 |     }
 65 |     assert.ok(Array.isArray(docs), 'Parsed docs should be array');
 66 |     assert.ok(docs.length >= 15, 'Expect at least 15 SFRA documents');
 67 |     return docs;
 68 |   }
 69 | 
 70 |   test('basic invocation returns valid JSON array with required keys', async () => {
 71 |     const { raw } = await invoke();
 72 |     const docs = safeParseDocuments(raw);
 73 |     // Validate keys & reasonable string values
 74 |     for (const d of docs.slice(0, 25)) { // sample first 25 to keep runtime low
 75 |       for (const key of REQUIRED_KEYS) {
 76 |         assert.ok(Object.prototype.hasOwnProperty.call(d, key), `Missing key ${key}`);
 77 |         assert.equal(typeof d[key], 'string', `${key} should be string`);
 78 |         assert.ok(d[key].length > 0, `${key} should be non-empty`);
 79 |       }
 80 |     }
 81 |   });
 82 | 
 83 |   test('category coverage present', async () => {
 84 |     const { raw } = await invoke();
 85 |     const docs = safeParseDocuments(raw);
 86 |     const categories = new Set(docs.map(d => d.category));
 87 |     for (const c of REQUIRED_CATEGORIES) {
 88 |       assert.ok(categories.has(c), `Expected category ${c}`);
 89 |     }
 90 |   });
 91 | 
 92 |   test('extraneous argument is ignored', async () => {
 93 |     const { raw } = await invoke({ unused: 'value' });
 94 |     const docs = safeParseDocuments(raw);
 95 |     assert.ok(docs.length >= 15, 'At least 15 docs expected with extraneous argument');
 96 |   });
 97 | 
 98 |   test('multiple product-* occurrences and filename pattern sanity', async () => {
 99 |     const { raw } = await invoke();
100 |     assert.match(raw, /(product-).*(product-).*(product-)/s, 'Expect at least three product- occurrences');
101 |   assert.match(raw, /"filename"\s*:\s*"[a-z0-9-]+\.md"/, 'Expect filename .md entries');
102 |   });
103 | 
104 |   test('negative path: invalid method should return JSON-RPC error', async () => {
105 |     // Raw JSON-RPC send with invalid method name returns error response (not throw)
106 |     const response = await client.sendMessage({
107 |       jsonrpc: '2.0',
108 |       id: 'bad-method-1',
109 |       method: 'tools/call_WRONG',
110 |       params: { name: TOOL_NAME, arguments: {} }
111 |     });
112 |     assert.ok(response.error, 'Expected JSON-RPC error object');
113 |     assert.match(response.error.message || '', /method/i, 'Error message should mention method');
114 |   });
115 | 
116 |   test('argument validation error path (null arguments object)', async () => {
117 |     let caught = null;
118 |     try {
119 |       await client.callTool(TOOL_NAME, null);
120 |     } catch (err) {
121 |       caught = err;
122 |     }
123 |     assert.ok(caught, 'Expected callTool to reject with invalid_type');
124 |     assert.match(caught.message, /invalid_type|Expected object/i, 'Error should mention invalid type');
125 |   });
126 | 
127 |   test('filenames unique and kebab-case', async () => {
128 |     const { raw } = await invoke();
129 |     const docs = safeParseDocuments(raw);
130 |     const filenames = docs.map(d => d.filename);
131 |     const fileSet = new Set(filenames);
132 |     assert.equal(fileSet.size, filenames.length, 'Filenames must be unique');
133 |     for (const f of filenames.slice(0, 50)) {
134 |       assert.match(f, /^[a-z0-9-]+\.md$/, 'filename should be kebab-case .md');
135 |     }
136 |   });
137 | 
138 |   test('filename semantic correlation with name (first token appears in name)', async () => {
139 |     const { raw } = await invoke();
140 |     const docs = safeParseDocuments(raw);
141 |     for (const d of docs.slice(0, 40)) {
142 |       assert.match(d.filename, /^[a-z0-9-]+\.md$/, 'filename must be kebab-case .md');
143 |       const firstSegment = d.filename.replace(/\.md$/, '').split('-')[0];
144 |       assert.ok(d.name.toLowerCase().includes(firstSegment), 'name should contain filename first segment');
145 |     }
146 |   });
147 | 
148 |   test('category distribution sanity (no category monopolizes >70%)', async () => {
149 |     const { raw } = await invoke();
150 |     const docs = safeParseDocuments(raw);
151 |     const counts = docs.reduce((acc, d) => { acc[d.category] = (acc[d.category]||0)+1; return acc; }, {});
152 |     const total = docs.length;
153 |     for (const [cat, cnt] of Object.entries(counts)) {
154 |       assert.ok(cnt / total <= 0.7, `Category ${cat} dominates with ${(cnt/total*100).toFixed(1)}%`);
155 |     }
156 |   });
157 | 
158 |   test('deterministic ordering (two calls produce identical first 10 IDs)', async () => {
159 |     const first = safeParseDocuments((await invoke()).raw).slice(0,10).map(d=>d.id);
160 |     const second = safeParseDocuments((await invoke()).raw).slice(0,10).map(d=>d.id);
161 |     assert.deepEqual(second, first, 'First 10 IDs should be stable across calls');
162 |   });
163 | 
164 |   test('sample documents contain expected semantic keywords', async () => {
165 |     const { raw } = await invoke();
166 |     const docs = safeParseDocuments(raw);
167 |     const textBlob = JSON.stringify(docs.slice(0, 30)).toLowerCase();
168 |     const expected = ['server', 'request', 'response', 'product', 'price', 'cart'];
169 |     for (const token of expected) {
170 |       assert.ok(textBlob.includes(token), `Expected token ${token} in first 30 docs blob`);
171 |     }
172 |   });
173 | 
174 |   test('no empty or placeholder names', async () => {
175 |     const { raw } = await invoke();
176 |     const docs = safeParseDocuments(raw);
177 |     for (const d of docs) {
178 |       assert.ok(d.name.trim().length > 2, 'name should be >2 chars');
179 |       assert.ok(!/^(todo|tbd|placeholder)$/i.test(d.name), 'name should not be placeholder');
180 |     }
181 |   });
182 | 
183 |   test('round-trip JSON parse reproducibility (stringify->parse equality for first 5)', async () => {
184 |     const { raw } = await invoke();
185 |     const docs = safeParseDocuments(raw).slice(0,5);
186 |     const roundTrip = JSON.parse(JSON.stringify(docs));
187 |     assert.deepEqual(roundTrip, docs, 'Round trip serialization must preserve first 5 docs');
188 |   });
189 | 
190 |   test('at least one document per required category and each category has <= 50% of docs', async () => {
191 |     const { raw } = await invoke();
192 |     const docs = safeParseDocuments(raw);
193 |     const counts = docs.reduce((acc, d) => { acc[d.category] = (acc[d.category]||0)+1; return acc; }, {});
194 |     const total = docs.length;
195 |     for (const c of REQUIRED_CATEGORIES) {
196 |       assert.ok(counts[c] > 0, `Category ${c} missing`);
197 |       assert.ok((counts[c] / total) <= 0.5, `Category ${c} exceeds 50% threshold`);
198 |     }
199 |   });
200 | 
201 |   test('filename/id pairing uniqueness (no duplicate filename)', async () => {
202 |     const { raw } = await invoke();
203 |     const docs = safeParseDocuments(raw);
204 |     const filenames = docs.map(d => d.filename);
205 |     const fileSet = new Set(filenames);
206 |     assert.equal(fileSet.size, filenames.length, 'Filenames must be unique');
207 |   });
208 | 
209 |   test('sorted by name alpha? (non-fatal heuristic) warn if not mostly sorted', async () => {
210 |     const { raw } = await invoke();
211 |     const docs = safeParseDocuments(raw).slice(0,30);
212 |     const names = docs.map(d=>d.name.toLowerCase());
213 |     const sorted = [...names].sort();
214 |     let outOfOrder = 0;
215 |     names.forEach((n,i)=>{ if(n!==sorted[i]) outOfOrder++; });
216 |     if (outOfOrder > Math.ceil(names.length * 0.4)) {
217 |       console.warn(`Heuristic: more than 40% (${outOfOrder}/${names.length}) of first 30 names out of alpha order`);
218 |     }
219 |   });
220 | 
221 |   // Removed category/id correlation test (no id field in response)
222 | 
223 |   // Removed id/filename prefix correlation (id not present)
224 | 
225 |   test('document count stable across two invocations (delta <= 2)', async () => {
226 |     const firstLen = safeParseDocuments((await invoke()).raw).length;
227 |     const secondLen = safeParseDocuments((await invoke()).raw).length;
228 |     const delta = Math.abs(firstLen - secondLen);
229 |     assert.ok(delta <= 2, `Doc count changed unexpectedly by ${delta}`);
230 |   });
231 | 
232 |   test('category histogram logged for diagnostic insight (non-asserting)', async () => {
233 |     const { raw } = await invoke();
234 |     const docs = safeParseDocuments(raw);
235 |     const counts = docs.reduce((acc, d) => { acc[d.category] = (acc[d.category]||0)+1; return acc; }, {});
236 |     console.info('SFRA docs category histogram:', counts);
237 |   });
238 | 
239 |   test('ensure presence of canonical core documents', async () => {
240 |     const { raw } = await invoke();
241 |     const docs = safeParseDocuments(raw);
242 |     const names = docs.map(d=>d.name.toLowerCase());
243 |     const required = ['server', 'request', 'response', 'querystring', 'render'];
244 |     for (const r of required) {
245 |       assert.ok(names.some(n=>n.includes(r)), `Missing canonical core doc: ${r}`);
246 |     }
247 |   });
248 | 
249 |   test('ensure presence of key product/order/customer domain docs', async () => {
250 |     const { raw } = await invoke();
251 |     const docs = safeParseDocuments(raw);
252 |     const blob = JSON.stringify(docs).toLowerCase();
253 |     const expected = ['product', 'cart', 'shipping', 'billing', 'account', 'customer', 'price'];
254 |     for (const token of expected) {
255 |       assert.ok(blob.includes(token), `Missing expected domain token: ${token}`);
256 |     }
257 |   });
258 | 
259 |   test('no obvious placeholder filenames', async () => {
260 |     const { raw } = await invoke();
261 |     const docs = safeParseDocuments(raw);
262 |     for (const d of docs) {
263 |       assert.ok(!/(placeholder|temp|dummy)/i.test(d.filename), 'Filename should not look placeholder');
264 |     }
265 |   });
266 | 
267 |   test('filename extension enforcement (.md only)', async () => {
268 |     const { raw } = await invoke();
269 |     const docs = safeParseDocuments(raw);
270 |     for (const d of docs) {
271 |       assert.ok(d.filename.endsWith('.md'), 'All filenames must end with .md');
272 |     }
273 |   });
274 | });
275 | 
```

--------------------------------------------------------------------------------
/tests/validation-helpers.test.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { ValidationHelpers, ValidationRule, CommonValidations } from '../src/core/handlers/validation-helpers.js';
  2 | import { HandlerError } from '../src/core/handlers/base-handler.js';
  3 | 
  4 | describe('ValidationHelpers', () => {
  5 |   describe('validateArguments', () => {
  6 |     it('should pass when all required fields are present and valid', () => {
  7 |       const args = {
  8 |         stringField: 'value1',
  9 |         numberField: 42,
 10 |         booleanField: true,
 11 |         objectField: { prop: 'value' },
 12 |       };
 13 | 
 14 |       const rules: ValidationRule[] = [
 15 |         { field: 'stringField', required: true, type: 'string' },
 16 |         { field: 'numberField', required: true, type: 'number' },
 17 |         { field: 'booleanField', required: true, type: 'boolean' },
 18 |         { field: 'objectField', required: true, type: 'object' },
 19 |       ];
 20 | 
 21 |       expect(() => {
 22 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
 23 |       }).not.toThrow();
 24 |     });
 25 | 
 26 |     it('should throw HandlerError when required field is missing', () => {
 27 |       const args = {
 28 |         field1: 'value1',
 29 |       };
 30 | 
 31 |       const rules: ValidationRule[] = [
 32 |         { field: 'field1', required: true, type: 'string' },
 33 |         { field: 'field2', required: true, type: 'string' },
 34 |       ];
 35 | 
 36 |       expect(() => {
 37 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
 38 |       }).toThrow(HandlerError);
 39 | 
 40 |       try {
 41 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
 42 |       } catch (error) {
 43 |         expect(error).toBeInstanceOf(HandlerError);
 44 |         expect((error as HandlerError).message).toBe('field2 is required');
 45 |         expect((error as HandlerError).toolName).toBe('test_tool');
 46 |         expect((error as HandlerError).code).toBe('MISSING_ARGUMENT');
 47 |       }
 48 |     });
 49 | 
 50 |     it('should throw when required field is null', () => {
 51 |       const args = {
 52 |         field1: 'value1',
 53 |         field2: null,
 54 |       };
 55 | 
 56 |       const rules: ValidationRule[] = [
 57 |         { field: 'field1', required: true, type: 'string' },
 58 |         { field: 'field2', required: true, type: 'string' },
 59 |       ];
 60 | 
 61 |       expect(() => {
 62 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
 63 |       }).toThrow('field2 is required');
 64 |     });
 65 | 
 66 |     it('should throw when required field is empty string', () => {
 67 |       const args = {
 68 |         field1: 'value1',
 69 |         field2: '',
 70 |       };
 71 | 
 72 |       const rules: ValidationRule[] = [
 73 |         { field: 'field1', required: true, type: 'string' },
 74 |         { field: 'field2', required: true, type: 'string' },
 75 |       ];
 76 | 
 77 |       expect(() => {
 78 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
 79 |       }).toThrow('field2 is required');
 80 |     });
 81 | 
 82 |     it('should throw when field type is incorrect', () => {
 83 |       const args = {
 84 |         stringField: 123, // Should be string
 85 |       };
 86 | 
 87 |       const rules: ValidationRule[] = [
 88 |         { field: 'stringField', required: true, type: 'string' },
 89 |       ];
 90 | 
 91 |       expect(() => {
 92 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
 93 |       }).toThrow(HandlerError);
 94 | 
 95 |       try {
 96 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
 97 |       } catch (error) {
 98 |         expect(error).toBeInstanceOf(HandlerError);
 99 |         expect((error as HandlerError).message).toBe('stringField must be of type string');
100 |         expect((error as HandlerError).code).toBe('INVALID_TYPE');
101 |       }
102 |     });
103 | 
104 |     it('should pass when optional field is missing', () => {
105 |       const args = {
106 |         required: 'value',
107 |       };
108 | 
109 |       const rules: ValidationRule[] = [
110 |         { field: 'required', required: true, type: 'string' },
111 |         { field: 'optional', required: false, type: 'string' },
112 |       ];
113 | 
114 |       expect(() => {
115 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
116 |       }).not.toThrow();
117 |     });
118 | 
119 |     it('should validate custom validator function', () => {
120 |       const args = {
121 |         email: 'invalid-email',
122 |       };
123 | 
124 |       const rules: ValidationRule[] = [
125 |         {
126 |           field: 'email',
127 |           required: true,
128 |           type: 'string',
129 |           validator: (value: string) => value.includes('@'),
130 |           errorMessage: 'email must be a valid email address',
131 |         },
132 |       ];
133 | 
134 |       expect(() => {
135 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
136 |       }).toThrow('email must be a valid email address');
137 |     });
138 | 
139 |     it('should pass custom validator when valid', () => {
140 |       const args = {
141 |         email: '[email protected]',
142 |       };
143 | 
144 |       const rules: ValidationRule[] = [
145 |         {
146 |           field: 'email',
147 |           required: true,
148 |           type: 'string',
149 |           validator: (value: string) => value.includes('@'),
150 |           errorMessage: 'email must be a valid email address',
151 |         },
152 |       ];
153 | 
154 |       expect(() => {
155 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
156 |       }).not.toThrow();
157 |     });
158 |   });
159 | 
160 |   describe('requireStrings', () => {
161 |     it('should pass when all required string fields are present', () => {
162 |       const args = {
163 |         field1: 'value1',
164 |         field2: 'value2',
165 |       };
166 | 
167 |       expect(() => {
168 |         ValidationHelpers.requireStrings(args, ['field1', 'field2'], 'test_tool');
169 |       }).not.toThrow();
170 |     });
171 | 
172 |     it('should throw when required string field is missing', () => {
173 |       const args = {
174 |         field1: 'value1',
175 |       };
176 | 
177 |       expect(() => {
178 |         ValidationHelpers.requireStrings(args, ['field1', 'field2'], 'test_tool');
179 |       }).toThrow('field2 is required for test_tool');
180 |     });
181 | 
182 |     it('should pass when no fields are required', () => {
183 |       const args = { field1: 'value1' };
184 | 
185 |       expect(() => {
186 |         ValidationHelpers.requireStrings(args, [], 'test_tool');
187 |       }).not.toThrow();
188 |     });
189 |   });
190 | 
191 |   describe('type validation', () => {
192 |     it('should validate string type correctly', () => {
193 |       const args = { field: 'string value' };
194 |       const rules: ValidationRule[] = [{ field: 'field', type: 'string' }];
195 | 
196 |       expect(() => {
197 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
198 |       }).not.toThrow();
199 |     });
200 | 
201 |     it('should validate number type correctly', () => {
202 |       const args = { field: 42 };
203 |       const rules: ValidationRule[] = [{ field: 'field', type: 'number' }];
204 | 
205 |       expect(() => {
206 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
207 |       }).not.toThrow();
208 |     });
209 | 
210 |     it('should validate boolean type correctly', () => {
211 |       const args = { field: true };
212 |       const rules: ValidationRule[] = [{ field: 'field', type: 'boolean' }];
213 | 
214 |       expect(() => {
215 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
216 |       }).not.toThrow();
217 |     });
218 | 
219 |     it('should validate object type correctly', () => {
220 |       const args = { field: { prop: 'value' } };
221 |       const rules: ValidationRule[] = [{ field: 'field', type: 'object' }];
222 | 
223 |       expect(() => {
224 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
225 |       }).not.toThrow();
226 |     });
227 | 
228 |     it('should validate array type correctly', () => {
229 |       const args = { field: ['item1', 'item2'] };
230 |       const rules: ValidationRule[] = [{ field: 'field', type: 'array' }];
231 | 
232 |       expect(() => {
233 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
234 |       }).not.toThrow();
235 |     });
236 | 
237 |     it('should reject array when object expected', () => {
238 |       const args = { field: ['item1', 'item2'] };
239 |       const rules: ValidationRule[] = [{ field: 'field', type: 'object' }];
240 | 
241 |       expect(() => {
242 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
243 |       }).toThrow('field must be of type object');
244 |     });
245 | 
246 |     it('should reject null when object expected', () => {
247 |       const args = { field: null };
248 |       const rules: ValidationRule[] = [{ field: 'field', required: true, type: 'object' }];
249 | 
250 |       expect(() => {
251 |         ValidationHelpers.validateArguments(args, rules, 'test_tool');
252 |       }).toThrow('field is required');
253 |     });
254 |   });
255 | 
256 |   describe('CommonValidations', () => {
257 |     describe('Generic validation methods', () => {
258 |       it('should support generic requiredString validation', () => {
259 |         const rules = CommonValidations.requiredString('customField');
260 |         expect(rules).toEqual([{
261 |           field: 'customField',
262 |           required: true,
263 |           type: 'string',
264 |           validator: expect.any(Function),
265 |           errorMessage: 'customField must be a non-empty string',
266 |         }]);
267 |       });
268 | 
269 |       it('should support custom error messages in requiredString', () => {
270 |         const rules = CommonValidations.requiredString('customField', 'Custom error message');
271 |         expect(rules[0].errorMessage).toBe('Custom error message');
272 |       });
273 | 
274 |       it('should validate with generic requiredString', () => {
275 |         const args = { customField: 'valid-value' };
276 |         const rules = CommonValidations.requiredString('customField');
277 | 
278 |         expect(() => {
279 |           ValidationHelpers.validateArguments(args, rules, 'test_tool');
280 |         }).not.toThrow();
281 |       });
282 | 
283 |       it('should fail with empty string in requiredString', () => {
284 |         const args = { customField: '' };
285 |         const rules = CommonValidations.requiredString('customField');
286 | 
287 |         expect(() => {
288 |           ValidationHelpers.validateArguments(args, rules, 'test_tool');
289 |         }).toThrow('customField must be a non-empty string');
290 |       });
291 | 
292 |       it('should support generic requiredField validation', () => {
293 |         const rules = CommonValidations.requiredField(
294 |           'myField',
295 |           'number',
296 |           (value: number) => value > 0,
297 |           'myField must be positive',
298 |         );
299 |         expect(rules).toEqual([{
300 |           field: 'myField',
301 |           required: true,
302 |           type: 'number',
303 |           validator: expect.any(Function),
304 |           errorMessage: 'myField must be positive',
305 |         }]);
306 |       });
307 | 
308 |       it('should support optionalField validation', () => {
309 |         const rules = CommonValidations.optionalField(
310 |           'optionalField',
311 |           'boolean',
312 |           (value: boolean) => typeof value === 'boolean',
313 |           'optionalField must be boolean',
314 |         );
315 |         expect(rules[0].required).toBe(false);
316 |       });
317 | 
318 |       it('should validate cartridge name with custom pattern', () => {
319 |         const rules = CommonValidations.requiredField(
320 |           'cartridgeName',
321 |           'string',
322 |           (value: string) => /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(value),
323 |           'cartridgeName must be a valid identifier (letters, numbers, underscore, hyphen)',
324 |         );
325 | 
326 |         // Test valid cartridge name
327 |         const validArgs = { cartridgeName: 'plugin_example' };
328 |         expect(() => {
329 |           ValidationHelpers.validateArguments(validArgs, rules, 'test_tool');
330 |         }).not.toThrow();
331 | 
332 |         // Test invalid cartridge name
333 |         const invalidArgs = { cartridgeName: '123invalid' };
334 |         expect(() => {
335 |           ValidationHelpers.validateArguments(invalidArgs, rules, 'test_tool');
336 |         }).toThrow('cartridgeName must be a valid identifier');
337 |       });
338 | 
339 |       it('should validate className pattern', () => {
340 |         const rules = CommonValidations.requiredString('className');
341 | 
342 |         // Test valid className
343 |         const validArgs = { className: 'Product' };
344 |         expect(() => {
345 |           ValidationHelpers.validateArguments(validArgs, rules, 'test_tool');
346 |         }).not.toThrow();
347 | 
348 |         // Test empty className
349 |         const invalidArgs = { className: '' };
350 |         expect(() => {
351 |           ValidationHelpers.validateArguments(invalidArgs, rules, 'test_tool');
352 |         }).toThrow('className must be a non-empty string');
353 |       });
354 |     });
355 |   });
356 | });
357 | 
```
Page 21/61FirstPrevNextLast