Skip to main content

Panoramica e Impostazioni

Centro di Controllo

consente di definire regole di controllo periodiche su un modello (es. mrp.production): ad ogni esecuzione la regola applica un dominio, calcola il totale reale dei record trovati, mostra fino a N esempi e invia un messaggio in un canale con un bottone che apre direttamente la lista filtrata.


1) Configurazione principale

Apri Impostazioni ▸ Funzioni tecniche▸ Point of Control ▸ Regole e crea una nuova regola. 

  • Nome: titolo chiaro della regola (es. ODP scadute e ferme). 
  • Azienda: azienda corrente (preimpostata).
  • Modello target (obbligatorio): il modello da controllare (es. mrp.production).
  • Canale destinazione (obbligatorio): canale di messaggistica in cui inviare il messaggio.
  • Attiva: se spuntato, la regola viene eseguita da cron.
  • Pianificazione:

    • Ogni N + Periodo (minuti/ore/giorni/settimane/mesi).

    • Prossima esecuzione / Ultima esecuzione: viene ricalcolata automaticamente

  • Messaggio: testo che viene riportato nel messaggio sul canale, se vuoto viene usato il modello di default. Ogni messaggio è personalizzabile e riporta nell'intestazione il titolo della regola ed il bottone per accedere all'elenco.
    • {count} : Segnaposto che riporta il num. totale di voci trovate
    • {sample} : Segnaposto che riporta un max. di 10 esempi delle voci trovate

2) Configurazione azione

L’azione Python è il codice che viene eseguito quando si clicca il bottone all’interno del messaggio.
Questa configurazione è fondamentale per garantire il corretto funzionamento del modulo.

{
  'type': 'ir.actions.act_window',
  'res_model': model._name,
  'name': "Ordini di produzione",
  'domain': domain,
  'context': dict(context or {}),
  'target': "main",
}
  • typeNon modificare mai. Deve rimanere invariato rispetto al valore riportato.
  • res_model → Inserire sempre model._name in modo da compilare automaticamente il campo con il valore selezionato sul Modello target.
  • name → Nome che verrà mostrato nel navigatore.
  • domain → Lasciare sempre domain. Questo verrà compilato secondo le regole già definite.
  • context → Si consiglia di utilizzare il valore di default oppure aggiungerne altri per attivare filtri o raggruppamenti specifici.
  • target → Impostare il valore main oppure current, a seconda della necessità.

3) Configurazione viste

Le viste sono fondamentali per visualizzare l’interfaccia nel modo più efficace possibile e permettere una corretta analisi dei dati.

È consigliato sempre configurare almeno due tipologie di viste nel seguente ordine:

  • Tree / Lista → per visualizzare l’elenco delle voci in formato tabellare.
  • Form → per accedere al dettaglio di una singola voce.

Il sistema utilizza una sequenza per definire l’ordine di priorità delle viste.
Non è necessario applicare filtri nella selezione, poiché il sistema propone automaticamente solo le viste relative al modello e alla tipologia selezionati.

È altamente consigliato definire viste primarie, ossia non ereditate da altre viste.


4) Condizioni (AND/OR)

La tabella Condizioni (AND/OR) definisce tutti filtri/regole da applicare nella regola di controllo.
Ogni condizione creata può appartenere a un gruppo, che stabilisce la logica di valutazione.
Senza gruppo tutte le condizione vengono valutate come AND.

Campi di configurazione

  • Campo: un campo memorizzato del modello.
  • Operatore=!=<<=>>=ilikenot ilikeinnot inis setis not set.
  • Tipo valorechar, integer, float, date, datetime, boolean, selection, many2one.
  • Sorgente valore:
    • literal: inserisci il valore direttamente.
    • today: data odierna (date).
    • now: data e ora correnti (datetime).
    • field: confronto campo vs campo (placeholder; non supportato nativamente dal dominio → completare in Filtro Python).
    • python: calcoli il valore con safe_eval (scalare/lista coerente con l’operatore).

5) Gruppi (AND/OR)

La tabella Gruppi (AND/OR) consente di organizzare e raggruppare più condizioni in insiemi logici.
Ogni gruppo definisce come devono essere valutate le condizioni al suo interno e come deve avvenire la combinazione con altri gruppi.

Funzionamento

  • AND → tutte le condizioni contenute nel gruppo devono risultare vere affinché il gruppo sia valido.
  • OR → è sufficiente che almeno una delle condizioni contenute nel gruppo sia vera affinché il gruppo sia valido.

I gruppi possono essere utilizzati per creare logiche complesse, combinando condizioni multiple tra loro e migliorando la precisione dei controlli.


6) Filtro Python (opz.)

Il Filtro Python è un meccanismo avanzato e opzionale che consente di definire controlli non esprimibili con le sole Condizioni (domini Odoo). È utile per confronti campo–campo, aggregazioni su relazioni, logiche multi-passo, ecc.

Funzionamento

  • Il codice è valutato con safe_eval in un ambiente sicuro.
  • Devi restituire uno dei seguenti valori:
    • Dominio (lista Odoo) → viene fatto AND con il dominio costruito dalle Condizioni/Group.
    • Recordset (sul modello della regola) → viene eseguita l’intersezione con i risultati del dominio base; l’apertura lista usa un dominio su id in [...].
  • Non sono supportati filtri che restituiscono un semplice booleano.

Modalità supportate

  • Espressione singola (consigliata): una sola espressione che valuta in un dominio o un recordset.
  • Script multi-linea: puoi usare assegnazioni; al termine devi valorizzare una variabile result (oppure domain / records) con il valore da restituire.

Contesto disponibile

All’interno del filtro sono disponibili:

env, model, relativedelta, company_id, today, now
  • today è la data odierna (tipo date).
  • now è il datetime corrente.
  • relativedelta permette l'aggiunta di tempo ad un datetime
Esempi di utilizzo
A)◆︎ Espressione singola → DOMINIO

Obiettivo: ODP collegati a una vendita confermata/chiusa e già scaduti (rispetto a now).

[
  ('date_deadline', '<', now),
  ('procurement_group_id', 'in',
    env['sale.order']
      .search([('state','in',['sale','done']),
               ('procurement_group_id','!=',False)])
      .mapped('procurement_group_id').ids
  ),
]

Variante: per “scaduti prima dell’inizio di oggi” usa today al posto di now.

B)◆︎ Espressione singola → RECORDSET

Obiettivo: Ordini non completati con ≤ 5 pezzi residui (product_qty - qty_produced).

model.search([]).filtered(
    lambda p: (p.product_qty - p.qty_produced) > 0
              and (p.product_qty - p.qty_produced) <= 5
)

La regola convertirà il recordset in un dominio su id per aprire la lista coerente.

C)◆︎ Script multi-linea → DOMINIO via result

Obiettivo: come l’esempio A, ma scritto a passaggi.

sale_groups = env['sale.order'].search([
    ('state','in',['sale','done']),
    ('procurement_group_id','!=',False),
]).mapped('procurement_group_id').ids

result = [
    ('date_deadline','<', now),
    ('procurement_group_id','in', sale_groups),
]

Note

  • Preferisci restituire un dominio quando possibile (più efficiente); usa il recordset solo per logiche impossibili in SQL (lambda, confronti campo–campo, aggregazioni complesse).
  • Le Condizioni standard restano attive: il filtro Python si somma (AND) al dominio base, oppure raffina i risultati via intersezione se restituisce un recordset.
  • Anteprima, messaggio e azione mostrano esattamente gli stessi record (coerenza tra len(rs), lista e bottone).
  • Evita calcoli costosi su tabelle molto grandi: se una logica è frequente, valuta un campo computed stored e poi filtra con un dominio classico.