Un Configuratore di Prodotto, chiamato anche configuratore commerciale o CPQ, non è altro che un software di gestione delle vendite che nasce per supportare i commerciali nel preparare offerte anche molto complesse.
Basandosi su una serie di algoritmi, un software CPQ aiuta nella configurazione di un prodotto o di un servizio, e nella scelta delle opzioni possibili, dei servizi accessori o dei prodotti correlati che sono sicuramente compatibili con il prodotto scelto.
Inoltre, un CPQ che si rispetti deve essere in grado di gestire in modo corretto tutto il pricing di una offerta generando un prezzo di vendita al cliente che sia un funzione non solo di un prezzo di listino ma anche di eventuali sconti e promozioni che possono essere applicate nell’ambito di una trattativa.
Negli anni l’utilizzo dei configuratori commerciali è diventato sempre più comune, complice il fatto che riducono notevolmente il tempo di generazione di una offerta commerciale e, allo stesso tempo, rendono tutto il processo di gestione della vendita più snello ed efficiente.
Il metodo tradizionale, che consiste nel consultare cataloghi, brochure, listini e riportare tutto su un foglio di carta ha da sempre portato problemi di efficienza e produttività.
Si pensi ad esempio ad errori di trascrizione di un prezzo a causa di listini non aggiornati, o errori sulla scelta di prodotti incompatibili tra loro, o peggio ancora l’applicazione di uno sconto non ammesso: tutti problemi che costringono il commerciale a ricontattare il potenziale cliente per riaprire la trattativa perdendo così tempo e credibilità.
Se sei alla ricerca di un CPQ non hai che l’imbarazzo della scelta: Oracle CPQ, Salesforce o l’italiana Apparound sono solo alcuni dei nomi più famosi.
Tuttavia, sono in molti coloro che decidono di creare in casa il proprio configuratore di prodotto.
Se anche tu stai valutando se vale la pena investire in un CPQ totalmente personalizzato questo tutorial fa per te.
In questo articolo, ti mostrerò come puoi realizzare in poche ore il tuo personalissimo CPQ utilizzando Oracle APEX. Ricorda, inoltre, che puoi vedere una applicazione di demo collegandoti a questo link.

IN QUESTO ARTICOLO
Cos’è un Configuratore di Prodotto
Prima di iniziare a mettere le mani in pasta, vorrei che ci soffermassimo un attimo sul capire in cosa consiste il configuratore commerciale che andremo a realizzare.
Quali sono le sue componenti principali e quale sarà il suo funzionamento?
Lo so, sembra qualcosa di noioso, però ti posso assicurare che ti aiuterà a comprendere meglio come funziona l’applicazione, così ti sarà più facile adattarla alle tue necessità.
Per realizzare il nostro CPQ dovremo prevedere tre funzionalità principali:
- Un’area di Amministrazione dei Prodotti per la gestione dei prodotti, degli articoli e del listino prezzi.
- Una sezione per l’Amministrazione delle Regole di Prodotto
- Il Configuratore di Prodotto vero e proprio, il cuore del nostro CPQ.
iniziamo..
Amministrazione dei Prodotti
In un CPQ un prodotto è l’oggetto dell’offerta, quello che vogliamo vendere.
Un prodotto è configurabile se possiamo personalizzarlo in base alle esigenze del cliente.
Facciamo un esempio: supponiamo tu debba acquistare un’auto da un produttore specifico e a tal proposito decidi di recarti dal tuo concessionario di fiducia.
Dopo aver scelto il modello tra quelli messi a disposizione, ti verrà chiesto quale colore preferisci per la carrozzeria, il tipo di allestimento ed in generale quali sono tutti gli accessori che desideri vengano installati.
Magari, ti verrà chiesto anche se desideri stipulare un contratto di assistenza per effettuare delle visite di manutenzione per i primi 2 anni dall’acquisito.
Ecco, quello che ti ho fatto è un ottimo esempio di prodotto configurabile.
Un prodotto configurabile non è solo qualcosa di fisico ma potrebbe essere quello che desideri: un software oppure un bundle di prodotti e servizi che vanno opportunamente messi insieme per offrire al cliente un pacchetto completo.
Anagrafica Prodotti
Un prodotto è, quindi, un oggetto identificato da un nome, una descrizione e un elenco di possibili componenti o articoli che andranno combinati insieme.
Iniziamo a creare la nostra applicazione partendo da questi oggetti.
- Collegati al Workspace di Oracle APEX e vai in SQL Workshop > Utilities > Quick SQL

- Inserisci il seguente script che servirà per creare tre tabelle
- Tabella PRODUCT: rappresenta il prodotto
- Tabella ITEM: sono gli articoli che verranno utilizzati per configurare il prodotto
- Tabella PRODUCT_ITEMS: è l’elenco di tutte le possibili opzioni che possono essere scelte quando viene configurato un prodotto.
product /api
id /pk
product_code vc(50)
product_name vc(250)
product_description vc(4000)
item /api
id /pk
item_code vc(50)
item_name vc(250)
item_description vc(4000)
product_items
id /pk
product_id /fk product
item_id /fk item
item_order num
- Premi Generate SQL

- Attraverso il tool Quick SQL, Oracle APEX è in grado di generare automaticamente gli script necessari per creare le tabelle nel database
- Premi Save SQL Script e successivamente Review and Run

- Premi Run

- Se va tutto come previsto dovresti vedere una pagina in cui vengono riepilogati tutti gli oggetti che sono stati creati nel database.
- A questo punto possiamo iniziare a configurare la nostra APP. Premi Create APP.

- Nella schermata successiva dovresti vedere l’elenco di tutte le tabelle che APEX collegherà alla nostra applicazione (PRODUCT, ITEM e PRODUCT_ITEMS)
- Premi Create Application

- Dai un nome alla tua applicazione

- Da qui puoi vedere la struttura di default dell’applicazione. Puoi lasciare tutto così com’è e modificarlo successivamente.
- Quando sei pronto premi Create Application

- Oracle APEX creerà l’applicazione che, tra l’altro, potremo iniziare ad usare fin da subito.
- Clicca su Run Application per avviarla.

- Nella sua versione base, l’applicazione sarà minimale e avrà tre voci di menù:
- Products per creare ed aggiornare i prodotti da aggiungere al catalogo
- Items per creare tutti gli articoli che compongono ciascun prodotto
- Product Items dove andrai a definire le relazioni tra i prodotti e gli articoli
Proviamo a creare un prodotto.
A tal proposito immaginiamo di essere una software house che crea applicazioni gestionali e che vuole inserire nel proprio catalogo prodotti una nuovo CRM, chiamato Easy CRM.
- Clicca su Products

- Il catalogo prodotti in questo momento è vuoto. Premi Create per creare un nuovo Prodotto

- Inserisci le informazioni richieste come un Product Code (questo campo potrebbe anche essere generato automaticamente da una sequenza) e un Product Name. Quando hai fatto premi Create per salvare le informazioni.

- Il prodotto è stato salvato.

Usando lo stesso metodo puoi creare tutti i prodotti che vuoi.
Fatto? Bene.
Ora dovremo definire per ciascun prodotto quali sono le opzioni o articoli che lo compongono perché, come potrai immaginare, tutti i prodotti software venduti dalla nostra azienda sono configurabili.
Quindi dobbiamo definire per ogni prodotto quali sono le sue opzioni e caratteristiche.
- Clicca su Items

- Crea uno o più articoli specificando le informazioni richieste come l’Item Code e l’Item Name.

Ovviamente puoi creare tutti gli articoli che desideri.
Ad esempio, io ho deciso di creare un articolo per ciascuna opzione che il cliente può attivare all’interno dell’ipotetica piattaforma Easy CRM.
Ti faccio notare come alcune opzioni (vedi le descrizioni degli articoli che ho inserito) per essere selezionate necessitano che siano soddisfatti alcuni vincoli.
Ad esempio il modulo EASY_BSB_COMMERCE può essere venduto solo con la licenza PRO di Easy CRM.
Vedremo più avanti come implementare questi vincoli utilizzando il motore di configurazione.

Per completare questa prima parte del tutorial dobbiamo infine collegare i singoli Items (che non possono essere venduti singolarmente) con il prodotto.
- Clicca su Product Items

- Crea un legame tra il prodotto EASY_CRM e tutti i suoi articoli

- Alla fine dovresti ottenere qualcosa di simile alla figura seguente.

Se lo desideri puoi ripetere l’operazione per tutti i Prodotti che vuoi e che potranno essere composti dagli stessi articoli piuttosto che da nuovi.
Una cosa importante che ci tengo a precisarti è che con Oracle APEX puoi implementare delle pagine più sofisticate che ti consentono di gestire in una unica schermata tutta la struttura di catalogo dello specifico prodotto.
In questo esempio, tuttavia, ho deciso di utilizzare solo le funzionalità standard e, cosa da non sottovalutare, non abbiamo ancora scritto una riga di codice!
Prima di andare avanti ti faccio notare che Oracle APEX ha creato automaticamente la lista valori PRODUCT.PRODUCT_CODE che puoi trovare sotto Shared Components > List of Values

Listino Prezzi
Per poter completare la definizione di un Catalogo Prodotti è necessario ovviamente gestire anche il Listino Prezzi che, come forse immaginerai, può avere tantissime sfaccettature e peculiarità.
In questo tutorial ci limiteremo ad implementare una gestione dei prezzi minimale. Potremo creare uno o più listini e, per ciascun listino, si dovrà specificare il prezzo unitario di ciascun articolo.
Come fatto per l’anagrafica prodotti, definiamo le tabelle della nostra applicazione usando il Quick SQL.
- Collegati al Workspace di Oracle APEX e vai in SQL Workshop > Utilities > Quick SQL
- Inserisci il seguente script che andrà a creare due tabelle:
- PRICE_BOOK: identifica il listino prezzi con un nome, una descrizione, una valuta di riferimento e delle date di validità
- PRICE_ITEM: serve per specificare il prezzo unitario di listino di ciascun articolo all’interno di ogni listino
price_book /api
id /pk
book_name vc(250)
book_description vc(4000)
valid_from date
valid_to date
currency vc(25)
price_item /api
id /pk
price_book_id /fk price_book
item_code vc(50) /fk item
item_price num
- Come visto precedentemente, genera lo script SQL per creare le tabelle ed eseguilo.
Ora possiamo creare le pagine APEX che utilizzeremo per creare ed aggiornare i listini prezzi.
In totale dovremo creare due pagine di tipo Interactive Report + Form, semplici e velocissime da creare:
- Price Books per definire i listini
- Item Price per caricare i singoli prezzi su ciascun listino
Come già sottolineato, in questo tutorial ho preferito gestire i dati usando delle funzionalità il più possibile semplici ma ciò non toglie che puoi divertirti a creare delle pagina più sofisticate.
Pagina Price Book
- Accedi all’APP Builder dell’applicazione Product Configurator e clicca Create Page

- Seleziona la Page Type Form e premi Next

- Seleziona l’opzione Report with Form e premi Next

- Nella schermata di configurazione della pagina seleziona le seguenti opzioni
- Report Type: Interactive Report
- Report Page Name: Price Books
- Form Page Name: Price Book Form
- Form Page Mode: Modal Dialog
- Premi Next

- Nella schermata Navigation Menu specifica la creazione di una voce di menù dedicata.
- Potrai personalizzare il menù della tua applicazione anche in un successivo momento. Per sapere come dai un occhio a questo tutorial.

- Nella schermata Data Source specifica la tabella PRICE_BOOK creata precedentemente e premi Next.

- Indica la chiave primaria della tabella (se hai usato gli script che ti ho fornito puoi specificare la colonna ID) e premi Create

- Dall’APP Builder clicca su Shared Components > List of Values
- Crea una nuova Lista Valori
- Name: PRICE_BOOK.BOOK_NAME
- Type: Dynamic

- Nelle opzioni dell’Origine Dati indica
- Source Type: Table
- Table / View Name: PRICE_BOOK

- Nella schermata Column Mapping specifica le seguenti opzioni
- Return Column: ID
- Display Column: BOOK_NAME

Pagina Item Price
Ora procediamo alla creazione della pagina Item Price per la quale dovrai eseguire esattamente gli stessi passi.
- Accedi all’APP Builder dell’applicazione Product Configurator e clicca Create Page
- Anche in questo caso selezionerai il tipo pagina Report with Form

- Collega la pagine Item Prices al Navigation Menu di APEX
- Collega come Origine Dati del report la tabella PRICE_ITEM

- Completa la configurazione guidata specificando la primary key (colonna ID) della tabella
- Apri la definizione della pagina Item Prices (quella di tipo Interactive Report)

- Seleziona il Page Item PRICE_BOOK_ID

- Cambiane il tipo a Plain Text (based on List of Values) e specifica nel campo List Of Values la lista valori PRICE_BOOK.BOOK_NAME che abbiamo creato nel paragrafo precedente.

- Seleziona il Page Item ITEM_CODE

- Cambiane il tipo a Plain Text (based on List of Values) e specifica nel campo List Of Values la lista valori ITEM.ITEM_CODE. Questa lista valori dovrebbe essere stata creata automaticamente da APEX quando abbiamo creato l’applicazione usando la procedura guidata. In ogni caso qui sotto ho riportato la sua definizione

- Apri la definizione della pagina Item Price (di tipo Form)

- Seleziona il campo PX_PRICE_BOOK_ID

- Cambiane il tipo a Select List

- Imposta anche in questo caso la lista valori PRICE_BOOK.BOOK_NAME

- Seleziona il Page Item PX_ITEM_CODE

- Cambiane il tipo a Popup LOV

- Imposta la lista valori ITEM.ITEM_CODE

Come definire il Listino Prezzi
Bene, ora possiamo finalmente creare i listini prezzi. Dopo aver velocemente aggiornato i vari menù di navigazione la mia Home Page si presenta come nell’immagine seguente.
- Clicca su Price Book per creare un nuovo Listino

- Specifica le informazioni richieste e salva

- Vai alla pagina Item Prices

- Aggiungi al listino appena creato i prezzi unitari.

Bene, arrivati a questo punto hai ottenuto già un risultato notevole perché senza scrivere una riga di codice hai costruito una applicazione web in grado di gestire tutto il tuo catalogo prodotti e prezzi di listino.
Non male, vero?
Il prossimo passo da fare è forse quello più interessante, perché andremo a creare un vero e proprio motore di configurazione.
Ti anticipo che dovremo scrivere un po’ di codice JavaScript e PL-SQL ma non preoccuparti! Ti fornirò tutti gli script da utilizzare.
Amministrazione delle Regole
Approcciare il tema delle regole di prodotto in un configuratore è sempre qualcosa di delicato.
Cos’è una regola? Quando dovrebbe e scattare e quali automatismi dovrebbe scatenare?
Questo sono solo alcune delle domande che vale la pena porsi quando si affrontano queste tematiche perché sono indispensabili per definire l’architettura generale della soluzione, così come il suo funzionamento.
In questo tutorial mostrerò un approccio specifico al problema della configurazione di prodotto ma non è detto che sia l’unico percorribile, infatti esistono decide di configuratori commerciali che funzionano in modo diverso.
Faccio questa premessa per sottolineare il fatto che quella che ti sto portando in questo tutorial è una soluzione al problema (sia in termini funzionali che tecnici) che ha sicuramente dei vantaggi ma anche dei limiti.
Bene, iniziamo.
Cos’è una Regola
Partiamo dal definire il concetto di Regola che potremmo rappresentare come la combinazione di tre oggetti specifici
- Rule Header: definisce il tipo di regola (es: Require, Exclude, …)
- Rule Conditions: definisce le condizioni che determinano il fatto che la regola scatti.
- Rule Actions: definisce cosa fa la regola. Ad esempio rende un codice obbligatorio oppure ne esclude un altro codice.

Ripensando al software che desideriamo vendere (Easy CRM) di cui riporto qui sotto il catalogo, vogliamo implementare una regola di questo tipo:
- il codice EASY_CUSTOMER_CARE richiede la versione EASY_CRM_PRO

Una rappresentazione logica della regola potrebbe essere la seguente:

Proviamo a spiegare meglio il modello dati
- Rule Header / Rule Type: Questa è una regola di tipo REQUIRE.
- Rule Conditions: La regola scatta (ovvero deve essere valutata) se viene selezionato il codice EASY_CUSTOMER_CARE.
- La regola è soddisfatta se il codice EASY_CRM_PRO è selezionato.
- La regola non è soddisfatta se il codice EASY_CRM_PRO non è selezionato.
- Rule Action: se la regola non è soddisfatta deve essere mostrato a video un messaggio che avvisa l’utente che il codice richiesto deve essere selezionato. La configurazione è invalida fin tanto che la regola non viene soddisfatta.
Sperando che fin qui sia tutto chiaro, adesso possiamo finalmente procedere con gli step successivi del tutorial.
Solo un paio di precisazioni prima di andare avanti.
In questo esempio ho definito una regola che scatta solo se è verificata una specifica condizione.
In generale, però, una regola può essere legata a più condizioni. Questo significa che deve essere valutata se sono tutte verificate contemporaneamente (AND) oppure se almeno una di esse è verificata (OR).
Infine, nel nostro configuratore di prodotto non creeremo funzionalità di selezione automatica, ma ci limiteremo ad implementare un motore di validazione della configurazione nella sua totalità.
Sarà poi cura dell’utente correggere le selezioni per far si che tutte le regole siano soddisfatte. Ovviamente questa è una semplificazione ma credo che per iniziare sia più che sufficiente.
Gestione delle Regole
- Accedi al Workspace APEX e vai, come al solito, in SQL Workspace > Utilities > Quick SQL
- Inserisci il seguente script necessario per creare le tabelle che serviranno per gestire le regole
- Tabella RULE: definisce le informazioni generali della singola regola, il tipo e la logica di valutazione delle sue condizioni (AND o OR)
- Tabella RULE_CONDITION: definisce la condizione che farà scattare la regola
- Tabella RULE_ACTION: definisce l’azione che deve scatenare la regola quando non è soddisfatta
rule /api
id /pk
product_id /fk product
rule_type /values REQUIRE,EXCLUDE,QUANTITY
rule_name vc(500)
rule_description vc(4000)
rule_status vc(150)
condition_logic vc(150) /values AND,OR
rule_condition /api
id /pk
rule_id /fk rule
item_code /fk item
condition_type vc(150) /values SELECTED,NOT_SELECTED,EQUAL_TO,NOT_EQUAL_TO,LESS_THAN,LESS_OR_EQUAL_THAN,GREATER_THAN,GREATER_OR_EQUAL_THAN
value vc(500)
rule_action /api
id /pk
rule_id /fk rule
item_code /fk item
min_quantity num
max_quantity num
action_message vc(4000)
- Premi Generate SQL ed esegui lo script SQL ottenuto
Come già visto per i Prodotti e Listini, adesso andremo a creare le pagine APEX che permetteranno di caricare le regole.
In totale creeremo 3 pagine di tipo Interactive Report + Form, una per ciascuna delle tre tabelle che abbiamo creato.
Arrivati a questo punto credo che tu abbia capito come fare quindi eviterò di ripetere ogni singolo passaggio ed andrò abbastanza veloce sui passaggi più classici.
Pagina Rules
- Accedi all’APP Builder e premi Create Page
- Seleziona l’opzione Create Form e poi Report with Form
- Specifica i nomi delle due pagine da create
- Report Page Name: Rules
- Form Page Name: Rule Detail
- Form Page Mode: Modal Dialog

- Aggiungi la pagina al Navigation Menu
- Seleziona come Source Type la tabella RULES

- Specifica la Primary Key della tabella (colonna ID)
- Accedi all’APP Builder e apri la definizione della pagina Rules

- Seleziona la colonna PRODUCT_ID

- Cambia il tipo a Plain Text (based on List of Values)
- Imposta la lista valori PRODUCT.PRODUCT_CODE

- Accedi all’APP Builder e apri la definizione della pagina Rules

- Seleziona la colonna PX_PRODUCT_ID

- Cambia il tipo a Select List

- Imposta la lista valori PRODUCT.PRODUCT_CODE

- Seleziona il Page Item PX_RULE_TYPE

- Imposta il Type e Select List e configura la seguente Lista Valori

- Seleziona il Page Item PX_CONDITION_LOGIC
- Cambia il tipo a Select List ed imposta la seguente Lista Valori

- Vai in Shared Components e crea la seguente lista valori RULE.RULE_NAME

Pagina Conditions
- Accedi all’APP Builder e premi Create Page
- Seleziona l’opzione Create Form e poi Report with Form
- Specifica i nomi delle due pagine da create
- Report Page Name: Rule Conditions
- Form Page Name: Rule Condition Detail
- Form Page Mode: Modal Dialog

- Aggiungi la pagina al Navigation Menu
- Seleziona come Source Type la tabella RULE_CONDITION ed indica la Primary Key (colonna ID)

- Seleziona la pagina Rule Conditions

- Seleziona il Page Item RULE_ID

- Cambia il tipo a Plain Text (based on List of Values) ed imposta la Lista Valori RULE.RULE_NAME che abbiamo creato nel paragrafo precedente

- Seleziona il Page Item ITEM_CODE

- Cambia il tipo a Plain Text (based on List of Values) ed imposta la Lista Valori ITEM.ITEM_CODE

- Seleziona la pagina Rule Condition Detail

- Seleziona il Page Item PX_RULE_ID

- Cambia il Type a Popup LOV e configura la lista valori RULE.RULE_NAME

- Seleziona il Page Item PX_ITEM_CODE

- Configura anche questo campo come Popup LOV; lista valori ITEM.ITEM_CODE

- Seleziona il Page Item PX_CONDITION_TYPE

- Cambia il Type a Select List e configura la seguente Lista Valori
Display Value | Return Value |
---|---|
SELECTED | SELECTED |
NOT_SELECTED | NOT_SELECTED |
EQUAL_TO | EQUAL_TO |
NOT_EQUAL_TO | NOT_EQUAL_TO |
LESS_THAN | LESS_THAN |
LESS_OR_EQUAL_THAN | LESS_OR_EQUAL_THAN |
GREATER_THAN | GREATER_THAN |
GREATER_OR_EQUAL_THAN | GREATER_OR_EQUAL_THAN |
Pagina Actions
- Accedi all’APP Builder e premi Create Page
- Seleziona l’opzione Create Form e poi Report with Form
- Specifica i nomi delle due pagine da create
- Report Page Name: Rule Actions
- Form Page Name: Rule Action Detail
- Form Page Mode: Modal Dialog

- Aggiungi la pagina al Navigation Menu
- Seleziona come Source Type la tabella RULE_ACTION ed indica la Primary Key (colonna ID)

- Seleziona la pagina Rule Actions

- Seleziona il Page Item RULE_ID

- Cambia il tipo a Plain Text (based on List of Values) ed imposta la Lista Valori RULE.RULE_NAME

- Seleziona il Page Item ITEM_CODE

- Cambia il tipo a Plain Text (based on List of Values) ed imposta la Lista Valori ITEM.ITEM_CODE

- Seleziona la pagina Rule Action Detail

- Seleziona il Page Item PX_RULE_ID

- Cambia il Type a Popup LOV e configura la lista valori RULE.RULE_NAME

- Seleziona il Page Item PX_ITEM_CODE

- Configura anche questo campo come Popup LOV; lista valori ITEM.ITEM_CODE

Come definire le Regole
Ora che hai finalmente completato le funzionalità di Amministrazione delle Regole possiamo iniziare a crearle.
Regola Require
Proviamo a sviluppare la regola che abbiamo citato all’inizio del capitolo e che riporto qui per comodità: il codice EASY_CUSTOMER_CARE richiede la versione EASY_CRM_PRO
- Apri l’applicazione e seleziona la voce di menu Rules

- Crea una nuova regola con queste caratteristiche:
- Product: EASY_CRM
- Rule Type: REQUIRE
- Rule Name: EASY_CRM_PRO Obbligatorio
- Condition Logic: AND

- Salva il record

- Vai alle Rule Conditions

- Dobbiamo esprimere la condizione che, se verificata, deve far scattare la valutazione della regola. Pertanto dovremo creare una Condition Rule fatta in questo modo:
- Rule: EASY_CRM_PRO Obbligatorio (è la regola creata prima)
- Item Code: EASY_CUSTOMER_CARE
- Condition Type: SELECTED

- Completiamo la configurazione della regola definendo l’azione, ossia quello che il sistema si aspetta quando è verificata la condizione.
- Vai alla pagina Rule Actions

- Crea l’Action Rule
- Rule: EASY_CRM_PRO Obbligatorio
- Item Code: EASY_CRM_PRO, il codice che il sistema si aspetta venga selezionato
- Action Message: se lo desideri puoi specificare un messaggio custom da mostrare a video (vedremo tra poco in che modo)

Esattamente allo stesso modo, possiamo creare altri 2 tipi di regole. Facciamo qualche esempio.
Regola Exclude
Proviamo a configurare le regole che rendono i seguenti codici mutuamente incompatibili fra di loro: EASY_CRM_BASE e EASY_CRM_PRO.
Regola 1: Se il codice EASY_CRM_BASE è selezionato, allora escludi il codice EASY_CRM_PRO
- Rule Definition

- Rule Condition

- Rule Action

Regola 2: Se il codice EASY_CRM_PRO è selezionato, allora escludi il codice EASY_CRM_BASE
- Rule Definition

- Rule Condition

- Rule Action

Regola Quantity
Proviamo a configurare il terzo di tipo di regola supportata dal nostro configuratore: Se selezionato, la quantità del codice EASY_MARKETING_CLOUD deve essere maggiore o uguale a 5
- Rule Definition

- Rule Condition

- Rule Action

Configuratore di Prodotto
Completiamo la terza ad ultima parte di questo tutorial con la realizzazione del nostro Configuratore di Prodotto, ossia una applicazione che, selezionato un Prodotto ed un Price Book, permette al venditore di fare le scelte di configurazione desiderate e che, allo stesso tempo, controlla se sono corrette.
Procediamo per passi.
API custom sales_configurator_api
Per realizzare il configuratore commerciale ho sviluppato una piccola api custom in PL-SQL che puoi scaricare a questo link.
Senza entrare nel dettaglio vorrei puntare la tua attenzione sulla store procedure più importante: check_configuration
procedure check_configuration (
p_configuration in clob,
l_configuration_status out varchar2,
l_configuration_validation out clob,
l_configuration_messages out clob,
l_configuration_price out varchar2
);
Questa store-procedure accetta come parametro in input un documento JSON e restituisce in output le seguenti informazioni
- configuration_status: VALID per configurazione valida, INVALID per configurazione invalida
- configuration_messages: un documento JSON contenente tutti i messaggi di validazione che vanno mostrati all’utente
- configuration_price: il prezzo totale della configurazione calcolato come somma del prezzo unitario di ciascun codice per la quantità selezionata
Prima di procedere con gli step successivi dovresti scaricare il package e compilarlo.
- Accedi al Worskspace APEX e vai in SQL Script
- Carica il file sales_configurator_api.sql

- Seleziona il file e premi Upload

- Esegui lo script

- In aggiunta al package PL-SQL appena compilato, ti chiedo di compilare anche la seguente Database View
CREATE OR REPLACE VIEW "PRODUCT_CATALOGS_V" ("PRODUCT_ID", "PRODUCT_CODE", "PRODUCT_NAME", "ITEM_ID", "ITEM_CODE", "ITEM_NAME", "ITEM_DESCRIPTION", "PRODUCT_ITEM_ID", "ITEM_ORDER") AS
select
product.id product_id,
product.product_code product_code,
product.product_name product_name,
item.id item_id,
item.item_code item_code,
item.item_name item_name,
item.item_description item_description,
product_items.id product_item_id,
product_items.item_order item_order
from
product product,
product_items product_items,
item item
where
1 = 1
and product_items.product_id = product.id
and product_items.item_id = item.id;
Pagina di Configurazione Prodotto
- Accede all’APP Builder e crea una nuova Blank Page
- Aggiungi una Page Region di nome Parameters con i seguenti Page Items
- PX_PRODUCT
- Type: Select List
- List Of Values: PRODUCT.PRODUCT_CODE
- PX_PRICE_BOOK
- Type: Select List
- List of Values: PRICE_BOOK.BOOK_NAME
- PX_CONFIGURATION_PRICE
- Type: Display Only
- PX_CONFIGURATION_STATUS
- Type: Display Text
- PX_PRODUCT

- Aggiungi una nuova Page Region di nome Parameters [Debug] con i seguenti Page Items
- PX_EVENT
- Type: Display Only
- PX_PRODUCT_ITEM_ID
- Type: Display Only
- PX_ITEM_QUANTITY
- Type: Display Only
- PX_CONFIGURATION_DATA
- Type: Display Only
- PX_VALIDATION
- Type: Display Only
- PX_VALIDATION_MESSAGE
- Type: Display Only
- PX_EVENT

- Crea una Page Region di nome Product Configurator

- Vai alle proprietà Page Region ed imposta il Type a Classic Report

- Vai alla sezione Source e configura il Type a SQL Query
- Specifica nella proprietà Page Items to Submit i campi PX_PRODUCT e PX_PRICE_BOOK creati precedentemente nella region Parameters.

- Inserisci la query seguente dove andrai a sostituire le variabili di biding px_price_book e px_product
select
product_id,
product_code,
product_name,
item_id,
item_code,
item_name,
item_description,
product_item_id,
item_order,
sales_configurator_api.add_item_checkbox (p_idx => 1,
p_value => product_item_id,
p_product_item_id => product_item_id,
p_checked => sales_configurator_api.is_item_selected(product_item_id, product_id, item_id, null)
) selection,
sales_configurator_api.add_item_qty (p_idx => 2,
p_value => sales_configurator_api.default_item_quantity(product_item_id, product_id, item_id, null),
p_product_item_id => product_item_id,
p_checked => sales_configurator_api.is_item_selected(product_item_id, product_id, item_id, null)
) quantity,
sales_configurator_api.item_unit_price_dsp(item_id,:px_price_book) UNIT_PRICE,
null row_price,
item_name title,
item_description description,
null item_classes,
null icon_class,
null icon_html,
null actions
from
product_catalogs_v product_catalog
where
product_id = :px_product
order by
item_order
- Crea due Dynamic Actions collegate rispettivamente ai Page Items PX_PRODUCT e PX_PRICE_BOOK

- Dynamic Action Change Product


- Dynamic Action Change Price Book


- Se esegui la Page Preview dovresti ottenere questo risultato

Quello che faremo adesso è personalizzare il layout del Classic Report usando un Template Custom.
- Vai Shared Components > User Interface > Templates

- Cerca il template Content Row e premi Duplicate. Dai al nuovo template il nome Product Configurator

- Apri la definizione del template Product Configurator
- Vai in Row Template ed inserisci il seguente Template HTML
<li class="t-ContentRow-item #ITEM_CLASSES#">
<div class="t-ContentRow-wrap">
<div class="t-ContentRow-selection">#SELECTION#</div>
<div class="t-ContentRow-iconWrap">
<span class="t-ContentRow-icon #ICON_CLASS#">#ICON_HTML#</span>
</div>
<div class="t-ContentRow-body">
<div class="t-ContentRow-content">
<h3 class="t-ContentRow-title">#TITLE#</h3>
<div class="t-ContentRow-description">#DESCRIPTION#</div>
</div>
<div class="t-ContentRow-selection">#QUANTITY#</div>
<div class="t-ContentRow-misc">#UNIT_PRICE#</div>
<div class="t-ContentRow-misc">#ROW_PRICE#</div>
<div class="t-ContentRow-actions">#ACTIONS#</div>
</div>
</div>
</li>

- Seleziona nuovamente la Page Region Product Configurator.

- Vai in Attributes > Appearance e seleziona il template Product Configurator appena creato.

- Seleziona i due Page Items SELECTION e QUANTITY

- Vai alla proprietà Security > Escape special characters ed imposta il valore a No

- Esegui la Preview
- Seleziona un Prodotto e un Listino Prezzi: dovresti vedere il catalogo del prodotto con indicati i prezzi unitari.

Modifica della Configurazione
Per implementare la parte interattiva del configuratore utilizzeremo del codice Java Script.
L’idea è che l’utente selezioni dei codici e delle quantità nel configuratore usando i campi evidenziati: ad ogni modifica il sistema deve validare in tempo reale la configurazione.

- Accedi all’APP Builder ed apri la definizione della pagina Product Configurator
- Vai in Processing > Ajax Callback > Create Process

- Definisci un nuovo Process
- Name: CHECK_CONFIGURATION
- Type: Execute Code
- Language: PL/SQL

- Nella proprietà PL/SQL Code inserisci lo script seguente
declare
configuration_status varchar2(2000);
configuration_price varchar2(2000);
configuration_validation clob;
configuration_messages clob;
begin
/* Questo è il frammento di codice che esegue la procedura PL-SQL */
for i in 1..apex_application.g_f01.count loop
sales_configurator_api.check_configuration( p_configuration => apex_application.g_f01(i),
l_configuration_status => configuration_status,
l_configuration_validation => configuration_validation,
l_configuration_messages => configuration_messages,
l_configuration_price => configuration_price);
end loop;
/* Questo è il frammento di codice che esegue stampa a video un messaggio */
apex_json.open_object;
apex_json.open_array('output');
apex_json.open_object;
apex_json.write('configuration_status', configuration_status);
apex_json.write('configuration_price', configuration_price);
apex_json.write('configuration_validation', configuration_validation);
apex_json.write('configuration_messages', configuration_messages);
apex_json.close_object;
apex_json.close_array;
apex_json.close_object;
end;
- Seleziona la Page Root

- Vai in JavaScript > Function and Global Variable Declaration ed inserisci il seguente script JS facendo attenzione a modificare i riferimenti ai Page Items con quelli effettivi della tua pagina.
var configurationMap = new Map();
function checkProductItemRules() {
var configurationData = apex.item("P10_CONFIGURATION_DATA").getValue();
/* ajax to call the database procedure */
apex.server.process("CHECK_CONFIGURATION", {
f01: configurationData,
pageItems: "#P10_CONFIGURATION_DATA"
}, {
success: function(pData) {
/* The Ajax process will return lv_error_msg and lv_error_code;
* if lv_error_code = 0 show the successful message, if not show the error */
var configuration_status = pData.output[0].configuration_status;
var configuration_validation = pData.output[0].configuration_validation;
var configuration_messages = pData.output[0].configuration_messages;
var configuration_price = pData.output[0].configuration_price;
apex.item("P10_CONFIGURATION_STATUS").setValue(configuration_status);
apex.item("P10_CONFIGURATION_PRICE").setValue(configuration_price);
apex.item("P10_VALIDATION").setValue(configuration_validation);
apex.item("P10_VALIDATION_MESSAGES").setValue(configuration_messages);
}
});
}
function mapToObj(inputMap) {
let obj = {};
inputMap.forEach(function(value, key){
obj[key] = value
});
return obj;
}
function buildJSON() {
var configurationId = null;
var productId = apex.item("P10_PRODUCT").getValue();
var priceBookId = apex.item("P10_PRICE_BOOK").getValue();
var items='[{"product_item_id":"0","item_quantity":0}';
configurationMap.forEach(function(value, key) {
console.log(key + " = " + JSON.stringify(value));
items = items +','+ JSON.stringify(value);
});
items = items + ']';
var myConfiguration = {
"configurationId": configurationId,
"productId": productId,
"priceBookId": priceBookId,
"productItems":
JSON.parse(items)
};
var myConfigurationData = JSON.stringify(myConfiguration);
apex.item("P10_CONFIGURATION_DATA").setValue(myConfigurationData);
}
function resetPageItems() {
apex.item("P10_CONFIGURATION_DATA").setValue(null);
apex.item("P10_EVENT").setValue(null);
apex.item("P10_PRODUCT_ITEM_ID").setValue(null);
apex.item("P10_ITEM_QUANTITY").setValue(null);
}

Le due funzioni JavaScript più importanti sono:
- buildJSON: genera un documento JSON che rappresenta la configurazione
- checkProductItemRules: invia al database il JSON della configurazione e richiama la store procedure sales_configurator_api.check_configuration
- Dalla definizione della pagina, clicca su Dynamic Actions > Change

- Crea una nuova Dynamic Action di nome Change Quantity che scatterà tutte le volte che l’utente modifica la quantità di un codice.

- Vai alla definizione della Dynamic Action ed imposta le seguenti proprietà
- Name: Change Quantity
- Event: Change
- Selection Type: jQuery Selector
- jQuery Selector: .item-quantity (questo parametro è definito nel template HTML che abbiamo creato pochi minuti fa)
- Event Scope: Dynamic

- Vai alla definizione dell’Action e specifica i seguenti parametri:
- Action: Execute JavaScript Code
- Code: inserisci lo script seguente facendo attenzione a modificare i riferimenti ai Page Items con quelli effettivi della tua pagina.
var event = 'SET_QUANTITY';
var item_quantity = this.triggeringElement.value;
var product_item_id = this.triggeringElement.getAttribute('product-item-id');
apex.item( "P10_EVENT").setValue (event);
apex.item( "P10_PRODUCT_ITEM_ID").setValue (product_item_id);
apex.item( "P10_ITEM_QUANTITY").setValue (item_quantity);
if (configurationMap.has(product_item_id)) {
var selection = {
"product_item_id": product_item_id,
"item_quantity": item_quantity
};
configurationMap.set(product_item_id,selection);
}
buildJSON();
checkProductItemRules();

- Dalla definizione della pagina, clicca su Dynamic Actions > Click
- Crea una nuova Dynamic Action di nome Select Item

- Definizione della Dynamic Action
- Name: Select Item
- Event: Click
- Selection Type: jQuery Selector
- jQuery Selector: .add-item (anche questo è un parametro incluso nel template HTML custom)

- Definizione dell’Action
- Action: Execute JavaScript Code
- Code: inserisci lo script seguente facendo attenzione a modificare i riferimenti ai Page Items con quelli effettivi della tua pagina.
var event, item_quantity;
var product_item_id = this.triggeringElement.getAttribute('product-item-id');
var item_checked = this.triggeringElement.checked;
var item_quantity_elem = document.getElementById('item-quantity-' + product_item_id);
if (item_checked) {
event = 'ADD_ITEM';
item_quantity = 1;
item_quantity_elem.disabled = false;
item_quantity_elem.value = item_quantity;
var selection = {"product_item_id": product_item_id, "item_quantity": item_quantity};
if (!configurationMap.has(product_item_id)) {
configurationMap.set(product_item_id,selection);
}
} else {
event = 'REMOVE_ITEM';
item_quantity = 0;
item_quantity_elem.disabled = true;
item_quantity_elem.value = item_quantity;
if (configurationMap.has(product_item_id)) {
configurationMap.delete(product_item_id);
}
}
apex.item("P10_EVENT").setValue(event);
apex.item("P10_PRODUCT_ITEM_ID").setValue(product_item_id);
apex.item("P10_ITEM_QUANTITY").setValue(item_quantity);
/* validate rules */
buildJSON();
checkProductItemRules();
- Esegui la Preview e prova a configurare il Prodotto.

- In funzione delle selezioni che fai dovresti notare diverse cose:
- Il campo Configuration Data che contiene il documento JSON della configurazione viene aggiornato in tempo reale
- Lo stesso avviene per il campo Validation Message dove sono riportato, sempre in formato JSON, i messaggi di validazione
- Il campo Configuration Price riporta il prezzo totale della configurazione mentre il campo Configuration Status assume un valore VALID o INVALID a seconda del fatto che ci siano o meno regole soddisfatte.
Ce l’hai fatta? Complimenti!
Nell’ultima parte del tutorial vedremo come rendere i messaggi più leggibili.
Validazione della Configurazione
- Accedi all’APP Builder ed apri la definizione della pagina Product Configurator
- Crea un nuovo Classic Report di nome Validation Message

- Inserisci nel report Validation Message la seguente query dove dovrai modificare il parametro di binding :PX_VALIDATION_MESSAGE con quello che hai creato nella tua pagina APEX
select
title LIST_TITLE ,message LIST_TEXT,icon,rule_type,rule_id, null LINK, icon icon_class
from
json_table ( :P10_VALIDATION_MESSAGES,
'$.messages[*]'
columns (
title varchar2 ( 4000 ) path '$.title',
message varchar2 ( 4000 ) path '$.message',
icon varchar2 ( 4000 ) path '$.icon',
rule_type varchar2 ( 4000 ) path '$.rule_type',
rule_id varchar2 ( 4000 ) path '$.rule_id'
)
)
jt
where
rule_id is not null
- Inserisci il parametro :PX_VALIDATION_MESSAGE nella proprietà Page Items to Submit

- Vai in Attributes > Appearance seleziona il template standard Media List

- Seleziona il campo dove andiamo a scrivere l’output della store procedure

- Crea una Dynamic Action

- Definizione della Dynamic Action

- Definizione dell’Action

- Vai nel tab Dynamic Action della pagina Product Configurator e crea una nuova Dynamic Action legata all’evento Page Load

- Definizione della Dynamic Action
- Name: Clear Data
- Event: Page Load
- Scope: Dynamic

- Definizione dell’Action Clear
- Action: Clear
- Selection Type: Item(s)
- Item(s): P10_CONFIGURATION_DATA, P10_VALIDATION_MESSAGES, P10_CONFIGURATION_STATUS, P10_CONFIGURATION_PRICE

- Definizione dell’Action Refresh
- Action: Refresh
- Selection Type: Region
- Region: Validation Message

- Definizione dell’Action Execute JavaScript Code
- Action: Execute JavaScript Code
- Code: esegui il seguente JS
buildJSON();
checkProductItemRules();

- Esegui la Preview e configura il Prodotto. In funzione delle validazioni vedrai comparire dei messaggi che indicano all’utente cosa deve fare per correggere la configurazione

Conclusioni
Bene, sei arrivato alla fine di questo tutorial.
Spero con tutto il cuore che tu lo abbia trovato interessante e di ispirazione per le tue avventure da creatore di applicazioni.
Ovviamente un CPQ più completo dovrebbe avere tante altre funzionalità oltre alla possibilità di poter definire regole più complesse.
Tuttavia, credo che quello che abbiamo fatto oggi insieme sia notevole e assolutamente non banale da realizzare.
Ci tengo poi a farti notare che la scelta di implementare la validazione tramite una procedura PL-SQL ti consente una più facile integrazione con applicazioni esterne, magari realizzate in APEX o no.
Ti basterà creare un servizio REST in Oracle APEX per far si che un qualunque sistema esterno (un sito WordPress, una applicazione AppSheet o quello che desideri) possa chiedere al tuo Product Configurator di validare una configurazione.
Fammi sapere se sei riuscito anche tu a realizzare il tuo CPQ personalizzato.
Nel frattempo ti invito ad seguirmi su Linkedin e su Twitter per rimanere aggiornato sulle future pubblicazioni.
Un abbraccio
Daniele
Lascia un commento