utb_cep_programs flow manages enrollment in Continuing Education Programs (Educación Continua). It renders a custom product landing page, validates student and graduate identity against the Banner ERP, applies role-based discounts in real time, and writes structured order metadata to WooCommerce.
Flow overview
| Property | Value |
|---|---|
| Flow ID | utb_cep_programs |
| Class | UTB\ProductBuilder\Flows\CEPFlow |
| Shortcode | [utb_cep_form] |
| Icon | dashicons-welcome-learn-more |
| AJAX endpoints | cep_calculate_discount, utb_cep_price |
| Order hook | woocommerce_checkout_order_processed → log_inscription |
Shortcode
Place[utb_cep_form] on any page or in a WooCommerce product description to render the standalone enrollment form. On a product page the flow renders the form automatically via render_custom_content().
AJAX endpoints
cep_calculate_discount
Validates the applicant’s identity and calculates their discount in one round-trip. Requires nonce utb_cep_nonce.
POST parameters:
| Parameter | Type | Description |
|---|---|---|
nonce | string | WordPress nonce (utb_cep_nonce) |
programa_codigo | string | Program code from the selector |
documento | int | ID document number |
primer_nombre | string | First name (must match Banner) |
segundo_nombre | string | Second name (optional, validated if provided) |
primer_apellido | string | First surname (must match Banner) |
segundo_apellido | string | Second surname (optional, validated if provided) |
(documento, programa_codigo, periodo, names_hash) tuple. A 30-second per-document rate limit applies after each live API call.
utb_cep_price
Returns a WooCommerce-formatted price string for visual updates when the user changes program selection.
POST parameters:
| Parameter | Type | Description |
|---|---|---|
price | float | Raw price value |
This endpoint does not require a nonce. It only formats a price provided by the client and performs no privileged operations.
Student role validation
Role validation is handled byCEPRolesValidator. When the applicant submits their document number, the class:
Check transient cache
Looks for
cep_roles_{documento} in the WordPress transient cache (10-minute TTL). Returns cached data immediately if found.Apply rate limit
If no cache exists, checks the
cep_rate_{documento} transient (30-second TTL). Returns a rate_limit WP_Error if the limit is active, preventing API flooding.Obtain OAuth token
Calls
ApiConnectionManager('cep_integrator')->get_auth_headers() to retrieve a valid Bearer token for the Banner integration.Query Banner API
Issues a GET request to
{api_base}/woocommerce/rol?documento={documento} with a 25-second timeout. Expects JSON with uppercase keys IDENTIFICACION, NOMBRE, APELLIDOS, and ROLES.Normalize roles
Maps raw role strings to uppercase hyphenated format (e.g.,
ESTUDIANTE_UG → ESTUDIANTE-UG). Determines rol_principal as ESTUDIANTE or EGRESADO for UI display.Identity fraud prevention
Before applying any discount, the flow performs a bilateral name-and-document validation insideajax_calculate_discount. The names the applicant typed are compared against what Banner returned for their document number:
primer_nombre(typed) must appear in Banner’sNOMBRE.primer_apellido(typed) must appear in Banner’sAPELLIDOS.- If
segundo_nombreorsegundo_apellidowere typed, they must also appear in Banner’s corresponding field.
remove_accents()), and use strpos() substring matching. A mismatch returns error code identity_mismatch and blocks the discount calculation:
Discount tiers
Discount calculation is delegated toCEPDiscountCalculator. Once roles are confirmed the class:
- Resolves the program’s billing concept code (
concepto). If the program has askuinwp_utb_cep_programs, that SKU is used directly; otherwise the fallback isEP-{CODIGO_PROGRAMA}. - Calls
{api_base}/woocommerce/programas/precios?periodo={period}&concepto={concepto}&programa={codigo}. - Reads
VALOR_LISTA(base price) andDESCUENTOSarray from the response. - Filters discounts to those whose
ROLmatches one of the applicant’s normalized roles. - Selects the discount with the highest
VALORpercentage.
| Role | Discount |
|---|---|
ESTUDIANTE (any sub-role) | 15% |
EGRESADO | 10% |
UTB_PB_DB_Schema::get_config()['rules']['cep_current_period'] with a fallback to the constant CEP_PERIODO_ACTUAL.
Dynamic program pricing
When the user selects a program from the<select id="cep_programa"> dropdown, cep-flow.js reads the data-precio attribute on the selected option and fires an AJAX call to utb_cep_price to render the formatted price string.
The price label uses direct inline styles (
attr('style', '...')), not jQuery .slideDown(), to avoid CSS animation conflicts that previously caused the price display to remain invisible. See changelog entry for v2.4.2.5.Default form configuration
CEPFlow::get_default_config() returns the field schema used when no JSON configuration has been saved via the Form Builder. The configuration is a flat array of field descriptors:
FormConfigManager::get_config() loads the configuration in this priority order:
_utb_form_configpost meta on the WooCommerce product (JSON saved by the Form Builder)._utb_linked_cert_idpost meta →form_config_jsonfromwp_utb_certificates.- Flow’s
get_default_config()result.
Cart metadata fields
The following order item meta keys are written byprepare_cart_metadata() and are visible in WooCommerce → Orders → (order) → Order details:
| Meta key | Source |
|---|---|
_utb_cep_primer_nombre | cep_primer_nombre (form field) |
_utb_cep_segundo_nombre | cep_segundo_nombre |
_utb_cep_primer_apellido | cep_primer_apellido |
_utb_cep_segundo_apellido | cep_segundo_apellido |
_utb_cep_tipo_documento | cep_tipo_documento |
_utb_cep_documento | cep_documento |
_utb_cep_programa_codigo | Program code from wp_utb_cep_programs |
_utb_cep_programa_nombre | Program name from wp_utb_cep_programs |
_utb_cep_precio | Base program price |
_utb_cep_descuento_porcentaje | Discount percentage (if applied) |
_utb_cep_descuento_monto | Discount amount in COP (if applied) |
_utb_cep_precio_con_descuento | Final price after discount (if applied) |
_utb_cep_rol_aplicado | Normalized role string (e.g. ESTUDIANTE) |
_utb_cep_periodo | Academic period (e.g. 2026.1) |
_utb_cep_concepto | Billing concept code |
_utb_cep_discount_request_id | Traceability ID from the discount API call |
Dynamic price at checkout
calculate_dynamic_price() overrides the WooCommerce cart item price. It returns _utb_cep_precio_con_descuento when a discount was applied, or _utb_cep_precio as the fallback. If neither key is present, null is returned and the original product price is kept.
Order logging
Thelog_inscription method is registered on woocommerce_checkout_order_processed with priority 10. It writes the completed enrollment record to wp_utb_cep_inscriptions via CEPInscriptionsRepository.
Frontend assets
| Handle | File | Depends on |
|---|---|---|
utb-cep-flow (CSS) | assets/frontend/cep-flow.css | — |
utb-cep-debug (JS) | assets/frontend/cep-debug.js | jquery |
utb-cep-flow (JS) | assets/frontend/cep-flow.js | jquery, utb-cep-debug |
UTB_CEP is localized with ajax_url, nonce, and debug_allowed. debug_allowed is true only for users with manage_options or edit_posts capabilities.
Debug mode
Add#debug or ?debug=1 to the product URL to enable verbose AJAX logging in the browser console. This requires the current WordPress user to have the Administrator or Editor role; anonymous users are silently blocked. The global window.UTB_DEBUG.enable() method can also be called from the browser console when logged in.