extracted objects
This commit is contained in:
141
.gitignore
vendored
Normal file
141
.gitignore
vendored
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional stylelint cache
|
||||||
|
.stylelintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
.output
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# vuepress v2.x temp and cache directory
|
||||||
|
.temp
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# Sveltekit cache directory
|
||||||
|
.svelte-kit/
|
||||||
|
|
||||||
|
# vitepress build output
|
||||||
|
**/.vitepress/dist
|
||||||
|
|
||||||
|
# vitepress cache directory
|
||||||
|
**/.vitepress/cache
|
||||||
|
|
||||||
|
# Docusaurus cache and generated files
|
||||||
|
.docusaurus
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# Firebase cache directory
|
||||||
|
.firebase/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v3
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/sdks
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# Vite files
|
||||||
|
vite.config.js.timestamp-*
|
||||||
|
vite.config.ts.timestamp-*
|
||||||
|
.vite/
|
||||||
336
docs/APPLICATION_OVERVIEW.md
Normal file
336
docs/APPLICATION_OVERVIEW.md
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
# Apollinare Catering & Banqueting - Application Overview
|
||||||
|
|
||||||
|
## Descrizione Applicazione Attuale
|
||||||
|
|
||||||
|
### Cos'è Apollinare
|
||||||
|
|
||||||
|
**Apollinare Catering & Banqueting Management Software** è un gestionale completo per aziende di catering e banqueting che gestisce l'intero ciclo di vita di un evento, dalla prima richiesta del cliente fino all'esecuzione finale.
|
||||||
|
|
||||||
|
L'applicazione è attualmente in uso presso Apollinare Catering (Italia) ed è stata sviluppata su piattaforma Oracle APEX 21.1.0.
|
||||||
|
|
||||||
|
### Funzionalità Principali
|
||||||
|
|
||||||
|
#### 1. Gestione Eventi
|
||||||
|
|
||||||
|
Il cuore dell'applicazione è la gestione degli eventi di catering:
|
||||||
|
|
||||||
|
- **Creazione Evento**: Wizard guidato per la creazione di nuovi eventi
|
||||||
|
- **Dati Evento**: Data, orario cerimonia, orario evento, location, cliente
|
||||||
|
- **Tipologie**: Matrimoni, battesimi, comunioni, cresime, eventi aziendali, feste private
|
||||||
|
- **Tipo Pasto**: Pranzo, cena, pranzo buffet, cena buffet
|
||||||
|
|
||||||
|
#### 2. Workflow Stati Evento
|
||||||
|
|
||||||
|
L'evento attraversa diverse fasi:
|
||||||
|
|
||||||
|
```
|
||||||
|
PREVENTIVO (100) → Cliente interessato, preventivo in preparazione
|
||||||
|
↓
|
||||||
|
SCHEDA (200) → Degustazione effettuata, scheda evento in preparazione
|
||||||
|
↓
|
||||||
|
CONFERMATA (300) → Prima caparra ricevuta
|
||||||
|
↓
|
||||||
|
QUASI CONFERMATO (350) → In attesa conferma definitiva
|
||||||
|
↓
|
||||||
|
CONFERMATO (400) → Evento confermato, in esecuzione
|
||||||
|
↓
|
||||||
|
SUPERATO (900) → Evento concluso o annullato
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Gestione Ospiti
|
||||||
|
|
||||||
|
Sistema sofisticato per la gestione degli ospiti:
|
||||||
|
|
||||||
|
- **Tipi Ospiti**: Adulti, bambini, staff, fornitori esterni
|
||||||
|
- **Conteggi Separati**: Seduti vs buffet, adulti vs bambini
|
||||||
|
- **Coefficienti**: Ogni tipo ospite ha coefficienti per il calcolo quantità
|
||||||
|
|
||||||
|
#### 4. Lista Prelievo (Pick List)
|
||||||
|
|
||||||
|
Gestione automatizzata del materiale necessario:
|
||||||
|
|
||||||
|
- **Articoli**: Catalogo completo con immagini, quantità standard, coefficienti
|
||||||
|
- **Categorie**: Posate, piatti, bicchieri, tovagliato, decorazioni, attrezzature cucina
|
||||||
|
- **Calcolo Automatico**: Le quantità vengono calcolate automaticamente in base a:
|
||||||
|
- Numero ospiti per tipo
|
||||||
|
- Coefficienti categoria (A=Adulti, S=Seduti, B=Buffet)
|
||||||
|
- Quantità standard articolo
|
||||||
|
- **Disponibilità**: Verifica impegni articoli su altri eventi nella stessa data
|
||||||
|
|
||||||
|
#### 5. Gestione Risorse (Staff)
|
||||||
|
|
||||||
|
Pianificazione del personale:
|
||||||
|
|
||||||
|
- **Tipi Risorsa**: Camerieri, cuochi, barman, responsabili sala
|
||||||
|
- **Assegnazione**: Assegnazione risorse per evento
|
||||||
|
- **Report**: Riepilogo impegni risorse per data
|
||||||
|
|
||||||
|
#### 6. Sistema Acconti e Pagamenti
|
||||||
|
|
||||||
|
Gestione finanziaria completa:
|
||||||
|
|
||||||
|
- **Caparre Automatiche**: Sistema 30% - 50% - 20%
|
||||||
|
- **Tracking Pagamenti**: Monitoraggio stato pagamenti
|
||||||
|
- **Solleciti**: Identificazione eventi con pagamenti in scadenza (65 giorni)
|
||||||
|
- **Email Automatiche**: Notifiche automatiche per pagamenti
|
||||||
|
|
||||||
|
#### 7. Reporting
|
||||||
|
|
||||||
|
Sistema di reportistica integrato:
|
||||||
|
|
||||||
|
- **Scheda Evento**: PDF completo per cliente
|
||||||
|
- **Preventivo**: Documento commerciale
|
||||||
|
- **Riepilogo Cucina**: Per lo staff di cucina
|
||||||
|
- **Riepilogo Allestimenti**: Per team setup
|
||||||
|
- **Griglia Eventi**: Vista calendario operativa
|
||||||
|
- **Report Costi**: Analisi costi per evento/categoria
|
||||||
|
|
||||||
|
#### 8. Calendario
|
||||||
|
|
||||||
|
Vista calendario interattiva:
|
||||||
|
|
||||||
|
- **Visualizzazione**: Eventi per giorno/settimana/mese
|
||||||
|
- **Colori Stati**: Codifica colore per stato evento
|
||||||
|
- **Limiti**: Controllo numero massimo eventi per data
|
||||||
|
- **Conflitti**: Verifica location già impegnate
|
||||||
|
|
||||||
|
#### 9. Gestione Degustazioni
|
||||||
|
|
||||||
|
Per eventi come matrimoni:
|
||||||
|
|
||||||
|
- **Pianificazione**: Data e dettagli degustazione
|
||||||
|
- **Tracking**: Stato degustazione
|
||||||
|
- **Note**: Preferenze e allergie
|
||||||
|
|
||||||
|
#### 10. Template Eventi
|
||||||
|
|
||||||
|
Sistema di template per velocizzare la creazione:
|
||||||
|
|
||||||
|
- **Template Predefiniti**: Configurazioni standard per tipologie evento
|
||||||
|
- **Duplicazione**: Copia evento esistente come base
|
||||||
|
- **Versionamento**: Sistema di versioni per tracciare modifiche
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Proposta SaaS: CaterPro
|
||||||
|
|
||||||
|
### Vision
|
||||||
|
|
||||||
|
Trasformare Apollinare in **CaterPro**, una piattaforma SaaS multi-tenant per la gestione di aziende di catering e banqueting, mantenendo le funzionalità core ma aggiungendo caratteristiche enterprise.
|
||||||
|
|
||||||
|
### Target Market
|
||||||
|
|
||||||
|
1. **Piccole Aziende di Catering** (1-10 dipendenti)
|
||||||
|
- Piano Basic
|
||||||
|
- Gestione eventi semplificata
|
||||||
|
- Fino a 50 eventi/mese
|
||||||
|
|
||||||
|
2. **Medie Aziende di Catering** (10-50 dipendenti)
|
||||||
|
- Piano Professional
|
||||||
|
- Multi-location
|
||||||
|
- Fino a 200 eventi/mese
|
||||||
|
|
||||||
|
3. **Grandi Aziende / Catene** (50+ dipendenti)
|
||||||
|
- Piano Enterprise
|
||||||
|
- Multi-brand, multi-country
|
||||||
|
- Eventi illimitati
|
||||||
|
|
||||||
|
### Architettura SaaS
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ CaterPro Cloud │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||||
|
│ │ Tenant A │ │ Tenant B │ │ Tenant C │ ... │
|
||||||
|
│ │ (Catering │ │ (Wedding │ │ (Corporate │ │
|
||||||
|
│ │ Roma) │ │ Planner) │ │ Events) │ │
|
||||||
|
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ Shared Services │
|
||||||
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ │ Auth/IAM │ │ Billing │ │Analytics │ │ API │ │
|
||||||
|
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ Infrastructure │
|
||||||
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ │ .NET 8 │ │ React │ │PostgreSQL│ │ Azure │ │
|
||||||
|
│ │ API │ │ SPA │ │ /Oracle │ │ Cloud │ │
|
||||||
|
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Funzionalità SaaS Aggiuntive
|
||||||
|
|
||||||
|
#### Multi-Tenancy
|
||||||
|
- **Isolamento Dati**: Ogni cliente ha i propri dati completamente isolati
|
||||||
|
- **Customizzazione**: Logo, colori, branding personalizzabile
|
||||||
|
- **Subdomain**: cliente.caterpro.com
|
||||||
|
|
||||||
|
#### Gestione Utenti Avanzata
|
||||||
|
- **Ruoli Predefiniti**: Admin, Manager, Operatore, Cucina, Solo Lettura
|
||||||
|
- **Ruoli Custom**: Creazione ruoli personalizzati
|
||||||
|
- **SSO**: Integrazione Azure AD, Google Workspace
|
||||||
|
- **2FA**: Autenticazione a due fattori
|
||||||
|
|
||||||
|
#### Integrazioni
|
||||||
|
- **Calendario**: Google Calendar, Outlook, Apple Calendar
|
||||||
|
- **Pagamenti**: Stripe, PayPal, bonifici SEPA
|
||||||
|
- **Contabilità**: Export per Fatture in Cloud, QuickBooks, Xero
|
||||||
|
- **CRM**: Salesforce, HubSpot
|
||||||
|
- **E-commerce**: Preventivi online, pagamenti online
|
||||||
|
|
||||||
|
#### Mobile App
|
||||||
|
- **App iOS/Android**: Per staff in mobilità
|
||||||
|
- **Check-in Ospiti**: QR code per eventi
|
||||||
|
- **Inventario Mobile**: Scansione barcode articoli
|
||||||
|
- **Foto Evento**: Upload diretto da app
|
||||||
|
|
||||||
|
#### Analytics & BI
|
||||||
|
- **Dashboard Real-time**: KPI principali
|
||||||
|
- **Report Avanzati**: Analisi trend, stagionalità
|
||||||
|
- **Forecasting**: Previsioni ricavi
|
||||||
|
- **Export**: Excel, PDF, API
|
||||||
|
|
||||||
|
#### Automazioni
|
||||||
|
- **Email Marketing**: Campagne automatiche
|
||||||
|
- **Reminder**: Notifiche scadenze, follow-up
|
||||||
|
- **Workflow**: Automazione processi custom
|
||||||
|
- **Webhooks**: Integrazione con sistemi esterni
|
||||||
|
|
||||||
|
### Pricing Model
|
||||||
|
|
||||||
|
#### Basic - €49/mese
|
||||||
|
- 1 utente admin + 2 operatori
|
||||||
|
- 50 eventi/mese
|
||||||
|
- 500 articoli catalogo
|
||||||
|
- Report base
|
||||||
|
- Email support
|
||||||
|
|
||||||
|
#### Professional - €149/mese
|
||||||
|
- 5 utenti inclusi (+€15/utente aggiuntivo)
|
||||||
|
- 200 eventi/mese
|
||||||
|
- Articoli illimitati
|
||||||
|
- Multi-location (fino a 3)
|
||||||
|
- Report avanzati
|
||||||
|
- Integrazioni base
|
||||||
|
- Chat support
|
||||||
|
|
||||||
|
#### Enterprise - €399/mese
|
||||||
|
- Utenti illimitati
|
||||||
|
- Eventi illimitati
|
||||||
|
- Location illimitate
|
||||||
|
- API access
|
||||||
|
- Integrazioni premium
|
||||||
|
- White-label option
|
||||||
|
- SLA garantito
|
||||||
|
- Account manager dedicato
|
||||||
|
|
||||||
|
#### Add-ons
|
||||||
|
- **Mobile App**: +€29/mese
|
||||||
|
- **E-commerce Module**: +€49/mese
|
||||||
|
- **Advanced Analytics**: +€39/mese
|
||||||
|
- **Custom Integrations**: Su richiesta
|
||||||
|
|
||||||
|
### Stack Tecnologico Proposto
|
||||||
|
|
||||||
|
#### Backend (.NET 8)
|
||||||
|
```
|
||||||
|
├── CaterPro.API # Web API REST
|
||||||
|
├── CaterPro.Core # Domain models, interfaces
|
||||||
|
├── CaterPro.Application # Business logic, CQRS
|
||||||
|
├── CaterPro.Infrastructure # Data access, external services
|
||||||
|
├── CaterPro.Identity # Authentication/Authorization
|
||||||
|
└── CaterPro.Workers # Background jobs
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Frontend (React TypeScript)
|
||||||
|
```
|
||||||
|
├── src/
|
||||||
|
│ ├── components/ # Reusable UI components
|
||||||
|
│ ├── features/ # Feature-based modules
|
||||||
|
│ │ ├── events/ # Event management
|
||||||
|
│ │ ├── inventory/ # Article/inventory
|
||||||
|
│ │ ├── calendar/ # Calendar views
|
||||||
|
│ │ ├── reports/ # Reporting
|
||||||
|
│ │ └── settings/ # Configuration
|
||||||
|
│ ├── hooks/ # Custom React hooks
|
||||||
|
│ ├── services/ # API services
|
||||||
|
│ ├── store/ # Redux/Zustand state
|
||||||
|
│ └── utils/ # Utilities
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Database
|
||||||
|
- **Primary**: PostgreSQL (per SaaS cost-efficiency)
|
||||||
|
- **Alternative**: Oracle (per clienti enterprise on-premise)
|
||||||
|
- **Cache**: Redis
|
||||||
|
- **Search**: Elasticsearch (per ricerca articoli/eventi)
|
||||||
|
|
||||||
|
#### Infrastructure
|
||||||
|
- **Cloud**: Azure / AWS
|
||||||
|
- **Container**: Docker + Kubernetes
|
||||||
|
- **CI/CD**: GitHub Actions / Azure DevOps
|
||||||
|
- **Monitoring**: Application Insights / DataDog
|
||||||
|
|
||||||
|
### Roadmap Migrazione
|
||||||
|
|
||||||
|
#### Fase 1: Core Migration (3-4 mesi)
|
||||||
|
- [ ] Setup architettura .NET 8
|
||||||
|
- [ ] Migrazione modelli dati
|
||||||
|
- [ ] API REST per entità principali
|
||||||
|
- [ ] Frontend React base
|
||||||
|
- [ ] Autenticazione JWT
|
||||||
|
|
||||||
|
#### Fase 2: Feature Parity (2-3 mesi)
|
||||||
|
- [ ] Gestione eventi completa
|
||||||
|
- [ ] Sistema calcolo quantità
|
||||||
|
- [ ] Workflow stati
|
||||||
|
- [ ] Report PDF
|
||||||
|
- [ ] Calendario
|
||||||
|
|
||||||
|
#### Fase 3: SaaS Features (2-3 mesi)
|
||||||
|
- [ ] Multi-tenancy
|
||||||
|
- [ ] Billing integration
|
||||||
|
- [ ] User management avanzato
|
||||||
|
- [ ] Customization engine
|
||||||
|
|
||||||
|
#### Fase 4: Advanced Features (3-4 mesi)
|
||||||
|
- [ ] Mobile app
|
||||||
|
- [ ] Integrazioni terze parti
|
||||||
|
- [ ] Analytics avanzati
|
||||||
|
- [ ] E-commerce module
|
||||||
|
|
||||||
|
### Vantaggi Competitivi
|
||||||
|
|
||||||
|
1. **Esperienza Reale**: Basato su software in produzione da anni
|
||||||
|
2. **Specifico per Settore**: Non un gestionale generico adattato
|
||||||
|
3. **Calcolo Automatico**: Algoritmo quantità unico nel settore
|
||||||
|
4. **Workflow Collaudato**: Processo testato su centinaia di eventi
|
||||||
|
5. **Localizzazione**: Già disponibile in italiano, facilmente estendibile
|
||||||
|
|
||||||
|
### Competitor Analysis
|
||||||
|
|
||||||
|
| Feature | CaterPro | Caterease | Total Party Planner | Better Cater |
|
||||||
|
|---------|----------|-----------|---------------------|--------------|
|
||||||
|
| Gestione Eventi | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| Calcolo Auto Quantità | ✅ | ❌ | ❌ | Parziale |
|
||||||
|
| Multi-tenant | ✅ | ❌ | ❌ | ✅ |
|
||||||
|
| Mobile App | ✅ | ✅ | ❌ | ✅ |
|
||||||
|
| Italiano | ✅ | ❌ | ❌ | ❌ |
|
||||||
|
| API Pubbliche | ✅ | Parziale | ❌ | ✅ |
|
||||||
|
| Prezzo Entry | €49 | $75 | $50 | $99 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Conclusioni
|
||||||
|
|
||||||
|
L'applicazione Apollinare rappresenta un'eccellente base per lo sviluppo di una soluzione SaaS nel settore catering. Le funzionalità core sono mature e testate, la business logic è ben documentata, e l'architettura può essere modernizzata mantenendo la compatibilità con i processi esistenti.
|
||||||
|
|
||||||
|
La migrazione a .NET + React TypeScript permetterà:
|
||||||
|
- Scalabilità orizzontale per SaaS
|
||||||
|
- Developer experience moderna
|
||||||
|
- Ecosystem di librerie più ampio
|
||||||
|
- Deployment cloud-native
|
||||||
|
- Costi operativi ridotti
|
||||||
|
|
||||||
|
Il mercato italiano del catering è frammentato e sottosevito da soluzioni software moderne, rappresentando un'opportunità significativa per un prodotto SaaS verticale ben eseguito.
|
||||||
422
docs/README.md
Normal file
422
docs/README.md
Normal file
@@ -0,0 +1,422 @@
|
|||||||
|
# Apollinare Catering - Documentazione Completa
|
||||||
|
|
||||||
|
Questa documentazione contiene l'estrazione completa di tutti gli oggetti del database Oracle e dell'applicazione APEX di Apollinare Catering & Banqueting.
|
||||||
|
|
||||||
|
## [Application Overview](APPLICATION_OVERVIEW.md)
|
||||||
|
|
||||||
|
**Apollinare Catering & Banqueting Management Software** è un gestionale completo per aziende di catering che gestisce l'intero ciclo di vita di un evento: dalla richiesta del cliente, al preventivo, alla conferma, fino all'esecuzione.
|
||||||
|
|
||||||
|
### Funzionalità Principali
|
||||||
|
|
||||||
|
| Area | Descrizione |
|
||||||
|
| --------------------- | ------------------------------------------- |
|
||||||
|
| **Gestione Eventi** | Creazione, workflow stati, versioning |
|
||||||
|
| **Gestione Ospiti** | Tipologie ospiti, conteggi, coefficienti |
|
||||||
|
| **Lista Prelievo** | Calcolo automatico quantità materiale |
|
||||||
|
| **Risorse/Staff** | Pianificazione personale per evento |
|
||||||
|
| **Acconti/Pagamenti** | Sistema caparre 30%-50%-20%, solleciti |
|
||||||
|
| **Calendario** | Vista eventi, limiti giornalieri, conflitti |
|
||||||
|
| **Reporting** | Schede evento, preventivi, report cucina |
|
||||||
|
|
||||||
|
### Proposta SaaS: CaterPro
|
||||||
|
|
||||||
|
La documentazione include una proposta per trasformare Apollinare in **CaterPro**, una piattaforma SaaS multi-tenant:
|
||||||
|
|
||||||
|
- **Target**: Piccole, medie e grandi aziende di catering
|
||||||
|
- **Stack**: .NET 8 + React TypeScript + PostgreSQL/Oracle
|
||||||
|
- **Pricing**: Da €49/mese (Basic) a €399/mese (Enterprise)
|
||||||
|
- **Roadmap**: 10-14 mesi per feature parity + SaaS
|
||||||
|
|
||||||
|
Leggi la [documentazione completa](APPLICATION_OVERVIEW.md) per dettagli su architettura, funzionalità e roadmap.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Struttura della Documentazione
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/
|
||||||
|
├── apex/ # Applicazione APEX
|
||||||
|
│ ├── README.md # Overview applicazione
|
||||||
|
│ ├── pages/ # 56 pagine
|
||||||
|
│ ├── processes/ # 98 processi
|
||||||
|
│ ├── lovs/ # 12 List of Values
|
||||||
|
│ ├── javascript/ # Librerie JavaScript
|
||||||
|
│ ├── authorization/ # 5 schemi autorizzazione
|
||||||
|
│ ├── dynamic-actions/ # Azioni dinamiche
|
||||||
|
│ ├── items/ # Items condivisi
|
||||||
|
│ ├── regions/ # Regioni condivise
|
||||||
|
│ └── navigation/ # Navigazione
|
||||||
|
├── tables/ # 32 tabelle
|
||||||
|
├── views/ # 26 viste
|
||||||
|
├── procedures/ # 11 stored procedures
|
||||||
|
├── functions/ # 23 funzioni
|
||||||
|
├── packages/ # 17 packages
|
||||||
|
├── triggers/ # 19 triggers
|
||||||
|
├── sequences/ # 22 sequences
|
||||||
|
└── types/ # 10 tipi custom
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## APEX Application Documentation
|
||||||
|
|
||||||
|
### [APEX Application Overview](apex/README.md)
|
||||||
|
|
||||||
|
**Application:** APCB Project (ID: 112)
|
||||||
|
**APEX Version:** 21.1.0
|
||||||
|
**Schema:** APOLLINARECATERINGPROD
|
||||||
|
|
||||||
|
| Component | Count |
|
||||||
|
| --------------- | ----- |
|
||||||
|
| Pages | 56 |
|
||||||
|
| Items | 302 |
|
||||||
|
| Processes | 98 |
|
||||||
|
| Regions | 151 |
|
||||||
|
| Buttons | 119 |
|
||||||
|
| Dynamic Actions | 62 |
|
||||||
|
| LOVs | 12 |
|
||||||
|
|
||||||
|
### Key APEX Documentation
|
||||||
|
|
||||||
|
- [APEX README](apex/README.md) - Application overview and navigation
|
||||||
|
- [Processes Documentation](apex/processes/README.md) - All 98 processes with PL/SQL code
|
||||||
|
- [LOVs Documentation](apex/lovs/README.md) - 12 List of Values definitions
|
||||||
|
- [JavaScript Libraries](apex/javascript/README.md) - Custom ajaxUtils.js and iframeObj.js
|
||||||
|
- [Authorization Schemes](apex/authorization/README.md) - 5 security schemes
|
||||||
|
|
||||||
|
### Critical APEX Pages
|
||||||
|
|
||||||
|
| Page | Name | Description |
|
||||||
|
| ------ | ---------------- | ------------------------------------------------- |
|
||||||
|
| 1 | Home | Dashboard principale |
|
||||||
|
| **22** | **Nuovo Evento** | **Pagina più complessa (108 items, 32 processi)** |
|
||||||
|
| 9 | Liste | Lista eventi |
|
||||||
|
| 12 | Calendario | Calendario eventi |
|
||||||
|
| 35 | Schede | Schede evento |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Indice per Categoria
|
||||||
|
|
||||||
|
### [Tabelle](tables/README.md) (32)
|
||||||
|
|
||||||
|
Tabelle principali del dominio business:
|
||||||
|
|
||||||
|
- [EVENTI](tables/EVENTI.md) - Tabella principale eventi
|
||||||
|
- [EVENTI_DET_PREL](tables/EVENTI_DET_PREL.md) - Liste prelievo
|
||||||
|
- [EVENTI_DET_OSPITI](tables/EVENTI_DET_OSPITI.md) - Dettaglio ospiti
|
||||||
|
- [EVENTI_DET_RIS](tables/EVENTI_DET_RIS.md) - Risorse assegnate
|
||||||
|
- [EVENTI_DET_DEGUST](tables/EVENTI_DET_DEGUST.md) - Degustazioni
|
||||||
|
- [EVENTI_ACCONTI](tables/EVENTI_ACCONTI.md) - Gestione acconti/pagamenti
|
||||||
|
- [EVENTI_ALTRICOSTI](tables/EVENTI_ALTRICOSTI.md) - Altri costi
|
||||||
|
- [EVENTI_ALLEG](tables/EVENTI_ALLEG.md) - Allegati
|
||||||
|
- [ARTICOLI](tables/ARTICOLI.md) - Catalogo articoli
|
||||||
|
- [COSTI_ARTICOLI](tables/COSTI_ARTICOLI.md) - Storico costi
|
||||||
|
- [CLIENTI](tables/CLIENTI.md) - Anagrafica clienti
|
||||||
|
- [LOCATION](tables/LOCATION.md) - Location eventi
|
||||||
|
- [RISORSE](tables/RISORSE.md) - Personale
|
||||||
|
|
||||||
|
Tabelle di lookup:
|
||||||
|
|
||||||
|
- [TB_TIPI_MAT](tables/TB_TIPI_MAT.md) - Tipi materiale
|
||||||
|
- [TB_CODICI_CATEG](tables/TB_CODICI_CATEG.md) - Categorie
|
||||||
|
- [TB_TIPI_EVENTO](tables/TB_TIPI_EVENTO.md) - Tipi evento
|
||||||
|
- [TB_TIPI_OSPITI](tables/TB_TIPI_OSPITI.md) - Tipi ospiti
|
||||||
|
- [TB_TIPI_RISORSA](tables/TB_TIPI_RISORSA.md) - Tipi risorsa
|
||||||
|
- [TB_TIPI_PASTO](tables/TB_TIPI_PASTO.md) - Tipi pasto
|
||||||
|
- [TB_CALENDAR_LOCKS](tables/TB_CALENDAR_LOCKS.md) - Limiti calendario
|
||||||
|
- [TB_CONFIG](tables/TB_CONFIG.md) - Configurazioni
|
||||||
|
|
||||||
|
Tabelle di sistema:
|
||||||
|
|
||||||
|
- [USERS_READONLY](tables/USERS_READONLY.md) - Permessi utenti
|
||||||
|
- [XLIB_LOGS](tables/XLIB_LOGS.md) - Log applicazione
|
||||||
|
- [XLIB_COMPONENTS](tables/XLIB_COMPONENTS.md) - Componenti
|
||||||
|
- [XLIB_JASPERREPORTS_CONF](tables/XLIB_JASPERREPORTS_CONF.md) - Config report
|
||||||
|
- [XLIB_JASPERREPORTS_DEMOS](tables/XLIB_JASPERREPORTS_DEMOS.md) - Demo report
|
||||||
|
|
||||||
|
### [Viste](views/README.md) (26)
|
||||||
|
|
||||||
|
Viste per calcolo costi:
|
||||||
|
|
||||||
|
- [GET_COSTO_ART_BY_EVT](views/GET_COSTO_ART_BY_EVT.md) - Costo articoli per evento
|
||||||
|
- [GET_COSTO_ART_EVT](views/GET_COSTO_ART_EVT.md) - Costo articoli aggregato
|
||||||
|
- [GET_COSTO_CATEG_EVT](views/GET_COSTO_CATEG_EVT.md) - Costo per categoria
|
||||||
|
- [GET_COSTO_DEGUS_EVT](views/GET_COSTO_DEGUS_EVT.md) - Costo degustazioni
|
||||||
|
- [GET_COSTO_OSPITI_EVT](views/GET_COSTO_OSPITI_EVT.md) - Costo ospiti
|
||||||
|
- [GET_COSTO_RIS_EVT](views/GET_COSTO_RIS_EVT.md) - Costo risorse
|
||||||
|
- [GET_COSTO_TIPI_EVT](views/GET_COSTO_TIPI_EVT.md) - Costo per tipo
|
||||||
|
- [GET_ULTIMI_COSTI](views/GET_ULTIMI_COSTI.md) - Ultimi costi articoli
|
||||||
|
|
||||||
|
Viste per eventi:
|
||||||
|
|
||||||
|
- [GET_EVT_DATA](views/GET_EVT_DATA.md) - Dati evento completi
|
||||||
|
- [GET_EVT_DATA_PRINT](views/GET_EVT_DATA_PRINT.md) - Dati per stampa
|
||||||
|
- [GET_PREL_ART_TOT](views/GET_PREL_ART_TOT.md) - Totali prelievo
|
||||||
|
- [GET_PREL_BY_EVT](views/GET_PREL_BY_EVT.md) - Prelievi per evento
|
||||||
|
|
||||||
|
Viste per calendario e stato:
|
||||||
|
|
||||||
|
- [VW_CALENDARIO_EVENTI](views/VW_CALENDARIO_EVENTI.md) - Vista calendario
|
||||||
|
- [VW_EVENT_COLOR](views/VW_EVENT_COLOR.md) - Colori stati
|
||||||
|
- [VW_EVENTI_STATUSES](views/VW_EVENTI_STATUSES.md) - Stati eventi
|
||||||
|
|
||||||
|
Viste per giacenze:
|
||||||
|
|
||||||
|
- [V_IMPEGNI_ARTICOLI](views/V_IMPEGNI_ARTICOLI.md) - Impegni articoli
|
||||||
|
- [V_IMPEGNI_ARTICOLI_LOC](views/V_IMPEGNI_ARTICOLI_LOC.md) - Impegni per location
|
||||||
|
|
||||||
|
Viste per report:
|
||||||
|
|
||||||
|
- [V_REP_ALLESTIMENTI](views/V_REP_ALLESTIMENTI.md) - Report allestimenti
|
||||||
|
- [VW_REP_DEGUSTAZIONI](views/VW_REP_DEGUSTAZIONI.md) - Report degustazioni
|
||||||
|
- [V_GRIGLIA](views/V_GRIGLIA.md) - Vista griglia
|
||||||
|
- [GET_REPORT_CONSUNTIVO_PER_DATA](views/GET_REPORT_CONSUNTIVO_PER_DATA.md) - Consuntivo
|
||||||
|
|
||||||
|
Viste per utenti/permessi:
|
||||||
|
|
||||||
|
- [GET_CONSUNTIVI_USERS](views/GET_CONSUNTIVI_USERS.md) - Utenti consuntivi
|
||||||
|
- [GET_GESTORI_USERS](views/GET_GESTORI_USERS.md) - Utenti gestori
|
||||||
|
- [GET_USERS_LIST](views/GET_USERS_LIST.md) - Lista utenti
|
||||||
|
|
||||||
|
Viste per pagamenti:
|
||||||
|
|
||||||
|
- [GET_EVENTI_DA_PAGARE_ENTRO_65GG](views/GET_EVENTI_DA_PAGARE_ENTRO_65GG.md) - Eventi da sollecitare
|
||||||
|
|
||||||
|
### [Stored Procedures](procedures/README.md) (11)
|
||||||
|
|
||||||
|
Business logic principale:
|
||||||
|
|
||||||
|
- [EVENTI_AGGIORNA_QTA_LISTA](procedures/EVENTI_AGGIORNA_QTA_LISTA.md) - Ricalcolo quantità lista prelievo
|
||||||
|
- [EVENTI_AGGIORNA_TOT_OSPITI](procedures/EVENTI_AGGIORNA_TOT_OSPITI.md) - Aggiorna totale ospiti
|
||||||
|
- [EVENTI_COPIA](procedures/EVENTI_COPIA.md) - Duplicazione evento
|
||||||
|
- [EVENTI_RICALCOLA_ACCONTI](procedures/EVENTI_RICALCOLA_ACCONTI.md) - Ricalcolo acconti
|
||||||
|
- [EVENTO_ELIMINA_PRELIEVI](procedures/EVENTO_ELIMINA_PRELIEVI.md) - Elimina prelievi
|
||||||
|
- [LISTE_COPIA](procedures/LISTE_COPIA.md) - Copia liste tra eventi
|
||||||
|
- [P_CANCEL_SAME_LOCATION_EVENTS](procedures/P_CANCEL_SAME_LOCATION_EVENTS.md) - Annulla eventi stessa location
|
||||||
|
|
||||||
|
Utility:
|
||||||
|
|
||||||
|
- [ROWSORT_TIPI](procedures/ROWSORT_TIPI.md) - Ordinamento tipi
|
||||||
|
- [HTPPRN](procedures/HTPPRN.md) - Stampa HTTP
|
||||||
|
- [SEND_DATA_TO_DROPBOX](procedures/SEND_DATA_TO_DROPBOX.md) - Export Dropbox
|
||||||
|
- [XLOG](procedures/XLOG.md) - Logging
|
||||||
|
|
||||||
|
### [Funzioni](functions/README.md) (23)
|
||||||
|
|
||||||
|
Calcolo quantità e disponibilità:
|
||||||
|
|
||||||
|
- [F_GET_QTA_IMPEGNATA](functions/F_GET_QTA_IMPEGNATA.md) - Quantità impegnata
|
||||||
|
- [F_GET_TOT_OSPITI](functions/F_GET_TOT_OSPITI.md) - Totale ospiti
|
||||||
|
- [F_GET_OSPITI](functions/F_GET_OSPITI.md) - Dettaglio ospiti (pipelined)
|
||||||
|
- [F_LIST_PRELIEVO_ADD_ARTICOLO](functions/F_LIST_PRELIEVO_ADD_ARTICOLO.md) - Aggiunta articolo
|
||||||
|
|
||||||
|
Calcolo costi:
|
||||||
|
|
||||||
|
- [F_GET_COSTO_ARTICOLO](functions/F_GET_COSTO_ARTICOLO.md) - Costo articolo a data
|
||||||
|
|
||||||
|
Validazioni:
|
||||||
|
|
||||||
|
- [F_EVENTO_SCADUTO](functions/F_EVENTO_SCADUTO.md) - Verifica scadenza
|
||||||
|
- [F_MAX_NUMERO_EVENTI_RAGGIUNTO](functions/F_MAX_NUMERO_EVENTI_RAGGIUNTO.md) - Limite eventi
|
||||||
|
- [F_MAX_NUM_EVENTI_CONFERMATI](functions/F_MAX_NUM_EVENTI_CONFERMATI.md) - Limite confermati
|
||||||
|
- [F_CI_SONO_EVENTI_CONFERMATI](functions/F_CI_SONO_EVENTI_CONFERMATI.md) - Check confermati
|
||||||
|
|
||||||
|
Report:
|
||||||
|
|
||||||
|
- [F_REP_ALLESTIMENTI](functions/F_REP_ALLESTIMENTI.md) - Report allestimenti
|
||||||
|
- [F_REP_CUCINA](functions/F_REP_CUCINA.md) - Report cucina
|
||||||
|
- [F_GET_ANGOLO_ALLESTIMENTO](functions/F_GET_ANGOLO_ALLESTIMENTO.md) - Angolo allestimento
|
||||||
|
- [F_GET_ANGOLO_ALLESTIMENTO_OB](functions/F_GET_ANGOLO_ALLESTIMENTO_OB.md) - Angolo open bar
|
||||||
|
- [F_GET_TOVAGLIATO_ALLESTIMENTO](functions/F_GET_TOVAGLIATO_ALLESTIMENTO.md) - Tovagliato
|
||||||
|
|
||||||
|
Autorizzazioni:
|
||||||
|
|
||||||
|
- [F_USER_IN_ROLE](functions/F_USER_IN_ROLE.md) - Verifica ruolo utente
|
||||||
|
- [F_USER_IN_ROLE_STR](functions/F_USER_IN_ROLE_STR.md) - Ruolo utente (stringa)
|
||||||
|
|
||||||
|
Utility:
|
||||||
|
|
||||||
|
- [F_DAY_TO_NAME](functions/F_DAY_TO_NAME.md) - Giorno in italiano
|
||||||
|
- [STRING_TO_TABLE_ENUM](functions/STRING_TO_TABLE_ENUM.md) - Stringa a tabella
|
||||||
|
- [GET_PARAM_VALUE](functions/GET_PARAM_VALUE.md) - Valore parametro
|
||||||
|
- [SPLIT](functions/SPLIT.md) - Split stringa
|
||||||
|
- [MY_INSTR](functions/MY_INSTR.md) - Instr custom
|
||||||
|
- [CLOB2BLOB](functions/CLOB2BLOB.md) - Conversione CLOB
|
||||||
|
- [EXTDATE_GET_ITA](functions/EXTDATE_GET_ITA.md) - Data in italiano
|
||||||
|
|
||||||
|
### [Packages](packages/README.md) (17)
|
||||||
|
|
||||||
|
Business:
|
||||||
|
|
||||||
|
- [MAIL_PKG](packages/MAIL_PKG.md) - Gestione invio email automatiche
|
||||||
|
|
||||||
|
Utility esterne:
|
||||||
|
|
||||||
|
- [UTL_BASE64](packages/UTL_BASE64.md) - Encoding Base64
|
||||||
|
|
||||||
|
JasperReports:
|
||||||
|
|
||||||
|
- [XLIB_JASPERREPORTS](packages/XLIB_JASPERREPORTS.md) - Integrazione JasperReports
|
||||||
|
- [XLIB_JASPERREPORTS_IMG](packages/XLIB_JASPERREPORTS_IMG.md) - Immagini report
|
||||||
|
|
||||||
|
HTTP/Componenti:
|
||||||
|
|
||||||
|
- [XLIB_HTTP](packages/XLIB_HTTP.md) - Chiamate HTTP
|
||||||
|
- [XLIB_COMPONENT](packages/XLIB_COMPONENT.md) - Componenti
|
||||||
|
- [XLIB_LOG](packages/XLIB_LOG.md) - Logging
|
||||||
|
|
||||||
|
JSON (libreria PLJSON):
|
||||||
|
|
||||||
|
- [PLJSON_DYN](packages/PLJSON_DYN.md)
|
||||||
|
- [PLJSON_EXT](packages/PLJSON_EXT.md)
|
||||||
|
- [PLJSON_HELPER](packages/PLJSON_HELPER.md)
|
||||||
|
- [PLJSON_ML](packages/PLJSON_ML.md)
|
||||||
|
- [PLJSON_OBJECT_CACHE](packages/PLJSON_OBJECT_CACHE.md)
|
||||||
|
- [PLJSON_PARSER](packages/PLJSON_PARSER.md)
|
||||||
|
- [PLJSON_PRINTER](packages/PLJSON_PRINTER.md)
|
||||||
|
- [PLJSON_UT](packages/PLJSON_UT.md)
|
||||||
|
- [PLJSON_UTIL_PKG](packages/PLJSON_UTIL_PKG.md)
|
||||||
|
- [PLJSON_XML](packages/PLJSON_XML.md)
|
||||||
|
|
||||||
|
### [Triggers](triggers/README.md) (19)
|
||||||
|
|
||||||
|
Generazione ID:
|
||||||
|
|
||||||
|
- [EVENTI_TRG](triggers/EVENTI_TRG.md) - ID eventi + inizializzazione
|
||||||
|
- [EVENTI_AI_TRG](triggers/EVENTI_AI_TRG.md) - Creazione ospiti default
|
||||||
|
- [EVENTI_DET_PREL_TRG](triggers/EVENTI_DET_PREL_TRG.md) - ID prelievi
|
||||||
|
- [EVENTI_DET_RIS_TRG](triggers/EVENTI_DET_RIS_TRG.md) - ID risorse
|
||||||
|
- [EVENTI_DET_DEGUST_TRG](triggers/EVENTI_DET_DEGUST_TRG.md) - ID degustazioni
|
||||||
|
- [EVENTI_ACCONTI_TRG](triggers/EVENTI_ACCONTI_TRG.md) - ID acconti
|
||||||
|
- [EVENTI_ALTRICOSTI_TRG](triggers/EVENTI_ALTRICOSTI_TRG.md) - ID altri costi
|
||||||
|
- [EVENTI_ALLEG_TRG](triggers/EVENTI_ALLEG_TRG.md) - ID allegati
|
||||||
|
- [CLIENTI_TRG](triggers/CLIENTI_TRG.md) - ID clienti
|
||||||
|
- [LOCATION_TRG](triggers/LOCATION_TRG.md) - ID location
|
||||||
|
- [RISORSE_TRG](triggers/RISORSE_TRG.md) - ID risorse
|
||||||
|
- [ARTICOLI_DET_REGOLE_TRG](triggers/ARTICOLI_DET_REGOLE_TRG.md) - ID regole articoli
|
||||||
|
- [TB_TIPI_PASTO_TRG](triggers/TB_TIPI_PASTO_TRG.md) - ID tipi pasto
|
||||||
|
|
||||||
|
Business logic:
|
||||||
|
|
||||||
|
- [EVENTI_DET_OSPITI_TRG_AI](triggers/EVENTI_DET_OSPITI_TRG_AI.md) - Aggiornamento ospiti
|
||||||
|
- [EVENTI_DET_PREL_QTA_TOT_TRG](triggers/EVENTI_DET_PREL_QTA_TOT_TRG.md) - Calcolo quantità totale
|
||||||
|
|
||||||
|
Ordinamento:
|
||||||
|
|
||||||
|
- [ADD_COD_STEP](triggers/ADD_COD_STEP.md) - Ordine tipi materiale
|
||||||
|
- [ON_DELETE_REORDER](triggers/ON_DELETE_REORDER.md) - Riordino dopo delete
|
||||||
|
|
||||||
|
Sistema:
|
||||||
|
|
||||||
|
- [BI_GL_SCHEMA_CHANGES](triggers/BI_GL_SCHEMA_CHANGES.md) - Log modifiche schema
|
||||||
|
- [XLIB_LOGS_BI_TRG](triggers/XLIB_LOGS_BI_TRG.md) - Log applicazione
|
||||||
|
|
||||||
|
### [Sequences](sequences/README.md) (22)
|
||||||
|
|
||||||
|
Tutte le sequence del database.
|
||||||
|
|
||||||
|
### [Types](types/README.md) (10)
|
||||||
|
|
||||||
|
Tipi custom:
|
||||||
|
|
||||||
|
- [T_DET_OSPITI_ROW](types/T_DET_OSPITI_ROW.md) / [T_DET_OSPITI_TAB](types/T_DET_OSPITI_TAB.md) - Tipo per F_GET_OSPITI
|
||||||
|
- [T_REP_ALLESTIMENTI_ROW](types/T_REP_ALLESTIMENTI_ROW.md) / [T_REP_ALLESTIMENTI_TAB](types/T_REP_ALLESTIMENTI_TAB.md) - Tipo per F_REP_ALLESTIMENTI
|
||||||
|
- [T_REP_CUCINA_ROW](types/T_REP_CUCINA_ROW.md) / [T_REP_CUCINA_TAB](types/T_REP_CUCINA_TAB.md) - Tipo per F_REP_CUCINA
|
||||||
|
- [STRING_LIST](types/STRING_LIST.md) - Lista stringhe
|
||||||
|
- [ENUM_TABLE_OBJECT](types/ENUM_TABLE_OBJECT.md) / [ENUM_TABLE_TYPE](types/ENUM_TABLE_TYPE.md) - Tipi per STRING_TO_TABLE_ENUM
|
||||||
|
- [XLIB_VC2_ARRAY_T](types/XLIB_VC2_ARRAY_T.md) - Array varchar2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schema ER Semplificato
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐
|
||||||
|
│ CLIENTI │
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||||
|
│ LOCATION │◄────│ EVENTI │────►│TB_TIPI_EVENTO│
|
||||||
|
└─────────────┘ └──────┬──────┘ └─────────────┘
|
||||||
|
│
|
||||||
|
┌─────────────────┼─────────────────┐
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│EVENTI_DET_OSPITI│ │ EVENTI_DET_PREL │ │ EVENTI_DET_RIS │
|
||||||
|
└─────────────────┘ └────────┬────────┘ └────────┬────────┘
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│ TB_TIPI_OSPITI │ │ ARTICOLI │ │ RISORSE │
|
||||||
|
└─────────────────┘ └────────┬────────┘ └─────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ TB_CODICI_CATEG │
|
||||||
|
└────────┬────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ TB_TIPI_MAT │
|
||||||
|
└─────────────────┘
|
||||||
|
|
||||||
|
┌─────────────────┬─────────────────┐
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│EVENTI_DET_DEGUST│ │ EVENTI_ACCONTI │ │EVENTI_ALTRICOSTI│
|
||||||
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workflow Stati Evento
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────┐
|
||||||
|
│ PREVENTIVO │ (100) - Bianco
|
||||||
|
└──────┬───────┘
|
||||||
|
│ Degustazione
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│SCHEDA EVENTO │ (200) - Celeste
|
||||||
|
│(preparazione)│
|
||||||
|
└──────┬───────┘
|
||||||
|
│ Prima caparra
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ SCHEDA │ (300) - Giallo
|
||||||
|
│ CONFERMATA │
|
||||||
|
└──────┬───────┘
|
||||||
|
│ Quasi confermato
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│SCHEDA QUASI │ (350) - Arancio
|
||||||
|
│ CONFERMATA │
|
||||||
|
└──────┬───────┘
|
||||||
|
│ Conferma definitiva
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ CONFERMATO │ (400) - Verde
|
||||||
|
└──────────────┘
|
||||||
|
|
||||||
|
│ Rifiuto/Scadenza
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│NON ACCETTATO/│ (900) - Viola
|
||||||
|
│ SUPERATO │
|
||||||
|
└──────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Note per lo Sviluppo
|
||||||
|
|
||||||
|
1. **Packages PLJSON\_\***: Libreria esterna per parsing JSON, può essere sostituita con funzionalità native .NET
|
||||||
|
|
||||||
|
2. **Packages XLIB\_\***: Componenti per integrazione JasperReports, da valutare sostituzione con report .NET
|
||||||
|
|
||||||
|
3. **Trigger per ID**: In .NET usare Identity columns o GUID
|
||||||
|
|
||||||
|
4. **Calcolo quantità**: La logica in `EVENTI_AGGIORNA_QTA_LISTA` è critica e deve essere portata fedelmente
|
||||||
|
|
||||||
|
5. **Sistema acconti**: Le percentuali 30%-50%-20% sono hardcoded, valutare parametrizzazione
|
||||||
195
docs/apex/README.md
Normal file
195
docs/apex/README.md
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
# APEX Application Documentation
|
||||||
|
|
||||||
|
## Application Overview
|
||||||
|
|
||||||
|
| Property | Value |
|
||||||
|
|----------|-------|
|
||||||
|
| **Application ID** | 112 |
|
||||||
|
| **Application Name** | APCB Project |
|
||||||
|
| **Application Alias** | F_110112 |
|
||||||
|
| **APEX Version** | 21.1.0 |
|
||||||
|
| **Owner/Schema** | APOLLINARECATERINGPROD |
|
||||||
|
| **Language** | Italian (it) |
|
||||||
|
| **Date Format** | DD-MM-YYYY |
|
||||||
|
| **DateTime Format** | DD-MM-YYYY HH24:MI:SS |
|
||||||
|
| **Logo Text** | Apollinare Catering & Banqueting - Management Software |
|
||||||
|
| **Last Updated By** | MONIA |
|
||||||
|
| **Last Update** | 2025-11-24 14:06:02 |
|
||||||
|
|
||||||
|
## Application Statistics
|
||||||
|
|
||||||
|
| Component | Count |
|
||||||
|
|-----------|-------|
|
||||||
|
| **Pages** | 56 |
|
||||||
|
| **Items** | 302 |
|
||||||
|
| **Processes** | 98 |
|
||||||
|
| **Regions** | 151 |
|
||||||
|
| **Buttons** | 119 |
|
||||||
|
| **Dynamic Actions** | 62 |
|
||||||
|
| **LOVs** | 12 |
|
||||||
|
| **Authorization Schemes** | 5 |
|
||||||
|
| **Computations** | 2 |
|
||||||
|
| **Breadcrumb Entries** | 22 |
|
||||||
|
| **List Entries** | 2 |
|
||||||
|
| **Templates** | 64 |
|
||||||
|
| **Plug-ins** | 2 |
|
||||||
|
| **Messages** | 464 |
|
||||||
|
|
||||||
|
## Navigation Structure
|
||||||
|
|
||||||
|
### Desktop Navigation Menu
|
||||||
|
|
||||||
|
```
|
||||||
|
Home (Page 1)
|
||||||
|
├── Articoli (Page 2)
|
||||||
|
│ └── Impegni Articoli (Page 39)
|
||||||
|
├── Categorie (Page 4)
|
||||||
|
├── Tipi (Page 6)
|
||||||
|
├── Clienti (Page 17)
|
||||||
|
├── Location (Page 15)
|
||||||
|
├── Risorse (Page 31)
|
||||||
|
├── Permessi (Page 47) [Admin Only]
|
||||||
|
├── Gestione Dati (Page 45) [Admin Only]
|
||||||
|
├── Job Schedulati (Page 49)
|
||||||
|
├── Mail Inviate (Page 50)
|
||||||
|
└── Mail In Attesa (Page 51)
|
||||||
|
|
||||||
|
Eventi
|
||||||
|
├── Tipi Evento (Page 13) [Admin Only]
|
||||||
|
├── Nuovo Evento (Page 22) [Admin Only]
|
||||||
|
├── Schede/Schede Confermate (Page 35)
|
||||||
|
├── Liste (Page 9) [Admin Only]
|
||||||
|
├── Calendario Eventi (Page 12)
|
||||||
|
├── Degustazioni (Page 27)
|
||||||
|
└── Template Eventi (Page 48) [Admin Only]
|
||||||
|
|
||||||
|
Riepiloghi/Report
|
||||||
|
├── Griglia (Page 16) [Admin Only]
|
||||||
|
├── Riepilogo Cucina (Page 25)
|
||||||
|
├── Torte e Costi Extra (Page 28) [Admin Only]
|
||||||
|
├── Riepilogo Allestimenti (Page 30)
|
||||||
|
└── Riepilogo Risorse (Page 38)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Page Categories
|
||||||
|
|
||||||
|
### Master Data Pages
|
||||||
|
| Page ID | Name | Description |
|
||||||
|
|---------|------|-------------|
|
||||||
|
| 2 | Articoli Rpt | Article list report |
|
||||||
|
| 3 | Articoli | Article detail form |
|
||||||
|
| 4 | Categorie Rpt | Categories list report |
|
||||||
|
| 5 | Categorie | Category detail form |
|
||||||
|
| 6 | Tipi Rpt | Types list report |
|
||||||
|
| 7 | Tipi | Type detail form |
|
||||||
|
| 17 | Clienti Rpt | Clients list report |
|
||||||
|
| 18 | Clienti | Client detail form |
|
||||||
|
| 15 | Location Rpt | Locations list report |
|
||||||
|
| 20 | Location | Location detail form |
|
||||||
|
| 31 | Risorse | Resources (staff) management |
|
||||||
|
|
||||||
|
### Event Management Pages
|
||||||
|
| Page ID | Name | Description |
|
||||||
|
|---------|------|-------------|
|
||||||
|
| 1 | Home | Dashboard |
|
||||||
|
| 8 | Nuovo Evento Wizard | Event creation wizard |
|
||||||
|
| 9 | Lista Eventi | Event list |
|
||||||
|
| 12 | Calendario | Event calendar |
|
||||||
|
| 13 | Tipi Evento Rpt | Event types list |
|
||||||
|
| 14 | Tipi Evento | Event type detail form |
|
||||||
|
| **22** | **Nuovo Evento** | **Main event form (most complex)** |
|
||||||
|
| 27 | Lista Degustazioni | Tastings list |
|
||||||
|
| 32 | Degustazione | Tasting detail |
|
||||||
|
| 35 | Schede/Schede Confermate | Event cards |
|
||||||
|
| 48 | Template Eventi | Event templates |
|
||||||
|
|
||||||
|
### Report Pages
|
||||||
|
| Page ID | Name | Description |
|
||||||
|
|---------|------|-------------|
|
||||||
|
| 16 | Griglia | Grid view |
|
||||||
|
| 25 | Riepilogo Cucina | Kitchen summary |
|
||||||
|
| 28 | Torte e Costi Extra | Cakes and extra costs |
|
||||||
|
| 30 | Riepilogo Allestimenti | Setup summary |
|
||||||
|
| 38 | Riepilogo Risorse | Resources summary |
|
||||||
|
| 39 | Impegni Articoli | Article commitments |
|
||||||
|
|
||||||
|
### Administration Pages
|
||||||
|
| Page ID | Name | Description |
|
||||||
|
|---------|------|-------------|
|
||||||
|
| 45 | Gestione Dati | Data management |
|
||||||
|
| 46 | Max Eventi | Max events configuration |
|
||||||
|
| 47 | Permessi | Permissions management |
|
||||||
|
| 49 | Job Schedulati | Scheduled jobs |
|
||||||
|
| 50 | Mail Inviate | Sent emails |
|
||||||
|
| 51 | Mail In Attesa | Pending emails |
|
||||||
|
|
||||||
|
## Page 22 (Nuovo Evento) - Most Complex Page
|
||||||
|
|
||||||
|
Page 22 is the main event management page with the highest complexity:
|
||||||
|
|
||||||
|
| Component | Count |
|
||||||
|
|-----------|-------|
|
||||||
|
| Items | 108 |
|
||||||
|
| Regions | 33 |
|
||||||
|
| Buttons | 32 |
|
||||||
|
| Processes | 32 |
|
||||||
|
| Dynamic Actions | Multiple |
|
||||||
|
|
||||||
|
### Key Features:
|
||||||
|
- Multiple Interactive Grids (master-detail)
|
||||||
|
- Guest type management with quantity recalculations
|
||||||
|
- Resource assignments
|
||||||
|
- Pick list management with coefficient-based calculations
|
||||||
|
- Event status workflow management
|
||||||
|
- Template support
|
||||||
|
- Versioning system
|
||||||
|
|
||||||
|
## Documentation Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/apex/
|
||||||
|
├── README.md (this file)
|
||||||
|
├── pages/ # Individual page documentation
|
||||||
|
├── processes/ # Process documentation
|
||||||
|
├── lovs/ # List of Values documentation
|
||||||
|
├── javascript/ # JavaScript libraries
|
||||||
|
├── authorization/ # Authorization schemes
|
||||||
|
├── dynamic-actions/ # Dynamic actions
|
||||||
|
├── items/ # Shared items
|
||||||
|
├── regions/ # Shared regions
|
||||||
|
└── navigation/ # Navigation components
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Files
|
||||||
|
|
||||||
|
- [LOVs Documentation](lovs/README.md) - List of Values definitions
|
||||||
|
- [Processes Documentation](processes/README.md) - PL/SQL processes
|
||||||
|
- [JavaScript Libraries](javascript/README.md) - Custom JavaScript
|
||||||
|
- [Authorization Schemes](authorization/README.md) - Security settings
|
||||||
|
- [Page 22 Documentation](pages/PAGE_022.md) - Main event form
|
||||||
|
|
||||||
|
## Event Status Workflow
|
||||||
|
|
||||||
|
```
|
||||||
|
100 (Preventivo/Quote)
|
||||||
|
↓ [Continue Event]
|
||||||
|
200 (Scheda/Preparazione)
|
||||||
|
↓ [Return to Preparazione]
|
||||||
|
300 (Confermata/Quasi)
|
||||||
|
↓ [Almost Continue Event]
|
||||||
|
350 (Quasi Confermato)
|
||||||
|
↓ [Confirm Event]
|
||||||
|
400 (Confermato/Confirmed)
|
||||||
|
↓ [Set Obsoleto]
|
||||||
|
900 (Superato/Expired)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authorization Schemes
|
||||||
|
|
||||||
|
| Scheme Name | Description |
|
||||||
|
|-------------|-------------|
|
||||||
|
| Admin_auth_schema | Full admin access |
|
||||||
|
| User Read/Write | Controlled by USERS_READONLY table |
|
||||||
|
| Consuntivi | Financial summaries access |
|
||||||
|
| Gestori | Manager-level permissions |
|
||||||
|
| Solo Admins | Highest level (admin, monia only) |
|
||||||
296
docs/apex/authorization/README.md
Normal file
296
docs/apex/authorization/README.md
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
# Authorization Schemes Documentation
|
||||||
|
|
||||||
|
This document describes the 5 authorization schemes used in the APEX application for access control.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
| Scheme Name | Type | Users/Condition | Error Message |
|
||||||
|
|-------------|------|-----------------|---------------|
|
||||||
|
| Admin_auth_schema | NATIVE_EXISTS | Specific user list | Utente non autorizzato |
|
||||||
|
| User Read/Write | NATIVE_FUNCTION_BODY | USERS_READONLY table | Utente abilitato in sola lettura |
|
||||||
|
| Consuntivi | NATIVE_EXISTS | GET_CONSUNTIVI_USERS view | Autorizzazione necessaria... |
|
||||||
|
| Gestori | NATIVE_EXISTS | GET_GESTORI_USERS view | Non possiedi i permessi... |
|
||||||
|
| Solo Admins | NATIVE_EXISTS | admin, monia only | Non possiedi i permessi... |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Admin_auth_schema
|
||||||
|
|
||||||
|
**Type:** NATIVE_EXISTS
|
||||||
|
**Caching:** BY_USER_BY_PAGE_VIEW
|
||||||
|
|
||||||
|
**SQL Query:**
|
||||||
|
```sql
|
||||||
|
select 1 from dual
|
||||||
|
where lower(:APP_USER) in ('admin','monia','andrea','maria','sabrina','nicole','cucina','developer','elia.ballarani');
|
||||||
|
```
|
||||||
|
|
||||||
|
**Authorized Users:**
|
||||||
|
- admin
|
||||||
|
- monia
|
||||||
|
- andrea
|
||||||
|
- maria
|
||||||
|
- sabrina
|
||||||
|
- nicole
|
||||||
|
- cucina
|
||||||
|
- developer
|
||||||
|
- elia.ballarani
|
||||||
|
|
||||||
|
**Usage:** General administrative access to most management pages.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## User Read/Write
|
||||||
|
|
||||||
|
**Type:** NATIVE_FUNCTION_BODY
|
||||||
|
**Caching:** BY_USER_BY_PAGE_VIEW
|
||||||
|
|
||||||
|
**PL/SQL Function:**
|
||||||
|
```plsql
|
||||||
|
declare
|
||||||
|
v_readonly number;
|
||||||
|
begin
|
||||||
|
select 1
|
||||||
|
into v_readonly
|
||||||
|
from users_readonly
|
||||||
|
where username = :APP_USER
|
||||||
|
and flgwrite = 0;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
exception when no_data_found then
|
||||||
|
return true;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Logic:**
|
||||||
|
- Checks `USERS_READONLY` table
|
||||||
|
- If user exists with `FLGWRITE = 0` → Returns FALSE (read-only mode)
|
||||||
|
- If user not found → Returns TRUE (write access)
|
||||||
|
|
||||||
|
**Usage:** Controls whether user can modify data or only view.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Consuntivi
|
||||||
|
|
||||||
|
**Type:** NATIVE_EXISTS
|
||||||
|
**Caching:** BY_USER_BY_PAGE_VIEW
|
||||||
|
|
||||||
|
**SQL Query:**
|
||||||
|
```sql
|
||||||
|
select 1 from dual
|
||||||
|
where :APP_USER in (select users from get_consuntivi_users);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Data Source:** `GET_CONSUNTIVI_USERS` view
|
||||||
|
|
||||||
|
**Usage:** Access to financial summary pages and cost management.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gestori
|
||||||
|
|
||||||
|
**Type:** NATIVE_EXISTS
|
||||||
|
**Caching:** BY_USER_BY_PAGE_VIEW
|
||||||
|
|
||||||
|
**SQL Query:**
|
||||||
|
```sql
|
||||||
|
select 1 from dual
|
||||||
|
where :APP_USER in (select users from get_gestori_users);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Data Source:** `GET_GESTORI_USERS` view
|
||||||
|
|
||||||
|
**Usage:** Manager-level access. Applied to:
|
||||||
|
- Home page
|
||||||
|
- Nuovo Evento (Page 22)
|
||||||
|
- Liste (Page 9)
|
||||||
|
- Griglia (Page 16)
|
||||||
|
- Torte e Costi Extra (Page 28)
|
||||||
|
- Template Eventi (Page 48)
|
||||||
|
- Tipi Evento (Page 13)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Solo Admins
|
||||||
|
|
||||||
|
**Type:** NATIVE_EXISTS
|
||||||
|
**Caching:** BY_USER_BY_PAGE_VIEW
|
||||||
|
|
||||||
|
**SQL Query:**
|
||||||
|
```sql
|
||||||
|
select 1 from dual
|
||||||
|
where lower(:APP_USER) in ('admin', 'monia');
|
||||||
|
```
|
||||||
|
|
||||||
|
**Authorized Users:**
|
||||||
|
- admin
|
||||||
|
- monia
|
||||||
|
|
||||||
|
**Usage:** Highest level of access. Reserved for:
|
||||||
|
- Permessi (Page 47)
|
||||||
|
- Gestione Dati (Page 45)
|
||||||
|
- Critical configuration pages
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Application-Level Processes
|
||||||
|
|
||||||
|
### SET_USER_READONLY
|
||||||
|
|
||||||
|
**Process Point:** Before Header (runs on every page)
|
||||||
|
**Sequence:** 1
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
select 1
|
||||||
|
into :APP_READ_ONLY
|
||||||
|
from users_readonly
|
||||||
|
where username = :APP_USER
|
||||||
|
and flgwrite = 0;
|
||||||
|
exception when no_data_found then
|
||||||
|
:APP_READ_ONLY := 0;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Sets:** `APP_READ_ONLY` application item
|
||||||
|
- Value `1` = Read-only mode
|
||||||
|
- Value `0` = Full access
|
||||||
|
|
||||||
|
This is checked in page processes with condition:
|
||||||
|
```plsql
|
||||||
|
:APP_READ_ONLY = 0
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### SET_ITEM_SESSION
|
||||||
|
|
||||||
|
**Process Point:** On Demand
|
||||||
|
**Security:** MUST_NOT_BE_PUBLIC_USER
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
declare
|
||||||
|
v_itemList varchar2(32000);
|
||||||
|
begin
|
||||||
|
v_itemList := APEX_UTIL.TABLE_TO_STRING(APEX_APPLICATION.G_F01);
|
||||||
|
|
||||||
|
for c in (
|
||||||
|
select
|
||||||
|
(select result from table(STRING_TO_TABLE_ENUM(a.result, 1, '='))) as item,
|
||||||
|
(select result from table(STRING_TO_TABLE_ENUM(a.result, 2, '='))) as val
|
||||||
|
from table(STRING_TO_TABLE_ENUM(v_itemList)) a
|
||||||
|
)
|
||||||
|
loop
|
||||||
|
APEX_UTIL.set_session_state(
|
||||||
|
p_name => c.item,
|
||||||
|
p_value => c.val
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:** Called by `setSessionState()` JavaScript function to update APEX session state for multiple items.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Application Items
|
||||||
|
|
||||||
|
### APP_READ_ONLY
|
||||||
|
|
||||||
|
**Protection Level:** Internal
|
||||||
|
**Escape on HTTP Output:** No
|
||||||
|
|
||||||
|
Stores the read-only flag for the current user session.
|
||||||
|
|
||||||
|
### APP_VERSION
|
||||||
|
|
||||||
|
Application version identifier.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Authorization Hierarchy
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ Solo Admins │
|
||||||
|
│ (admin, monia) │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ Admin_auth_schema │
|
||||||
|
│ (admin, monia, andrea, maria, sabrina, nicole, │
|
||||||
|
│ cucina, developer, elia.ballarani) │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ Gestori │
|
||||||
|
│ (from GET_GESTORI_USERS view) │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ Consuntivi │
|
||||||
|
│ (from GET_CONSUNTIVI_USERS view) │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ User Read/Write │
|
||||||
|
│ (based on USERS_READONLY.FLGWRITE flag) │
|
||||||
|
├─────────────────────────────────────────────────────────────┤
|
||||||
|
│ Authenticated Users │
|
||||||
|
│ (basic application access) │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Database Objects for Authorization
|
||||||
|
|
||||||
|
### USERS_READONLY Table
|
||||||
|
|
||||||
|
| Column | Type | Description |
|
||||||
|
|--------|------|-------------|
|
||||||
|
| USERNAME | VARCHAR2 | APEX username |
|
||||||
|
| FLGWRITE | NUMBER | 0 = read-only, 1 = write |
|
||||||
|
|
||||||
|
### GET_GESTORI_USERS View
|
||||||
|
|
||||||
|
Returns list of users with manager permissions.
|
||||||
|
|
||||||
|
### GET_CONSUNTIVI_USERS View
|
||||||
|
|
||||||
|
Returns list of users with financial access.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration Notes
|
||||||
|
|
||||||
|
When migrating to .NET + React:
|
||||||
|
|
||||||
|
1. **Authentication**
|
||||||
|
- Implement JWT or cookie-based authentication
|
||||||
|
- Consider integration with existing Oracle users or migrate to new system
|
||||||
|
|
||||||
|
2. **Authorization**
|
||||||
|
- Map authorization schemes to .NET roles/claims
|
||||||
|
- Implement policy-based authorization in .NET
|
||||||
|
|
||||||
|
3. **Role Mapping**
|
||||||
|
```csharp
|
||||||
|
public enum UserRole
|
||||||
|
{
|
||||||
|
User, // Basic authenticated user
|
||||||
|
ReadOnly, // Read-only access
|
||||||
|
Consuntivi, // Financial access
|
||||||
|
Gestori, // Manager level
|
||||||
|
Admin, // Admin_auth_schema equivalent
|
||||||
|
SuperAdmin // Solo Admins equivalent
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Frontend Authorization**
|
||||||
|
- Store user roles in JWT/session
|
||||||
|
- Implement route guards in React
|
||||||
|
- Conditionally render UI elements based on permissions
|
||||||
|
|
||||||
|
5. **Backend Authorization**
|
||||||
|
```csharp
|
||||||
|
[Authorize(Policy = "Gestori")]
|
||||||
|
public class EventController : Controller
|
||||||
|
{
|
||||||
|
[Authorize(Policy = "SoloAdmins")]
|
||||||
|
public IActionResult DeleteEvent(int id) { ... }
|
||||||
|
}
|
||||||
|
```
|
||||||
53282
docs/apex/f112.sql
Normal file
53282
docs/apex/f112.sql
Normal file
File diff suppressed because it is too large
Load Diff
330
docs/apex/javascript/README.md
Normal file
330
docs/apex/javascript/README.md
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
# JavaScript Libraries Documentation
|
||||||
|
|
||||||
|
This document describes the custom JavaScript libraries used in the APEX application.
|
||||||
|
|
||||||
|
## Static Application Files
|
||||||
|
|
||||||
|
| File Name | Description |
|
||||||
|
|-----------|-------------|
|
||||||
|
| ajaxUtils.js | AJAX utilities for dynamic updates and server communication |
|
||||||
|
| iframeObj.js | Jasper Reports integration wrapper |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ajaxUtils.js
|
||||||
|
|
||||||
|
Custom AJAX utility library for managing server-side communication and UI feedback.
|
||||||
|
|
||||||
|
### Functions
|
||||||
|
|
||||||
|
#### `notifica(pText, pType = null)`
|
||||||
|
|
||||||
|
Central dynamic notification function.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `pText` (string): Message text to display
|
||||||
|
- `pType` (string, optional): Notification type - 'alert', 'success', 'error', 'warning', 'info'
|
||||||
|
|
||||||
|
**Behavior:**
|
||||||
|
- Clears existing errors
|
||||||
|
- If `pType` is provided, shows error notification at page level
|
||||||
|
- If `pType` is null, shows success message
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
notifica("Record saved successfully"); // Success message
|
||||||
|
notifica("Error occurred", "error"); // Error message
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `setSessionState(elemList, pCallback = null)`
|
||||||
|
|
||||||
|
Sets APEX session state for multiple items.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `elemList` (string): Comma-separated list of item IDs (without P prefix)
|
||||||
|
- `pCallback` (function, optional): Callback function after session state is set
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
1. Splits the element list by comma
|
||||||
|
2. Gets values for each element using jQuery
|
||||||
|
3. Creates a dictionary of item-value pairs
|
||||||
|
4. Calls APEX process `SET_ITEM_SESSION` to update session state
|
||||||
|
5. Executes callback with data and elements dictionary
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
setSessionState("P22_EVENT_ID,P22_CLIENTE", function(pData, elems) {
|
||||||
|
console.log("Session state updated");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `ajaxExec(pName, clickObj, pParams, pCallback, pConfirm, pLoading, pAsync, pType)`
|
||||||
|
|
||||||
|
Generic AJAX execution wrapper for APEX server processes.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `pName` (string): APEX process name to execute
|
||||||
|
- `clickObj` (jQuery object): Button/element that triggered the action
|
||||||
|
- `pParams` (object): Parameters to pass to the process
|
||||||
|
- `pCallback` (function): Callback function on success/error
|
||||||
|
- `pConfirm` (string): Confirmation message (uses native confirm dialog)
|
||||||
|
- `pLoading` (boolean): Show loading popup
|
||||||
|
- `pAsync` (boolean): Execute asynchronously
|
||||||
|
- `pType` (string): Response data type (default: 'text')
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Prevents page unload during execution
|
||||||
|
- Shows loading spinner on clicked element
|
||||||
|
- Handles confirmation dialogs
|
||||||
|
- Parses response and removes quotes
|
||||||
|
- Executes callback with parsed data
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
ajaxExec("SAVE_EVENT", clickBtn, {x01: eventId}, function(data, btn, params) {
|
||||||
|
notifica("Event saved");
|
||||||
|
}, "Are you sure?", true);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `execProcessAsync(pName, pParams, pPreExec, pCallback, pItems = null, clickObj = null, pConfirm = null, pLoading = null)`
|
||||||
|
|
||||||
|
Wrapper for async process execution with optional session state update.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `pName` (string): Process name
|
||||||
|
- `pParams` (object): Process parameters
|
||||||
|
- `pPreExec` (function): Function to execute before AJAX call
|
||||||
|
- `pCallback` (function): Callback after process execution
|
||||||
|
- `pItems` (string): Items to set in session state first
|
||||||
|
- `clickObj`: Clicked element
|
||||||
|
- `pConfirm` (string): Confirmation message
|
||||||
|
- `pLoading` (boolean): Show loading indicator
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
execProcessAsync("UPDATE_QTY", {x01: itemId}, null, function(data) {
|
||||||
|
apex.region("LIST_PREL").refresh();
|
||||||
|
}, "P22_EVENT_ID");
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `execQueryAsync(pQuery, pPreExec, pCallback, clickObj = null, pConfirm = null, pItems = null, pLoading = null)`
|
||||||
|
|
||||||
|
Executes a SQL query asynchronously.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `pQuery` (string): SQL query to execute
|
||||||
|
- `pPreExec` (function): Pre-execution function
|
||||||
|
- `pCallback` (function): Callback with query results
|
||||||
|
- `clickObj`: Clicked element
|
||||||
|
- `pConfirm` (string): Confirmation message
|
||||||
|
- `pItems` (string): Items to set in session state
|
||||||
|
- `pLoading` (boolean): Show loading indicator
|
||||||
|
|
||||||
|
**Note:** Calls the `EXEC_QUERY` APEX process with the query in `x01` parameter.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## iframeObj.js
|
||||||
|
|
||||||
|
JavaScript wrapper for embedding Jasper Reports in iframes.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var j_datasource = "default"; // Jasper datasource name
|
||||||
|
var j_username = "jasperadmin"; // Jasper server username
|
||||||
|
var j_password = "jasperadmin"; // Jasper server password
|
||||||
|
var j_def_outp = "pdf"; // Default output format (HTML, PDF)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Iframe Class
|
||||||
|
|
||||||
|
#### Constructor
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var Iframe = function(parentObj, id, attr) { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `parentObj`: Parent DOM element
|
||||||
|
- `id`: Iframe element ID
|
||||||
|
- `attr`: Additional attributes
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
|
||||||
|
#### `setCss(css)`
|
||||||
|
|
||||||
|
Sets CSS styles on the iframe.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `css` (object): CSS properties dictionary
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
iframe.setCss({ width: "100%", height: "600px", border: "none" });
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `setUrl(Url)`
|
||||||
|
|
||||||
|
Sets the iframe source URL.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `getUrl()`
|
||||||
|
|
||||||
|
Returns the current iframe URL.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `refresh()`
|
||||||
|
|
||||||
|
Reloads the iframe content.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `hide()`
|
||||||
|
|
||||||
|
Hides the iframe (display: none).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `show()`
|
||||||
|
|
||||||
|
Shows the iframe (display: block).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `jasperReport(dir, datasource, params, output, username, password)`
|
||||||
|
|
||||||
|
Generates a Jasper Reports URL and loads it in the iframe.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `dir` (string, required): Report path in Jasper server
|
||||||
|
- `datasource` (string): Data source name (default: "default")
|
||||||
|
- `params` (object): Report parameters as key-value pairs
|
||||||
|
- `output` (string): Output format - 'pdf' or 'html' (default: 'pdf')
|
||||||
|
- `username` (string): Jasper server username
|
||||||
|
- `password` (string): Jasper server password
|
||||||
|
|
||||||
|
**URL Format:**
|
||||||
|
```
|
||||||
|
/jri/report?_repName={dir}&_repFormat={output}&_dataSource={datasource}&_repLocale=it_IT&_repTimeZone=Europe/Rome&{params}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
var rptFrame = new Iframe(container, "reportFrame");
|
||||||
|
rptFrame.jasperReport(
|
||||||
|
"apcb/scheda_evento_rpt",
|
||||||
|
"default",
|
||||||
|
{ P_EVENT_ID: eventId, P_TIPO: "PREVENTIVO" },
|
||||||
|
"pdf"
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage in APEX Pages
|
||||||
|
|
||||||
|
### Time Input Masks
|
||||||
|
|
||||||
|
The application uses inputmask library for time fields:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Inputmask("99:99", {
|
||||||
|
placeholder: "HH:MM"
|
||||||
|
}).mask($("#P22_ORA_INI_EVENTO"));
|
||||||
|
```
|
||||||
|
|
||||||
|
### SweetAlert2 Integration
|
||||||
|
|
||||||
|
Used for enhanced confirmation dialogs:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Conferma',
|
||||||
|
text: 'Vuoi continuare?',
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
// proceed
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interactive Grid Refresh
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Refresh a specific interactive grid
|
||||||
|
apex.region("LISTA_PRELIEVO").refresh();
|
||||||
|
|
||||||
|
// Refresh with callback
|
||||||
|
apex.region("OSPITI").widget().interactiveGrid("getViews", "grid").model.fetchRecords();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration Notes
|
||||||
|
|
||||||
|
When migrating to React TypeScript:
|
||||||
|
|
||||||
|
1. **AJAX Utilities** - Replace with:
|
||||||
|
- Axios or fetch for HTTP requests
|
||||||
|
- React Query or SWR for data fetching
|
||||||
|
- Toast library (react-toastify) for notifications
|
||||||
|
|
||||||
|
2. **Session State** - Replace with:
|
||||||
|
- React Context or Redux for state management
|
||||||
|
- URL parameters for shareable state
|
||||||
|
- Session storage for persistence
|
||||||
|
|
||||||
|
3. **Jasper Reports** - Options:
|
||||||
|
- Keep Jasper and embed via iframe
|
||||||
|
- Migrate to SSRS, Crystal Reports
|
||||||
|
- Use PDF libraries (QuestPDF, iTextSharp)
|
||||||
|
- Use React-PDF for client-side PDF generation
|
||||||
|
|
||||||
|
4. **Input Masks** - Use:
|
||||||
|
- react-input-mask
|
||||||
|
- @react-input/mask
|
||||||
|
- Material-UI TextField with InputProps
|
||||||
|
|
||||||
|
5. **SweetAlert2** - Replace with:
|
||||||
|
- MUI Dialog components
|
||||||
|
- react-confirm-alert
|
||||||
|
- Custom modal component
|
||||||
|
|
||||||
|
### Example React Migration
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ajaxUtils.js equivalent in React
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
export const notifica = (text: string, type?: 'success' | 'error' | 'warning' | 'info') => {
|
||||||
|
if (type) {
|
||||||
|
toast[type](text);
|
||||||
|
} else {
|
||||||
|
toast.success(text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const executeProcess = async <T>(
|
||||||
|
processName: string,
|
||||||
|
params: Record<string, any>
|
||||||
|
): Promise<T> => {
|
||||||
|
const response = await axios.post(`/api/processes/${processName}`, params);
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
```
|
||||||
242
docs/apex/lovs/README.md
Normal file
242
docs/apex/lovs/README.md
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
# List of Values (LOVs) Documentation
|
||||||
|
|
||||||
|
This document contains all 12 List of Values defined in the APEX application.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
| LOV Name | Source Type | Description |
|
||||||
|
|----------|-------------|-------------|
|
||||||
|
| ARTICOLI | SQL Query | Article selection |
|
||||||
|
| CATEGORIE | SQL Query | Category selection |
|
||||||
|
| CLIENTI | SQL Query | Client selection |
|
||||||
|
| LOCATION | SQL Query | Location selection |
|
||||||
|
| RISORSE | SQL Query | Resource (staff) selection |
|
||||||
|
| STATO_EVENTO | Static | Event status values |
|
||||||
|
| TIPI MAT | SQL Query | Material type selection |
|
||||||
|
| TIPI RISORSE | SQL Query | Resource type selection |
|
||||||
|
| TIPO_EVENTO | SQL Query | Event type selection |
|
||||||
|
| TIPO_OSPITI | SQL Query | Guest type selection |
|
||||||
|
| TIPO_PASTO | Static | Meal type values |
|
||||||
|
| USERS | SQL Query | User selection |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ARTICOLI
|
||||||
|
|
||||||
|
**Source Type:** SQL Query (LEGACY_SQL)
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
```sql
|
||||||
|
select /*a.cod_categ || ' - ' || c.descrizione || ' - ' ||*/ a.DESCRIZIONE as descrizione, a.COD_ARTICOLO
|
||||||
|
from articoli a
|
||||||
|
join tb_codici_categ c on a.cod_categ = c.cod_categ
|
||||||
|
order by 1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:** Selecting articles in pick lists and event details.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CATEGORIE
|
||||||
|
|
||||||
|
**Source Type:** SQL Query (LEGACY_SQL)
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
```sql
|
||||||
|
SELECT descrizione as d,
|
||||||
|
cod_categ as r
|
||||||
|
FROM tb_codici_categ
|
||||||
|
ORDER BY 1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:** Filtering articles by category, category selection in forms.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CLIENTI
|
||||||
|
|
||||||
|
**Source Type:** SQL Query (LEGACY_SQL)
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
```sql
|
||||||
|
select CLIENTE, ID
|
||||||
|
from clienti
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:** Client selection in event forms.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## LOCATION
|
||||||
|
|
||||||
|
**Source Type:** SQL Query (LEGACY_SQL)
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
```sql
|
||||||
|
select location || ' - ' || indirizzo, id
|
||||||
|
from location
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:** Location selection in event forms. Displays location name with address.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## RISORSE
|
||||||
|
|
||||||
|
**Source Type:** SQL Query (LEGACY_SQL)
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
```sql
|
||||||
|
select NOME || ' ' || COGNOME d, id r
|
||||||
|
from risorse
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:** Resource (staff) assignment in events. Displays full name.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## STATO_EVENTO
|
||||||
|
|
||||||
|
**Source Type:** Static
|
||||||
|
|
||||||
|
**Values:**
|
||||||
|
|
||||||
|
| Display Value | Return Value | Sequence |
|
||||||
|
|---------------|--------------|----------|
|
||||||
|
| Scheda Evento (Preparazione) | 0 | 10 |
|
||||||
|
| Preventivo | 10 | 20 |
|
||||||
|
| Confermato | 20 | 30 |
|
||||||
|
|
||||||
|
**Note:** The actual status values in the database have been expanded:
|
||||||
|
- 100 = Preventivo
|
||||||
|
- 200 = Scheda
|
||||||
|
- 300 = Confermata
|
||||||
|
- 350 = Quasi Confermato
|
||||||
|
- 400 = Confermato
|
||||||
|
- 900 = Superato
|
||||||
|
|
||||||
|
**Usage:** Event status display and selection.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TIPI MAT
|
||||||
|
|
||||||
|
**Source Type:** SQL Query (LEGACY_SQL)
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
```sql
|
||||||
|
SELECT descrizione as d,
|
||||||
|
cod_tipo as r
|
||||||
|
FROM tb_tipi_mat
|
||||||
|
ORDER BY 1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:** Material type filtering in pick lists. Controls the step-by-step wizard flow.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TIPI RISORSE
|
||||||
|
|
||||||
|
**Source Type:** SQL Query (LEGACY_SQL)
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
```sql
|
||||||
|
select descrizione, cod_tipo
|
||||||
|
from tb_tipi_risorsa
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:** Resource type classification (camerieri, cuochi, etc.).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TIPO_EVENTO
|
||||||
|
|
||||||
|
**Source Type:** SQL Query (LEGACY_SQL)
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
```sql
|
||||||
|
select trim(DESCRIZIONE) || decode(tipo_pasto, 'C', ' - Cena', 'P', ' - Pranzo', null) as d,
|
||||||
|
COD_TIPO as r
|
||||||
|
from tb_tipi_evento
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:** Event type selection. Displays description with meal type indicator (Pranzo/Cena).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TIPO_OSPITI
|
||||||
|
|
||||||
|
**Source Type:** SQL Query (LEGACY_SQL)
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
```sql
|
||||||
|
select descrizione as d,
|
||||||
|
cod_tipo as r
|
||||||
|
from tb_tipi_ospiti
|
||||||
|
order by 1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:** Guest type selection in event guest details.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TIPO_PASTO
|
||||||
|
|
||||||
|
**Source Type:** Static
|
||||||
|
|
||||||
|
**Values:**
|
||||||
|
|
||||||
|
| Display Value | Return Value | Sequence |
|
||||||
|
|---------------|--------------|----------|
|
||||||
|
| Pranzo | P | 1 |
|
||||||
|
| Cena | C | 2 |
|
||||||
|
| Pranzo Buffet | A | 3 |
|
||||||
|
| Cena Buffet | B | 4 |
|
||||||
|
|
||||||
|
**Usage:** Meal type classification for events and event types.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## USERS
|
||||||
|
|
||||||
|
**Source Type:** SQL Query
|
||||||
|
|
||||||
|
**Query:**
|
||||||
|
```sql
|
||||||
|
select user_name D, user_name R
|
||||||
|
from WWV_FLOW_USERS
|
||||||
|
```
|
||||||
|
|
||||||
|
**Return Column:** R
|
||||||
|
**Display Column:** D
|
||||||
|
|
||||||
|
**Usage:** User selection for permissions and assignments.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration Notes
|
||||||
|
|
||||||
|
When migrating to React TypeScript:
|
||||||
|
|
||||||
|
1. **Static LOVs** (STATO_EVENTO, TIPO_PASTO) can be implemented as TypeScript enums or const objects
|
||||||
|
2. **SQL-based LOVs** should be converted to API endpoints
|
||||||
|
3. Consider caching strategy for frequently used LOVs (CATEGORIE, TIPI MAT, etc.)
|
||||||
|
4. TIPO_EVENTO uses Oracle `decode()` function - convert to CASE WHEN or handle in API
|
||||||
|
|
||||||
|
### Example TypeScript Implementation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Static LOV - TIPO_PASTO
|
||||||
|
export const TIPO_PASTO = {
|
||||||
|
PRANZO: { value: 'P', label: 'Pranzo' },
|
||||||
|
CENA: { value: 'C', label: 'Cena' },
|
||||||
|
PRANZO_BUFFET: { value: 'A', label: 'Pranzo Buffet' },
|
||||||
|
CENA_BUFFET: { value: 'B', label: 'Cena Buffet' },
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// Dynamic LOV - API endpoint
|
||||||
|
// GET /api/lovs/articoli
|
||||||
|
// GET /api/lovs/categorie
|
||||||
|
// GET /api/lovs/clienti
|
||||||
|
// etc.
|
||||||
|
```
|
||||||
5
docs/apex/pages/PAGE_002.md
Normal file
5
docs/apex/pages/PAGE_002.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Page 2 - Articoli Rpt
|
||||||
|
|
||||||
|
## Items (1)
|
||||||
|
|
||||||
|
- `P2_IMMAGINE`
|
||||||
25
docs/apex/pages/PAGE_003.md
Normal file
25
docs/apex/pages/PAGE_003.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Page 3 - Articoli
|
||||||
|
|
||||||
|
## Items (21)
|
||||||
|
|
||||||
|
- `P3_COD_ARTICOLO`
|
||||||
|
- `P3_COD_CATEG`
|
||||||
|
- `P3_COD_RELATIVO`
|
||||||
|
- `P3_COEFF`
|
||||||
|
- `P3_COEFF_A`
|
||||||
|
- `P3_COEFF_B`
|
||||||
|
- `P3_COEFF_S`
|
||||||
|
- `P3_DESCRIZIONE`
|
||||||
|
- `P3_FLG_CUCINA`
|
||||||
|
- `P3_IMMAGINE`
|
||||||
|
- `P3_IMMAGINE_DISPLAY`
|
||||||
|
- `P3_PERC_IVA`
|
||||||
|
- `P3_PERC_OSPITI`
|
||||||
|
- `P3_QTAGIAC`
|
||||||
|
- `P3_QTAIMP`
|
||||||
|
- `P3_QTA_STD_A`
|
||||||
|
- `P3_QTA_STD_B`
|
||||||
|
- `P3_QTA_STD_S`
|
||||||
|
- `P3_RANK`
|
||||||
|
- `P3_ROWID`
|
||||||
|
- `P3_TIPO_QTA`
|
||||||
13
docs/apex/pages/PAGE_005.md
Normal file
13
docs/apex/pages/PAGE_005.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Page 5 - Categorie
|
||||||
|
|
||||||
|
## Items (9)
|
||||||
|
|
||||||
|
- `P5_COD_CATEG`
|
||||||
|
- `P5_COD_TIPO`
|
||||||
|
- `P5_COEFF_A`
|
||||||
|
- `P5_COEFF_B`
|
||||||
|
- `P5_COEFF_S`
|
||||||
|
- `P5_DESCRIZIONE`
|
||||||
|
- `P5_ROWID`
|
||||||
|
- `P5_SHOW_PRINT`
|
||||||
|
- `P5_TIPO_RIEPILOGO`
|
||||||
7
docs/apex/pages/PAGE_007.md
Normal file
7
docs/apex/pages/PAGE_007.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Page 7 - Tipi
|
||||||
|
|
||||||
|
## Items (3)
|
||||||
|
|
||||||
|
- `P7_COD_TIPO`
|
||||||
|
- `P7_DESCRIZIONE`
|
||||||
|
- `P7_ROWID`
|
||||||
39
docs/apex/pages/PAGE_008.md
Normal file
39
docs/apex/pages/PAGE_008.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Page 8 - Creazione Evento
|
||||||
|
|
||||||
|
## Items (35)
|
||||||
|
|
||||||
|
- `P8_ALLERGIE`
|
||||||
|
- `P8_CATEG`
|
||||||
|
- `P8_CATEG_FILTER`
|
||||||
|
- `P8_CLIENTE`
|
||||||
|
- `P8_CLIENTE_DISPLAY`
|
||||||
|
- `P8_COD_TIPO`
|
||||||
|
- `P8_COD_TIPO_DISPLAY`
|
||||||
|
- `P8_COD_TIPO_FILTER`
|
||||||
|
- `P8_CONFETTATA`
|
||||||
|
- `P8_DATA`
|
||||||
|
- `P8_DATA_DISPLAY`
|
||||||
|
- `P8_DESCRIZIONE`
|
||||||
|
- `P8_DESCRIZIONE_DISPLAY`
|
||||||
|
- `P8_EVENT_ID`
|
||||||
|
- `P8_FLG_TEMPLATE`
|
||||||
|
- `P8_ID_IMAGE_SHOW`
|
||||||
|
- `P8_INDIRIZZO`
|
||||||
|
- `P8_INDIRIZZO_DISPLAY`
|
||||||
|
- `P8_LOCATION`
|
||||||
|
- `P8_LOCATION_DISPLAY`
|
||||||
|
- `P8_MAXSTEP`
|
||||||
|
- `P8_NOTE`
|
||||||
|
- `P8_NOTE_DISPLAY`
|
||||||
|
- `P8_ORA_INI_CER`
|
||||||
|
- `P8_ORA_INI_EVT`
|
||||||
|
- `P8_PERC_SEDUTE`
|
||||||
|
- `P8_STAMPA_MENU`
|
||||||
|
- `P8_STEP`
|
||||||
|
- `P8_TAVOLI_NR`
|
||||||
|
- `P8_TORTA`
|
||||||
|
- `P8_TORTA_DISPLAY`
|
||||||
|
- `P8_TOT_ADULTI`
|
||||||
|
- `P8_TOT_BABY`
|
||||||
|
- `P8_TOT_KINDER`
|
||||||
|
- `P8_TOT_OSPITI`
|
||||||
6
docs/apex/pages/PAGE_010.md
Normal file
6
docs/apex/pages/PAGE_010.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 10 - Anteprima Immagine
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P10_IMMAGINE`
|
||||||
|
- `P10_ROWID`
|
||||||
5
docs/apex/pages/PAGE_011.md
Normal file
5
docs/apex/pages/PAGE_011.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Page 11 - Stampa Riepilogo
|
||||||
|
|
||||||
|
## Items (1)
|
||||||
|
|
||||||
|
- `P11_EVENT_ID`
|
||||||
9
docs/apex/pages/PAGE_014.md
Normal file
9
docs/apex/pages/PAGE_014.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Page 14 - Tipi Evento
|
||||||
|
|
||||||
|
## Items (5)
|
||||||
|
|
||||||
|
- `P14_COD_TIPO`
|
||||||
|
- `P14_DESCRIZIONE`
|
||||||
|
- `P14_LIVELLO`
|
||||||
|
- `P14_ROWID`
|
||||||
|
- `P14_TIPO_PASTO`
|
||||||
5
docs/apex/pages/PAGE_016.md
Normal file
5
docs/apex/pages/PAGE_016.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Page 16 - Griglia
|
||||||
|
|
||||||
|
## Items (1)
|
||||||
|
|
||||||
|
- `P16_SETTIMANA`
|
||||||
14
docs/apex/pages/PAGE_018.md
Normal file
14
docs/apex/pages/PAGE_018.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Page 18 - Clienti
|
||||||
|
|
||||||
|
## Items (10)
|
||||||
|
|
||||||
|
- `P18_CLIENTE`
|
||||||
|
- `P18_COGNOME_RIF`
|
||||||
|
- `P18_INDIRIZZO`
|
||||||
|
- `P18_MAIL`
|
||||||
|
- `P18_NOME_RIF`
|
||||||
|
- `P18_PIVA`
|
||||||
|
- `P18_RAGSOC`
|
||||||
|
- `P18_ROWID`
|
||||||
|
- `P18_TEL1`
|
||||||
|
- `P18_TEL2`
|
||||||
20
docs/apex/pages/PAGE_019.md
Normal file
20
docs/apex/pages/PAGE_019.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Page 19 - Articoli Popup
|
||||||
|
|
||||||
|
## Items (16)
|
||||||
|
|
||||||
|
- `P19_COD_ARTICOLO`
|
||||||
|
- `P19_COD_CATEG`
|
||||||
|
- `P19_COD_RELATIVO`
|
||||||
|
- `P19_COEFF`
|
||||||
|
- `P19_COEFF_A`
|
||||||
|
- `P19_COEFF_B`
|
||||||
|
- `P19_COEFF_S`
|
||||||
|
- `P19_DESCRIZIONE`
|
||||||
|
- `P19_FLG_CUCINA`
|
||||||
|
- `P19_IMMAGINE`
|
||||||
|
- `P19_IMMAGINE_DISPLAY`
|
||||||
|
- `P19_QTA_STD_A`
|
||||||
|
- `P19_QTA_STD_B`
|
||||||
|
- `P19_QTA_STD_S`
|
||||||
|
- `P19_ROWID`
|
||||||
|
- `P19_TIPO_QTA`
|
||||||
11
docs/apex/pages/PAGE_020.md
Normal file
11
docs/apex/pages/PAGE_020.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Page 20 - Location
|
||||||
|
|
||||||
|
## Items (7)
|
||||||
|
|
||||||
|
- `P20_ID`
|
||||||
|
- `P20_INDIRIZZO`
|
||||||
|
- `P20_LOCATION`
|
||||||
|
- `P20_NOTE`
|
||||||
|
- `P20_NOTE2`
|
||||||
|
- `P20_REFERENTE`
|
||||||
|
- `P20_ROWID`
|
||||||
5
docs/apex/pages/PAGE_021.md
Normal file
5
docs/apex/pages/PAGE_021.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Page 21 - Costi Articolo
|
||||||
|
|
||||||
|
## Items (1)
|
||||||
|
|
||||||
|
- `P21_COD_ARTICOLO`
|
||||||
112
docs/apex/pages/PAGE_022.md
Normal file
112
docs/apex/pages/PAGE_022.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# Page 22 - Evento
|
||||||
|
|
||||||
|
## Items (108)
|
||||||
|
|
||||||
|
- `P22_ALLERGIE`
|
||||||
|
- `P22_ALLEST_BUFF`
|
||||||
|
- `P22_ALTRO`
|
||||||
|
- `P22_ALTRO_A`
|
||||||
|
- `P22_ALTRO_B`
|
||||||
|
- `P22_ARTICOLO_ADD`
|
||||||
|
- `P22_ARTICOLO_REMOVE`
|
||||||
|
- `P22_BICCHIERI`
|
||||||
|
- `P22_BUFFET_DOLCI_A`
|
||||||
|
- `P22_BUFFET_DOLCI_B`
|
||||||
|
- `P22_BUFFET_FINALE`
|
||||||
|
- `P22_BUFFET_FINALE_DISPLAY`
|
||||||
|
- `P22_BUFFET_INIZIALE`
|
||||||
|
- `P22_BUFFET_INIZIALE_DISPLAY`
|
||||||
|
- `P22_CARICOAPOLL`
|
||||||
|
- `P22_CARICOSPOSI`
|
||||||
|
- `P22_CATEG`
|
||||||
|
- `P22_CATEG_FILTER`
|
||||||
|
- `P22_CLIENTE`
|
||||||
|
- `P22_CLIENTE_EMAIL`
|
||||||
|
- `P22_CLIENTE_TEL`
|
||||||
|
- `P22_COD_TIPO`
|
||||||
|
- `P22_COD_TIPO_FILTER`
|
||||||
|
- `P22_COLOR`
|
||||||
|
- `P22_CONSUNTIVO_MORE_DETAILS`
|
||||||
|
- `P22_CONTRATTO_FIRMATO`
|
||||||
|
- `P22_DATA`
|
||||||
|
- `P22_DATA_DOC`
|
||||||
|
- `P22_DATA_SCAD_PREVENTIVO`
|
||||||
|
- `P22_DATORASCARICO`
|
||||||
|
- `P22_DATORASCARICO_NOTE`
|
||||||
|
- `P22_DELETED`
|
||||||
|
- `P22_DELETED_BY`
|
||||||
|
- `P22_DELETED_DATE`
|
||||||
|
- `P22_DESCRIZIONE`
|
||||||
|
- `P22_DISABLED`
|
||||||
|
- `P22_DISTANZA_LOCATION`
|
||||||
|
- `P22_EVENT_ID`
|
||||||
|
- `P22_EVENT_ID_DISPLAY`
|
||||||
|
- `P22_EXTRA`
|
||||||
|
- `P22_EXTRA_COSTI`
|
||||||
|
- `P22_FLG_SUPERATO`
|
||||||
|
- `P22_FLG_TEMPLATE`
|
||||||
|
- `P22_GGSETT`
|
||||||
|
- `P22_GRAN_BUFFET_A`
|
||||||
|
- `P22_GRAN_BUFFET_B`
|
||||||
|
- `P22_ID_EVT_FIGLIO`
|
||||||
|
- `P22_ID_EVT_PADRE`
|
||||||
|
- `P22_ID_IMAGE_SHOW`
|
||||||
|
- `P22_INDIRIZZO`
|
||||||
|
- `P22_IS_TEMPLATE`
|
||||||
|
- `P22_LISTA_PRINT`
|
||||||
|
- `P22_LOCATION`
|
||||||
|
- `P22_LOCATION_DESCRI`
|
||||||
|
- `P22_MAIL_ENABLED`
|
||||||
|
- `P22_MAXSTEP`
|
||||||
|
- `P22_NEW`
|
||||||
|
- `P22_NEW_EVENT_ID`
|
||||||
|
- `P22_NOTE`
|
||||||
|
- `P22_NOTE_INVIO`
|
||||||
|
- `P22_NUMALTRI`
|
||||||
|
- `P22_NUMDEGUSTAZIONI`
|
||||||
|
- `P22_NUM_LISTA`
|
||||||
|
- `P22_ORA_CERIMONIA`
|
||||||
|
- `P22_ORA_EVENTO`
|
||||||
|
- `P22_ORA_FINE_CERIMONIA`
|
||||||
|
- `P22_ORA_FINE_EVENTO`
|
||||||
|
- `P22_ORA_FI_CER`
|
||||||
|
- `P22_ORA_FI_EVENTO`
|
||||||
|
- `P22_ORA_INI_CER`
|
||||||
|
- `P22_ORA_INI_EVENTO`
|
||||||
|
- `P22_PERC_SEDUTE`
|
||||||
|
- `P22_PERMES_CONSUNTIVI_REPORT`
|
||||||
|
- `P22_PIATTI`
|
||||||
|
- `P22_PIATTINO_PANE`
|
||||||
|
- `P22_POSATE`
|
||||||
|
- `P22_PRE_BOUV_A`
|
||||||
|
- `P22_PRE_BOUV_B`
|
||||||
|
- `P22_PRIMI`
|
||||||
|
- `P22_PRIMI_DISPLAY`
|
||||||
|
- `P22_REFERENTE_TEL`
|
||||||
|
- `P22_RISORSA_ADD`
|
||||||
|
- `P22_RISORSA_REMOVE`
|
||||||
|
- `P22_RUNNER`
|
||||||
|
- `P22_SCADUTO`
|
||||||
|
- `P22_SECONDI`
|
||||||
|
- `P22_SEDIA`
|
||||||
|
- `P22_SERVIZIO_TAVOLO_A`
|
||||||
|
- `P22_SERVIZIO_TAVOLO_B`
|
||||||
|
- `P22_SOTTOPIATTI`
|
||||||
|
- `P22_STATO`
|
||||||
|
- `P22_STATUS`
|
||||||
|
- `P22_STEP`
|
||||||
|
- `P22_STILE_COLORI`
|
||||||
|
- `P22_TIPOL_TAV_OSPITI`
|
||||||
|
- `P22_TIPOL_TAV_SPOSI`
|
||||||
|
- `P22_TIPORIS_FILTER`
|
||||||
|
- `P22_TORTA`
|
||||||
|
- `P22_TORTA_A`
|
||||||
|
- `P22_TORTA_B`
|
||||||
|
- `P22_TOT_OSPITI`
|
||||||
|
- `P22_TOVAGLIA`
|
||||||
|
- `P22_TOVAGLIOLO`
|
||||||
|
- `P22_VERSION_DISPLAY`
|
||||||
|
- `P22_VERS_NUMBER`
|
||||||
|
- `P22_VERS_TOKEN`
|
||||||
|
- `P22_VINI`
|
||||||
|
- `P22_VINI_DISPLAY`
|
||||||
6
docs/apex/pages/PAGE_024.md
Normal file
6
docs/apex/pages/PAGE_024.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 24 - Stampa Riepilogo Extra
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P24_DATA_FI`
|
||||||
|
- `P24_DATA_IN`
|
||||||
6
docs/apex/pages/PAGE_025.md
Normal file
6
docs/apex/pages/PAGE_025.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 25 - Cucina
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P25_DATA_FI`
|
||||||
|
- `P25_DATA_IN`
|
||||||
6
docs/apex/pages/PAGE_026.md
Normal file
6
docs/apex/pages/PAGE_026.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 26 - Stampa Riepilogo Cucina
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P26_DATA_FI`
|
||||||
|
- `P26_DATA_IN`
|
||||||
6
docs/apex/pages/PAGE_027.md
Normal file
6
docs/apex/pages/PAGE_027.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 27 - Degustazioni_Lista
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P27_DATA_FI`
|
||||||
|
- `P27_DATA_IN`
|
||||||
6
docs/apex/pages/PAGE_028.md
Normal file
6
docs/apex/pages/PAGE_028.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 28 - Torte e Costi Extra
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P28_DATA_FI`
|
||||||
|
- `P28_DATA_IN`
|
||||||
6
docs/apex/pages/PAGE_029.md
Normal file
6
docs/apex/pages/PAGE_029.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 29 - Stampa Riepilogo Allestimenti
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P29_DATA_FI`
|
||||||
|
- `P29_DATA_IN`
|
||||||
6
docs/apex/pages/PAGE_030.md
Normal file
6
docs/apex/pages/PAGE_030.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 30 - Riepilogo Allestimenti
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P30_DATA_FI`
|
||||||
|
- `P30_DATA_IN`
|
||||||
18
docs/apex/pages/PAGE_032.md
Normal file
18
docs/apex/pages/PAGE_032.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Page 32 - Degustazioni
|
||||||
|
|
||||||
|
## Items (14)
|
||||||
|
|
||||||
|
- `P32_DATA`
|
||||||
|
- `P32_EMAIL`
|
||||||
|
- `P32_ID`
|
||||||
|
- `P32_ID_EVENTO`
|
||||||
|
- `P32_LOCATION`
|
||||||
|
- `P32_MENU`
|
||||||
|
- `P32_NOME`
|
||||||
|
- `P32_NOTE`
|
||||||
|
- `P32_N_DEGUSTAZIONE`
|
||||||
|
- `P32_N_PAGANTI`
|
||||||
|
- `P32_N_PERSONE`
|
||||||
|
- `P32_ORA`
|
||||||
|
- `P32_ROWID`
|
||||||
|
- `P32_TELEFONO`
|
||||||
6
docs/apex/pages/PAGE_033.md
Normal file
6
docs/apex/pages/PAGE_033.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 33 - Stampa Scheda Evento
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P33_EVENT_ID`
|
||||||
|
- `P33_LISTA`
|
||||||
6
docs/apex/pages/PAGE_035.md
Normal file
6
docs/apex/pages/PAGE_035.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 35 - Lista Schede Evento
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P35_DATEFROM`
|
||||||
|
- `P35_DATETO`
|
||||||
6
docs/apex/pages/PAGE_036.md
Normal file
6
docs/apex/pages/PAGE_036.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 36 - Stampa Riepilogo Degustazioni
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P36_DATA_FI`
|
||||||
|
- `P36_DATA_IN`
|
||||||
7
docs/apex/pages/PAGE_038.md
Normal file
7
docs/apex/pages/PAGE_038.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Page 38 - Riepilogo Risorse
|
||||||
|
|
||||||
|
## Items (3)
|
||||||
|
|
||||||
|
- `P38_COD_AZIENDA`
|
||||||
|
- `P38_DATA_FI`
|
||||||
|
- `P38_DATA_IN`
|
||||||
8
docs/apex/pages/PAGE_039.md
Normal file
8
docs/apex/pages/PAGE_039.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Page 39 - Impegni Articoli
|
||||||
|
|
||||||
|
## Items (4)
|
||||||
|
|
||||||
|
- `P39_COD_ARTICOLO`
|
||||||
|
- `P39_DATA_FI`
|
||||||
|
- `P39_DATA_IN`
|
||||||
|
- `P39_SHOW_HISTORY`
|
||||||
7
docs/apex/pages/PAGE_040.md
Normal file
7
docs/apex/pages/PAGE_040.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Page 40 - Stampa Riepilogo Risorse
|
||||||
|
|
||||||
|
## Items (3)
|
||||||
|
|
||||||
|
- `P40_COD_AZIENDA`
|
||||||
|
- `P40_DATA_FI`
|
||||||
|
- `P40_DATA_IN`
|
||||||
5
docs/apex/pages/PAGE_041.md
Normal file
5
docs/apex/pages/PAGE_041.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Page 41 - Backup
|
||||||
|
|
||||||
|
## Items (1)
|
||||||
|
|
||||||
|
- `P41_BCKPASSWORD`
|
||||||
12
docs/apex/pages/PAGE_042.md
Normal file
12
docs/apex/pages/PAGE_042.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Page 42 - Nuovo Allegato Evento
|
||||||
|
|
||||||
|
## Items (8)
|
||||||
|
|
||||||
|
- `P42_CHARSET`
|
||||||
|
- `P42_EVENT_ID`
|
||||||
|
- `P42_FILENAME`
|
||||||
|
- `P42_FILESIZELIMITKB`
|
||||||
|
- `P42_ID`
|
||||||
|
- `P42_LAST_UPDATE`
|
||||||
|
- `P42_MIME_TYPE`
|
||||||
|
- `P42_RAW_DATA`
|
||||||
5
docs/apex/pages/PAGE_043.md
Normal file
5
docs/apex/pages/PAGE_043.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Page 43 - Registro Acconti Evento
|
||||||
|
|
||||||
|
## Items (1)
|
||||||
|
|
||||||
|
- `P43_ID_EVENTO`
|
||||||
5
docs/apex/pages/PAGE_044.md
Normal file
5
docs/apex/pages/PAGE_044.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Page 44 - Registro Altri Costi
|
||||||
|
|
||||||
|
## Items (1)
|
||||||
|
|
||||||
|
- `P44_ID_EVENTO`
|
||||||
8
docs/apex/pages/PAGE_045.md
Normal file
8
docs/apex/pages/PAGE_045.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Page 45 - GestioneDati
|
||||||
|
|
||||||
|
## Items (4)
|
||||||
|
|
||||||
|
- `P45_CONSUNTIVI_A`
|
||||||
|
- `P45_CONSUNTIVI_DA`
|
||||||
|
- `P45_EVENTI_A`
|
||||||
|
- `P45_EVENTI_DA`
|
||||||
6
docs/apex/pages/PAGE_046.md
Normal file
6
docs/apex/pages/PAGE_046.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 46 - Imposta Blocco Calendario
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P46_GIORNO`
|
||||||
|
- `P46_MAX_EVENTI`
|
||||||
6
docs/apex/pages/PAGE_047.md
Normal file
6
docs/apex/pages/PAGE_047.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 47 - Permessi
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P47_CONSUNTIVI_USERS`
|
||||||
|
- `P47_GESTORI_USERS`
|
||||||
10
docs/apex/pages/PAGE_052.md
Normal file
10
docs/apex/pages/PAGE_052.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Page 52 - send_mail_modal
|
||||||
|
|
||||||
|
## Items (6)
|
||||||
|
|
||||||
|
- `P52_DATA_FROM`
|
||||||
|
- `P52_DATA_FROM_DISPLAY`
|
||||||
|
- `P52_DATA_TO`
|
||||||
|
- `P52_DATA_TO_DISPLAY`
|
||||||
|
- `P52_MAIL_BODY`
|
||||||
|
- `P52_MAIL_SUBJECT`
|
||||||
11
docs/apex/pages/PAGE_053.md
Normal file
11
docs/apex/pages/PAGE_053.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Page 53 - COPIA_LISTA_PAGE
|
||||||
|
|
||||||
|
## Items (7)
|
||||||
|
|
||||||
|
- `P53_COPIA_ACCONTI`
|
||||||
|
- `P53_COPIA_ALTRICOSTI`
|
||||||
|
- `P53_COPIA_DEGUSTAZIONI`
|
||||||
|
- `P53_COPIA_PRELIEVI`
|
||||||
|
- `P53_COPIA_RISORSE`
|
||||||
|
- `P53_EVENTO_FROM`
|
||||||
|
- `P53_EVENTO_TO`
|
||||||
6
docs/apex/pages/PAGE_101.md
Normal file
6
docs/apex/pages/PAGE_101.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Page 101 - Login Page
|
||||||
|
|
||||||
|
## Items (2)
|
||||||
|
|
||||||
|
- `P101_PASSWORD`
|
||||||
|
- `P101_USERNAME`
|
||||||
7
docs/apex/pages/PAGE_999.md
Normal file
7
docs/apex/pages/PAGE_999.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Page 999 - Stampa Preventivo
|
||||||
|
|
||||||
|
## Items (3)
|
||||||
|
|
||||||
|
- `P999_EVENT_ID`
|
||||||
|
- `P999_MORE_DETAILS`
|
||||||
|
- `P999_SHOW_ECONOMICS`
|
||||||
558
docs/apex/processes/README.md
Normal file
558
docs/apex/processes/README.md
Normal file
@@ -0,0 +1,558 @@
|
|||||||
|
# APEX Processes Documentation
|
||||||
|
|
||||||
|
This document contains all 98 processes defined in the APEX application, organized by page.
|
||||||
|
|
||||||
|
## Process Overview
|
||||||
|
|
||||||
|
| Process Type | Count |
|
||||||
|
|--------------|-------|
|
||||||
|
| NATIVE_FORM_INIT | Multiple |
|
||||||
|
| NATIVE_FORM_DML | Multiple |
|
||||||
|
| NATIVE_PLSQL | Multiple |
|
||||||
|
| NATIVE_IG_DML | Multiple |
|
||||||
|
| NATIVE_SESSION_STATE | Multiple |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Shared (Application-Level) Processes
|
||||||
|
|
||||||
|
### SET_USER_READONLY
|
||||||
|
|
||||||
|
**Process Point:** Before Header (runs on every page)
|
||||||
|
**Type:** NATIVE_PLSQL
|
||||||
|
|
||||||
|
Sets the `APP_READ_ONLY` application item based on user permissions.
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
if F_USER_IN_ROLE(:APP_USER, 'READONLY') then
|
||||||
|
:APP_READ_ONLY := 1;
|
||||||
|
else
|
||||||
|
:APP_READ_ONLY := 0;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Page 3 - Articoli (Article Form)
|
||||||
|
|
||||||
|
### Fetch Row from ARTICOLI
|
||||||
|
**Process Point:** After Header
|
||||||
|
**Type:** NATIVE_FORM_INIT
|
||||||
|
|
||||||
|
Initializes form with article data.
|
||||||
|
|
||||||
|
### Process Row of ARTICOLI
|
||||||
|
**Process Point:** After Submit
|
||||||
|
**Type:** NATIVE_FORM_DML
|
||||||
|
|
||||||
|
Saves/updates article record.
|
||||||
|
|
||||||
|
### Delete Image
|
||||||
|
**Process Point:** After Submit
|
||||||
|
**Type:** NATIVE_PLSQL
|
||||||
|
**Button:** Delete Image
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
update articoli
|
||||||
|
set
|
||||||
|
raw_data = null,
|
||||||
|
last_update = null,
|
||||||
|
charset = null,
|
||||||
|
mimetype = null,
|
||||||
|
filename = null
|
||||||
|
where rowid = :P3_ROWID;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Page 22 - Nuovo Evento (Main Event Form)
|
||||||
|
|
||||||
|
Page 22 is the most complex page with 32 processes.
|
||||||
|
|
||||||
|
### After Header Processes
|
||||||
|
|
||||||
|
#### Get Event Details
|
||||||
|
**Sequence:** 10
|
||||||
|
**Type:** NATIVE_FORM_INIT
|
||||||
|
|
||||||
|
Fetches event record into form items.
|
||||||
|
|
||||||
|
#### Set Ospiti on load
|
||||||
|
**Sequence:** 20
|
||||||
|
**Type:** NATIVE_PLSQL
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
EVENTI_AGGIORNA_TOT_OSPITI(:P22_EVENT_ID);
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Default Values
|
||||||
|
**Sequence:** 40
|
||||||
|
**Type:** NATIVE_PLSQL
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
select trim(l.location)
|
||||||
|
into :P22_LOCATION_DESCRI
|
||||||
|
from eventi e
|
||||||
|
join location l on l.id = e.id_location
|
||||||
|
where e.id = :P22_EVENT_ID;
|
||||||
|
exception when no_data_found then
|
||||||
|
null;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Normalizza dati
|
||||||
|
**Sequence:** 50
|
||||||
|
**Type:** NATIVE_PLSQL
|
||||||
|
|
||||||
|
Formats time values for display:
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
:P22_ORA_INI_CER := to_char(to_date(:P22_ORA_CERIMONIA, 'DD-MM-YYYY HH24:MI'), 'hh24:mi');
|
||||||
|
:P22_ORA_INI_EVENTO := to_char(to_date(:P22_ORA_EVENTO, 'DD-MM-YYYY HH24:MI'), 'hh24:mi');
|
||||||
|
:P22_ORA_FI_CER := to_char(to_date(:ORA_FINE_CERIMONIA, 'DD-MM-YYYY HH24:MI'), 'hh24:mi');
|
||||||
|
:P22_ORA_FI_EVENTO := to_char(to_date(:ORA_FINE_EVENTO, 'DD-MM-YYYY HH24:MI'), 'hh24:mi');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### New Template Default Data
|
||||||
|
**Sequence:** 60
|
||||||
|
**Condition:** P22_IS_TEMPLATE is not null
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
:P22_DATA := sysdate;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### After Submit Processes
|
||||||
|
|
||||||
|
#### Set Date Default if Template
|
||||||
|
**Sequence:** 10
|
||||||
|
**Condition:** P22_IS_TEMPLATE is not null
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
:P22_DATA := sysdate;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Delete Template
|
||||||
|
**Sequence:** 20
|
||||||
|
**Button:** Delete Template
|
||||||
|
**Condition:** P22_IS_TEMPLATE is not null
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
delete from eventi where id = :P22_EVENT_ID;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Genera Evento da Template
|
||||||
|
**Sequence:** 30
|
||||||
|
**Button:** Generate from Template
|
||||||
|
**Condition:** P22_IS_TEMPLATE is not null
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
EVENTI_COPIA
|
||||||
|
(
|
||||||
|
ID_EVENTO_OLD => :P22_EVENT_ID,
|
||||||
|
NUOVA_VERSIONE => 0,
|
||||||
|
ID_EVENTO_NEW => :P22_EVENT_ID
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Formatta Ore Inizio
|
||||||
|
**Sequence:** 40
|
||||||
|
|
||||||
|
Combines date and time for storage:
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
:P22_ORA_EVENTO := :P22_DATA || ' ' || :P22_ORA_INI_EVENTO;
|
||||||
|
:P22_ORA_CERIMONIA := :P22_DATA || ' ' || :P22_ORA_INI_CER;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Prepara Acconti Automatici
|
||||||
|
**Sequence:** 50
|
||||||
|
**Condition:** REQUEST in ('PREPARA_ACCONTI', 'PRINT_PREVENTIVO')
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
EVENTI_RICALCOLA_ACCONTI(p_event_id => :P22_EVENT_ID);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Comment:** Default 3 deposits: 30%, 50%, 20%
|
||||||
|
|
||||||
|
#### Go Forward
|
||||||
|
**Sequence:** 60
|
||||||
|
**Button:** NEXT
|
||||||
|
|
||||||
|
Navigates to next wizard step:
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
declare
|
||||||
|
v_step number;
|
||||||
|
begin
|
||||||
|
begin
|
||||||
|
select min(cod_step)
|
||||||
|
into v_step
|
||||||
|
from tb_tipi_mat
|
||||||
|
where cod_step > TO_NUMBER(:P22_STEP);
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
select cod_tipo
|
||||||
|
into :P22_COD_TIPO_FILTER
|
||||||
|
from tb_tipi_mat
|
||||||
|
where cod_step = v_step;
|
||||||
|
exception when no_data_found
|
||||||
|
then raise_application_error(-20001, 'Errore sconosciuto');
|
||||||
|
end;
|
||||||
|
|
||||||
|
:P22_STEP := v_step;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Go Backward
|
||||||
|
**Sequence:** 70
|
||||||
|
**Button:** PREVIOUS
|
||||||
|
|
||||||
|
Navigates to previous wizard step.
|
||||||
|
|
||||||
|
#### Tipo Ospiti - Save Interactive Grid Data
|
||||||
|
**Sequence:** 80
|
||||||
|
**Region:** Guest Types Grid
|
||||||
|
**Type:** NATIVE_IG_DML
|
||||||
|
**Condition:** APP_READ_ONLY = 0
|
||||||
|
|
||||||
|
Saves guest type records.
|
||||||
|
|
||||||
|
#### Tipo Ospiti - Aggiorna Lista Prelievo
|
||||||
|
**Sequence:** 90
|
||||||
|
**Type:** NATIVE_PLSQL
|
||||||
|
**Condition:** APP_READ_ONLY = 0
|
||||||
|
|
||||||
|
Recalculates pick list quantities after guest changes:
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
EVENTI_AGGIORNA_QTA_LISTA(
|
||||||
|
P_ID_EVENTO => :P22_EVENT_ID
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Degustazioni - Save Interactive Grid Data
|
||||||
|
**Sequence:** 100
|
||||||
|
**Region:** Tastings Grid
|
||||||
|
**Type:** NATIVE_IG_DML
|
||||||
|
|
||||||
|
#### Delete Eventi Childs
|
||||||
|
**Sequence:** 110
|
||||||
|
**Button:** DELETE
|
||||||
|
**Condition:** NEVER (disabled)
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
delete from eventi_det_ospiti
|
||||||
|
where id_evento = :P22_EVENT_ID;
|
||||||
|
|
||||||
|
delete from eventi_det_prel
|
||||||
|
where id_evento = :P22_EVENT_ID;
|
||||||
|
|
||||||
|
delete from eventi_det_ris
|
||||||
|
where id_evento = :P22_EVENT_ID;
|
||||||
|
|
||||||
|
delete from eventi_det_degust
|
||||||
|
where id_evento = :P22_EVENT_ID;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Set Obsoleto
|
||||||
|
**Sequence:** 120
|
||||||
|
**Button:** Set Obsolete
|
||||||
|
**Condition:** APP_READ_ONLY = 0
|
||||||
|
|
||||||
|
Marks event as expired/cancelled:
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
UPDATE EVENTI
|
||||||
|
SET FLG_SUPERATO = 1, STATO = 900, MAIL_ENABLED = 0
|
||||||
|
WHERE ID = :P22_EVENT_ID;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Salva Evento
|
||||||
|
**Sequence:** 130
|
||||||
|
**Condition:** Complex (handles CREATE, SAVE, DELETE)
|
||||||
|
|
||||||
|
Main event save process. Full implementation handles:
|
||||||
|
- All event fields mapping
|
||||||
|
- Email validation
|
||||||
|
- Status-based logic
|
||||||
|
- Versioning support
|
||||||
|
- Soft delete
|
||||||
|
|
||||||
|
Key excerpts:
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
declare
|
||||||
|
r_eventi eventi%rowtype;
|
||||||
|
begin
|
||||||
|
if :REQUEST = 'PREVIOUS' or :REQUEST = 'NEXT'
|
||||||
|
then
|
||||||
|
return;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if(:P22_DATA is null)
|
||||||
|
then
|
||||||
|
raise_application_error(-20001, 'Inserire la data evento');
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Set all row fields
|
||||||
|
r_eventi."ID" := :P22_EVENT_ID;
|
||||||
|
r_eventi.DESCRIZIONE := :P22_DESCRIZIONE;
|
||||||
|
r_eventi.COD_TIPO := :P22_COD_TIPO;
|
||||||
|
-- ... (all other fields)
|
||||||
|
|
||||||
|
-- Email validation
|
||||||
|
IF REGEXP_LIKE(:P22_CLIENTE_EMAIL, '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$')
|
||||||
|
OR :P22_CLIENTE_EMAIL IS NULL THEN
|
||||||
|
r_eventi.CLIENTE_EMAIL := :P22_CLIENTE_EMAIL;
|
||||||
|
ELSE
|
||||||
|
RAISE_APPLICATION_ERROR(-20005, 'Formato email cliente non valido');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Versioning
|
||||||
|
r_eventi.VERS_NUMBER := nvl(:P22_VERS_NUMBER, 0);
|
||||||
|
r_eventi.VERS_TOKEN := :P22_VERS_TOKEN;
|
||||||
|
|
||||||
|
case :REQUEST
|
||||||
|
when 'SAVE' then
|
||||||
|
update eventi set row = r_eventi where id = :P22_EVENT_ID;
|
||||||
|
when 'CREATE' then
|
||||||
|
insert into eventi values r_eventi returning id into :P22_EVENT_ID;
|
||||||
|
when 'DELETE' then
|
||||||
|
if r_eventi.ID_EVT_FIGLIO is not null or r_eventi.ID_EVT_PADRE is not null
|
||||||
|
then
|
||||||
|
raise_application_error(-20001, 'Impossibile eliminare un evento...');
|
||||||
|
end if;
|
||||||
|
update eventi
|
||||||
|
set deleted = 1,
|
||||||
|
deleted_by = :APP_USER,
|
||||||
|
deleted_date = sysdate
|
||||||
|
where id = r_eventi."ID";
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
end case;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Nuova Versione
|
||||||
|
**Sequence:** 140
|
||||||
|
**Button:** New Version
|
||||||
|
|
||||||
|
Creates a new version of the event:
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
EVENTI_COPIA
|
||||||
|
(
|
||||||
|
ID_EVENTO_OLD => :P22_EVENT_ID,
|
||||||
|
NUOVA_VERSIONE => 1,
|
||||||
|
ID_EVENTO_NEW => :P22_NEW_EVENT_ID
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Lista Prelievo - Save Interactive Grid Data
|
||||||
|
**Sequence:** 150
|
||||||
|
**Type:** NATIVE_IG_DML
|
||||||
|
**Table:** EVENTI_DET_PREL
|
||||||
|
|
||||||
|
Saves pick list records.
|
||||||
|
|
||||||
|
#### Continue Event
|
||||||
|
**Sequence:** 160
|
||||||
|
**Button:** Continue
|
||||||
|
|
||||||
|
Advances event to "Confermata" status (300):
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
declare
|
||||||
|
v_count number;
|
||||||
|
v_count_evt number;
|
||||||
|
begin
|
||||||
|
-- Check if confirmed event exists for same location/date
|
||||||
|
select count(*) into v_count
|
||||||
|
from eventi
|
||||||
|
where data = (select data from eventi where id = :P22_EVENT_ID)
|
||||||
|
and stato = 300
|
||||||
|
and id_location = (select id_location from eventi where id = :P22_EVENT_ID);
|
||||||
|
|
||||||
|
if v_count > 0 then
|
||||||
|
raise_application_error(-20001, 'Esiste un evento Confermato per la location - Impossibile proseguire');
|
||||||
|
return;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Update status
|
||||||
|
update eventi
|
||||||
|
set stato = 300
|
||||||
|
where id = :P22_EVENT_ID;
|
||||||
|
|
||||||
|
-- Check total confirmed events for date
|
||||||
|
select count(*) into v_count_evt
|
||||||
|
from eventi
|
||||||
|
where data = (select data from eventi where id = :P22_EVENT_ID)
|
||||||
|
and stato = 300;
|
||||||
|
|
||||||
|
if v_count_evt > 6 then
|
||||||
|
RAISE_APPLICATION_ERROR(-20000, 'Ci sono già 6 eventi Confermati per la data');
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Almost Continue Event
|
||||||
|
**Sequence:** 170
|
||||||
|
**Button:** Almost Continue
|
||||||
|
|
||||||
|
Sets status to "Quasi Confermato" (350):
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
update eventi
|
||||||
|
set stato = 350
|
||||||
|
where id = :P22_EVENT_ID;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Confirm Event
|
||||||
|
**Sequence:** 180
|
||||||
|
**Button:** Confirm
|
||||||
|
**Condition:** APP_READ_ONLY = 0
|
||||||
|
|
||||||
|
Final confirmation (status 400) and cancels competing events:
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
update eventi
|
||||||
|
set stato = 400
|
||||||
|
where id = :P22_EVENT_ID;
|
||||||
|
|
||||||
|
-- Cancel events with same date and location
|
||||||
|
p_cancel_same_location_events(
|
||||||
|
p_good_event_id => :P22_EVENT_ID
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Unconfirm Event
|
||||||
|
**Sequence:** 190
|
||||||
|
**Button:** Unconfirm
|
||||||
|
|
||||||
|
Returns event to initial status (100):
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
update eventi
|
||||||
|
set stato = 100
|
||||||
|
where id = :P22_EVENT_ID;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Reopen Event
|
||||||
|
**Sequence:** 200
|
||||||
|
**Button:** Reopen
|
||||||
|
|
||||||
|
Clears the expired flag:
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
update eventi
|
||||||
|
set flg_superato = 0
|
||||||
|
where id = :P22_EVENT_ID;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Return to Preparazione
|
||||||
|
**Sequence:** 210
|
||||||
|
**Button:** Return to Preparation
|
||||||
|
|
||||||
|
Sets status back to preparation (200):
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
begin
|
||||||
|
update eventi
|
||||||
|
set stato = 200
|
||||||
|
where id = :P22_EVENT_ID;
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Risorse - Save Interactive Grid Data
|
||||||
|
**Sequence:** 220
|
||||||
|
**Type:** NATIVE_IG_DML
|
||||||
|
|
||||||
|
Saves resource assignments.
|
||||||
|
|
||||||
|
#### Aggiorna QTA Lista
|
||||||
|
**Sequence:** 230
|
||||||
|
**Condition:** APP_READ_ONLY = 0 AND REQUEST = 'AGGIORNA_QTA'
|
||||||
|
|
||||||
|
Manual quantity recalculation:
|
||||||
|
|
||||||
|
```plsql
|
||||||
|
EVENTI_AGGIORNA_QTA_LISTA(
|
||||||
|
P_ID_EVENTO => :P22_EVENT_ID
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Restore Deleted Event
|
||||||
|
**Sequence:** 240
|
||||||
|
|
||||||
|
Restores soft-deleted event.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Event Status Workflow Summary
|
||||||
|
|
||||||
|
| Status Code | Status Name | Italian | Next Action |
|
||||||
|
|-------------|-------------|---------|-------------|
|
||||||
|
| 100 | Preventivo | Quote | Continue Event → 300 |
|
||||||
|
| 200 | Scheda | Preparation | - |
|
||||||
|
| 300 | Confermata | Confirmed (Pending) | Almost Continue → 350 |
|
||||||
|
| 350 | Quasi | Almost Confirmed | Confirm → 400 |
|
||||||
|
| 400 | Confermato | Confirmed | - |
|
||||||
|
| 900 | Superato | Expired/Cancelled | Reopen → clears flag |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Process Patterns
|
||||||
|
|
||||||
|
### Read-Only Check
|
||||||
|
All write processes include this condition:
|
||||||
|
```plsql
|
||||||
|
:APP_READ_ONLY = 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
Standard error pattern:
|
||||||
|
```plsql
|
||||||
|
exception when no_data_found then
|
||||||
|
raise_application_error(-20001, 'Error message in Italian');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interactive Grid Save
|
||||||
|
Standard IG DML process:
|
||||||
|
- Type: NATIVE_IG_DML
|
||||||
|
- Attributes: REGION_SOURCE, Allow Insert (Y), Allow Update (Y), Allow Delete (Y)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration Notes
|
||||||
|
|
||||||
|
When migrating these processes to .NET:
|
||||||
|
|
||||||
|
1. **Form Initialization** - Use API endpoints to fetch entity data
|
||||||
|
2. **Form DML** - Implement CRUD endpoints with proper validation
|
||||||
|
3. **Custom PL/SQL** - Convert to C# methods or stored procedures
|
||||||
|
4. **IG DML** - Implement batch update endpoints for grid data
|
||||||
|
5. **Session State** - Use application state management (Redux, Context)
|
||||||
|
6. **Validation** - Implement in both frontend and backend
|
||||||
|
7. **Workflow** - Consider state machine pattern for event status
|
||||||
22
docs/functions/CLOB2BLOB.md
Normal file
22
docs/functions/CLOB2BLOB.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# CLOB2BLOB
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "CLOB2BLOB" (AClob CLOB) return BLOB is
|
||||||
|
Result BLOB;
|
||||||
|
o1 integer;
|
||||||
|
o2 integer;
|
||||||
|
c integer;
|
||||||
|
w integer;
|
||||||
|
begin
|
||||||
|
o1 := 1;
|
||||||
|
o2 := 1;
|
||||||
|
c := 0;
|
||||||
|
w := 0;
|
||||||
|
DBMS_LOB.CreateTemporary(Result, true);
|
||||||
|
DBMS_LOB.ConvertToBlob(Result, AClob, length(AClob), o1, o2, 0, c, w);
|
||||||
|
return(Result);
|
||||||
|
end clob2blob;
|
||||||
|
|
||||||
|
```
|
||||||
10
docs/functions/EXTDATE_GET_ITA.md
Normal file
10
docs/functions/EXTDATE_GET_ITA.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# EXTDATE_GET_ITA
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
function extdate_get_ita( p_date date ) return varchar2
|
||||||
|
as
|
||||||
|
begin
|
||||||
|
return REGEXP_REPLACE(TO_CHAR(p_date, 'Day dd Month yyyy', 'NLS_DATE_LANGUAGE = ITALIAN'), ' [ ]+', ' ');
|
||||||
|
end;```
|
||||||
37
docs/functions/F_CI_SONO_EVENTI_CONFERMATI.md
Normal file
37
docs/functions/F_CI_SONO_EVENTI_CONFERMATI.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# F_CI_SONO_EVENTI_CONFERMATI
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_CI_SONO_EVENTI_CONFERMATI
|
||||||
|
(
|
||||||
|
P_EVT_DATE IN DATE
|
||||||
|
, P_LOCATION_ID IN NUMBER
|
||||||
|
, P_BYPASS IN NUMBER
|
||||||
|
) RETURN NUMBER AS
|
||||||
|
|
||||||
|
v_evt_cnt number;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
-- function bypass
|
||||||
|
if P_BYPASS > 0 then
|
||||||
|
return 0;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select
|
||||||
|
count(e.id) as evt_cnt
|
||||||
|
into v_evt_cnt
|
||||||
|
from eventi e
|
||||||
|
join vw_event_color c on c.id = e.id
|
||||||
|
where e.data = P_EVT_DATE
|
||||||
|
and e.id_location = P_LOCATION_ID
|
||||||
|
and c.status = 'Confermato';
|
||||||
|
|
||||||
|
if v_evt_cnt > 0 then
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
END F_CI_SONO_EVENTI_CONFERMATI;```
|
||||||
45
docs/functions/F_DAY_TO_NAME.md
Normal file
45
docs/functions/F_DAY_TO_NAME.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# F_DAY_TO_NAME
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_DAY_TO_NAME
|
||||||
|
(
|
||||||
|
DAY_NUMBER IN NUMBER
|
||||||
|
) RETURN VARCHAR2 AS
|
||||||
|
v_day_number number := DAY_NUMBER;
|
||||||
|
v_language varchar2(255);
|
||||||
|
BEGIN
|
||||||
|
with t as (
|
||||||
|
select DECODE(parameter, 'NLS_CHARACTERSET', 'CHARACTER SET',
|
||||||
|
'NLS_LANGUAGE', 'LANGUAGE',
|
||||||
|
'NLS_TERRITORY', 'TERRITORY') name,
|
||||||
|
value from v$nls_parameters
|
||||||
|
WHERE parameter IN ( 'NLS_CHARACTERSET', 'NLS_LANGUAGE', 'NLS_TERRITORY')
|
||||||
|
)
|
||||||
|
select value into v_language
|
||||||
|
from t
|
||||||
|
where name = 'LANGUAGE';
|
||||||
|
|
||||||
|
if v_language = 'AMERICAN' then
|
||||||
|
case v_day_number
|
||||||
|
when 1 then return 'Domenica';
|
||||||
|
when 2 then return 'Lunedì';
|
||||||
|
when 3 then return 'Martedì';
|
||||||
|
when 4 then return 'Mercoledì';
|
||||||
|
when 5 then return 'Giovedì';
|
||||||
|
when 6 then return 'Venerdì';
|
||||||
|
when 7 then return 'Sabato';
|
||||||
|
end case;
|
||||||
|
else
|
||||||
|
case v_day_number
|
||||||
|
when 1 then return 'Lunedì';
|
||||||
|
when 2 then return 'Martedì';
|
||||||
|
when 3 then return 'Mercoledì';
|
||||||
|
when 4 then return 'Giovedì';
|
||||||
|
when 5 then return 'Venerdì';
|
||||||
|
when 6 then return 'Sabato';
|
||||||
|
when 7 then return 'Domenica';
|
||||||
|
end case;
|
||||||
|
end if;
|
||||||
|
END F_DAY_TO_NAME;```
|
||||||
22
docs/functions/F_EVENTO_SCADUTO.md
Normal file
22
docs/functions/F_EVENTO_SCADUTO.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# F_EVENTO_SCADUTO
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_EVENTO_SCADUTO
|
||||||
|
(
|
||||||
|
DATA_SCADENZA IN DATE,
|
||||||
|
STATO_EVENTO IN NUMBER,
|
||||||
|
STATO_FROM IN NUMBER,
|
||||||
|
STATO_TO IN NUMBER
|
||||||
|
) RETURN NUMBER AS
|
||||||
|
BEGIN
|
||||||
|
if trunc(DATA_SCADENZA) <= trunc(sysdate)
|
||||||
|
and STATO_EVENTO between STATO_FROM and STATO_TO
|
||||||
|
then
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
end if;
|
||||||
|
END F_EVENTO_SCADUTO;
|
||||||
|
```
|
||||||
31
docs/functions/F_GET_ANGOLO_ALLESTIMENTO.md
Normal file
31
docs/functions/F_GET_ANGOLO_ALLESTIMENTO.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# F_GET_ANGOLO_ALLESTIMENTO
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "F_GET_ANGOLO_ALLESTIMENTO" (
|
||||||
|
p_filtro VARCHAR2,
|
||||||
|
p_id NUMBER
|
||||||
|
) RETURN VARCHAR2 AS
|
||||||
|
|
||||||
|
TYPE ref_cur IS REF CURSOR;
|
||||||
|
c_data ref_cur;
|
||||||
|
v_val VARCHAR2(1000);
|
||||||
|
v_filtro VARCHAR2(100);
|
||||||
|
v_id NUMBER;
|
||||||
|
BEGIN
|
||||||
|
v_filtro := p_filtro;
|
||||||
|
v_id := p_id;
|
||||||
|
OPEN c_data FOR ' select substr(a.descrizione || '' - '' || p.note ,1,1000)
|
||||||
|
from eventi e
|
||||||
|
left join location l on e.id_location = l.id
|
||||||
|
join eventi_det_prel p on e.id=p.id_evento
|
||||||
|
join articoli a on p.cod_articolo=a.cod_articolo
|
||||||
|
where p.COD_ARTICOLO = :filtro -- AN-GELAT
|
||||||
|
and e.id = to_number(:id)'
|
||||||
|
USING v_filtro, v_id;
|
||||||
|
|
||||||
|
FETCH c_data INTO v_val;
|
||||||
|
CLOSE c_data;
|
||||||
|
RETURN v_val;
|
||||||
|
END;```
|
||||||
34
docs/functions/F_GET_ANGOLO_ALLESTIMENTO_OB.md
Normal file
34
docs/functions/F_GET_ANGOLO_ALLESTIMENTO_OB.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# F_GET_ANGOLO_ALLESTIMENTO_OB
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "F_GET_ANGOLO_ALLESTIMENTO_OB" (
|
||||||
|
p_filtro VARCHAR2,
|
||||||
|
p_id NUMBER
|
||||||
|
) RETURN VARCHAR2
|
||||||
|
--ANGOLI OPEN BAR
|
||||||
|
AS
|
||||||
|
|
||||||
|
TYPE ref_cur IS REF CURSOR;
|
||||||
|
c_data ref_cur;
|
||||||
|
v_val VARCHAR2(1000);
|
||||||
|
v_filtro VARCHAR2(100);
|
||||||
|
v_id NUMBER;
|
||||||
|
BEGIN
|
||||||
|
v_filtro := p_filtro;
|
||||||
|
v_id := p_id;
|
||||||
|
OPEN c_data FOR ' select substr(a.descrizione || '' - '' || p.note ,1,1000)
|
||||||
|
from eventi e
|
||||||
|
left join location l on e.id_location = l.id
|
||||||
|
join eventi_det_prel p on e.id=p.id_evento
|
||||||
|
join articoli a on p.cod_articolo=a.cod_articolo
|
||||||
|
where a.cod_categ = ''AN-FIN''
|
||||||
|
and a.descrizione like :filtro -- AN-GELAT
|
||||||
|
and e.id = to_number(:id)'
|
||||||
|
USING v_filtro, v_id;
|
||||||
|
|
||||||
|
FETCH c_data INTO v_val;
|
||||||
|
CLOSE c_data;
|
||||||
|
RETURN v_val;
|
||||||
|
END;```
|
||||||
37
docs/functions/F_GET_COSTO_ARTICOLO.md
Normal file
37
docs/functions/F_GET_COSTO_ARTICOLO.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# F_GET_COSTO_ARTICOLO
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
function f_get_costo_articolo(p_cod_articolo varchar2, p_date date)
|
||||||
|
return number
|
||||||
|
as
|
||||||
|
v_costo number := null;
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- Cerco il costo alla data
|
||||||
|
begin
|
||||||
|
SELECT a.costo_uni
|
||||||
|
into v_costo
|
||||||
|
FROM COSTI_ARTICOLI a
|
||||||
|
where a.data_costo = p_date
|
||||||
|
and a.cod_articolo = p_cod_articolo;
|
||||||
|
exception when no_data_found then
|
||||||
|
v_costo := null;
|
||||||
|
end;
|
||||||
|
|
||||||
|
-- Se non lo trovo prendo l'ultimo costo
|
||||||
|
begin
|
||||||
|
SELECT a.costo_uni
|
||||||
|
into v_costo
|
||||||
|
FROM COSTI_ARTICOLI a
|
||||||
|
WHERE a.DATA_COSTO = (SELECT max(b.DATA_COSTO) FROM COSTI_ARTICOLI b where b.cod_articolo = a.cod_articolo)
|
||||||
|
and a.cod_articolo = p_cod_articolo;
|
||||||
|
exception when no_data_found then
|
||||||
|
v_costo := null;
|
||||||
|
end;
|
||||||
|
|
||||||
|
-- se non trovo niente torno 0
|
||||||
|
return nvl(v_costo, 0);
|
||||||
|
end;
|
||||||
|
```
|
||||||
164
docs/functions/F_GET_OSPITI.md
Normal file
164
docs/functions/F_GET_OSPITI.md
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
# F_GET_OSPITI
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "F_GET_OSPITI" (
|
||||||
|
p_id_evento IN NUMBER
|
||||||
|
) RETURN t_det_ospiti_tab
|
||||||
|
PIPELINED
|
||||||
|
AS
|
||||||
|
|
||||||
|
v_data DATE;
|
||||||
|
v_location VARCHAR2(100);
|
||||||
|
v_cliente VARCHAR2(100);
|
||||||
|
v_descrizione VARCHAR2(100);
|
||||||
|
v_ora_cerimonia VARCHAR2(10);
|
||||||
|
v_ora_evento VARCHAR2(10);
|
||||||
|
v_tot_adulti NUMBER;
|
||||||
|
v_tot_kinder NUMBER;
|
||||||
|
v_tot_baby NUMBER;
|
||||||
|
v_tot_staff NUMBER;
|
||||||
|
v_tot_invitati NUMBER;
|
||||||
|
v_allergie VARCHAR2(4000);
|
||||||
|
v_torta VARCHAR2(1000);
|
||||||
|
v_confettata VARCHAR2(100);
|
||||||
|
v_stampa_menu VARCHAR2(100);
|
||||||
|
v_angoli VARCHAR2(1000);
|
||||||
|
v_extra_info VARCHAR2(1000);
|
||||||
|
v_note_adulti VARCHAR2(1000);
|
||||||
|
v_note_kinder VARCHAR2(1000);
|
||||||
|
v_note_baby VARCHAR2(1000);
|
||||||
|
v_note_staff VARCHAR2(1000);
|
||||||
|
BEGIN
|
||||||
|
BEGIN
|
||||||
|
v_tot_adulti := 0;
|
||||||
|
v_tot_kinder := 0;
|
||||||
|
v_tot_baby := 0;
|
||||||
|
v_tot_staff := 0;
|
||||||
|
v_tot_invitati := 0;
|
||||||
|
v_angoli := 0;
|
||||||
|
v_note_adulti := '';
|
||||||
|
v_note_kinder := '';
|
||||||
|
v_note_baby := '';
|
||||||
|
v_note_staff := '';
|
||||||
|
|
||||||
|
--ospiti
|
||||||
|
SELECT
|
||||||
|
nvl(SUM(o.numero),
|
||||||
|
0)
|
||||||
|
INTO v_tot_adulti
|
||||||
|
FROM
|
||||||
|
eventi_det_ospiti o
|
||||||
|
WHERE
|
||||||
|
o.id_evento = p_id_evento
|
||||||
|
AND o.cod_tipo_ospite = 8; -- adulti
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
SELECT
|
||||||
|
o.note
|
||||||
|
INTO v_note_adulti
|
||||||
|
FROM
|
||||||
|
eventi_det_ospiti o
|
||||||
|
WHERE
|
||||||
|
o.id_evento = p_id_evento
|
||||||
|
AND o.cod_tipo_ospite = 8; -- adulti
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN no_data_found THEN
|
||||||
|
NULL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
nvl(SUM(o.numero),
|
||||||
|
0)
|
||||||
|
INTO v_tot_kinder
|
||||||
|
FROM
|
||||||
|
eventi_det_ospiti o
|
||||||
|
WHERE
|
||||||
|
o.id_evento = p_id_evento
|
||||||
|
AND o.cod_tipo_ospite = 5; --Kinder
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
SELECT
|
||||||
|
o.note
|
||||||
|
INTO v_note_kinder
|
||||||
|
FROM
|
||||||
|
eventi_det_ospiti o
|
||||||
|
WHERE
|
||||||
|
o.id_evento = p_id_evento
|
||||||
|
AND o.cod_tipo_ospite = 5; --Kinder
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN no_data_found THEN
|
||||||
|
NULL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
nvl(SUM(o.numero),
|
||||||
|
0)
|
||||||
|
INTO v_tot_baby
|
||||||
|
FROM
|
||||||
|
eventi_det_ospiti o
|
||||||
|
WHERE
|
||||||
|
o.id_evento = p_id_evento
|
||||||
|
AND o.cod_tipo_ospite = 6; -- Baby
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
SELECT
|
||||||
|
o.note
|
||||||
|
INTO v_note_baby
|
||||||
|
FROM
|
||||||
|
eventi_det_ospiti o
|
||||||
|
WHERE
|
||||||
|
o.id_evento = p_id_evento
|
||||||
|
AND o.cod_tipo_ospite = 6; -- Baby
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN no_data_found THEN
|
||||||
|
NULL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
nvl(SUM(o.numero),
|
||||||
|
0)
|
||||||
|
INTO v_tot_staff
|
||||||
|
FROM
|
||||||
|
eventi_det_ospiti o
|
||||||
|
WHERE
|
||||||
|
o.id_evento = p_id_evento
|
||||||
|
AND o.cod_tipo_ospite = 7; -- Staff
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
SELECT
|
||||||
|
o.note
|
||||||
|
INTO v_note_staff
|
||||||
|
FROM
|
||||||
|
eventi_det_ospiti o
|
||||||
|
WHERE
|
||||||
|
o.id_evento = p_id_evento
|
||||||
|
AND o.cod_tipo_ospite = 7; -- Staff
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN no_data_found THEN
|
||||||
|
NULL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
nvl(e.tot_ospiti, 0)
|
||||||
|
INTO v_tot_invitati
|
||||||
|
FROM
|
||||||
|
eventi e
|
||||||
|
WHERE
|
||||||
|
e.id = p_id_evento;
|
||||||
|
|
||||||
|
PIPE ROW ( t_det_ospiti_row(p_id_evento, v_tot_adulti, v_tot_kinder, v_tot_baby, v_tot_staff,
|
||||||
|
v_tot_invitati, v_note_adulti, v_note_kinder, v_note_baby, v_note_staff) );
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
NULL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
END;```
|
||||||
36
docs/functions/F_GET_QTA_IMPEGNATA.md
Normal file
36
docs/functions/F_GET_QTA_IMPEGNATA.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# F_GET_QTA_IMPEGNATA
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "F_GET_QTA_IMPEGNATA" (
|
||||||
|
p_codart VARCHAR2,
|
||||||
|
p_data_from DATE,
|
||||||
|
p_data_to DATE DEFAULT NULL
|
||||||
|
) RETURN NUMBER AS
|
||||||
|
v_qta NUMBER;
|
||||||
|
v_data_to DATE := p_data_to;
|
||||||
|
BEGIN
|
||||||
|
v_qta := 0;
|
||||||
|
IF ( p_data_to IS NULL ) THEN
|
||||||
|
v_data_to := p_data_from;
|
||||||
|
END IF;
|
||||||
|
BEGIN
|
||||||
|
SELECT
|
||||||
|
nvl(SUM(qta_imp),
|
||||||
|
0)
|
||||||
|
INTO v_qta
|
||||||
|
FROM
|
||||||
|
v_impegni_articoli
|
||||||
|
WHERE
|
||||||
|
cod_articolo = p_codart
|
||||||
|
--and data <= p_data --
|
||||||
|
AND data BETWEEN p_data_from AND v_data_to; -- qta impegnata per quella data
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
v_qta := 0;
|
||||||
|
END;
|
||||||
|
|
||||||
|
RETURN v_qta;
|
||||||
|
END;```
|
||||||
31
docs/functions/F_GET_TOT_OSPITI.md
Normal file
31
docs/functions/F_GET_TOT_OSPITI.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# F_GET_TOT_OSPITI
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "F_GET_TOT_OSPITI" (
|
||||||
|
p_id_evento IN NUMBER,
|
||||||
|
p_tipo_ospite IN NUMBER := -1
|
||||||
|
) RETURN NUMBER AS
|
||||||
|
v_tot NUMBER;
|
||||||
|
BEGIN
|
||||||
|
v_tot := 0;
|
||||||
|
BEGIN
|
||||||
|
SELECT
|
||||||
|
nvl(SUM(numero),
|
||||||
|
0)
|
||||||
|
INTO v_tot
|
||||||
|
FROM
|
||||||
|
eventi_det_ospiti
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
AND ( cod_tipo_ospite = p_tipo_ospite
|
||||||
|
OR p_tipo_ospite = - 1 );
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
v_tot := 0;
|
||||||
|
END;
|
||||||
|
|
||||||
|
RETURN v_tot;
|
||||||
|
END;```
|
||||||
34
docs/functions/F_GET_TOVAGLIATO_ALLESTIMENTO.md
Normal file
34
docs/functions/F_GET_TOVAGLIATO_ALLESTIMENTO.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# F_GET_TOVAGLIATO_ALLESTIMENTO
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "F_GET_TOVAGLIATO_ALLESTIMENTO" (
|
||||||
|
p_filtro VARCHAR2,
|
||||||
|
p_id NUMBER
|
||||||
|
) RETURN VARCHAR2 AS
|
||||||
|
|
||||||
|
TYPE ref_cur IS REF CURSOR;
|
||||||
|
c_data ref_cur;
|
||||||
|
v_val VARCHAR2(1000);
|
||||||
|
v_filtro VARCHAR2(100);
|
||||||
|
v_id NUMBER;
|
||||||
|
BEGIN
|
||||||
|
v_filtro := p_filtro;
|
||||||
|
v_id := p_id;
|
||||||
|
OPEN c_data FOR ' select substr(a.descrizione || '' - '' || p.note ,1,1000) as dato
|
||||||
|
from eventi e
|
||||||
|
left join location l on e.id_location = l.id
|
||||||
|
join eventi_det_prel p on e.id=p.id_evento
|
||||||
|
join articoli a on p.cod_articolo=a.cod_articolo
|
||||||
|
join TB_CODICI_CATEG c on a.cod_categ=c.cod_categ
|
||||||
|
--where c.COD_TIPO = ''TVB'' -- dividere tovagliolo da tovagliato con i codici categ
|
||||||
|
where c.COD_TIPO = :filtro
|
||||||
|
and rownum = 1 -- se esistono più articoli fare list_agg op loop
|
||||||
|
and e.id = to_number(:id)'
|
||||||
|
USING v_filtro, v_id;
|
||||||
|
|
||||||
|
FETCH c_data INTO v_val;
|
||||||
|
CLOSE c_data;
|
||||||
|
RETURN v_val;
|
||||||
|
END;```
|
||||||
84
docs/functions/F_LIST_PRELIEVO_ADD_ARTICOLO.md
Normal file
84
docs/functions/F_LIST_PRELIEVO_ADD_ARTICOLO.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# F_LIST_PRELIEVO_ADD_ARTICOLO
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
function f_list_prelievo_add_articolo(
|
||||||
|
p_event_id number,
|
||||||
|
p_articolo_add varchar2,
|
||||||
|
p_qta_aperitivo NUMBER := 0,
|
||||||
|
p_qta_seduto NUMBER := 0,
|
||||||
|
p_qta_dolci NUMBER := 0
|
||||||
|
)
|
||||||
|
return varchar2
|
||||||
|
as
|
||||||
|
v_qta_imp number;
|
||||||
|
v_qta_giac number;
|
||||||
|
v_data_evento date;
|
||||||
|
v_cod_art varchar2(10);
|
||||||
|
v_error_json varchar2(4000);
|
||||||
|
v_qta_da_imp NUMBER;
|
||||||
|
v_qta_da_imp_test NUMBER;
|
||||||
|
v_num_evt_imp number;
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
v_cod_art := p_articolo_add;
|
||||||
|
v_qta_da_imp := nvl(p_qta_aperitivo, 0) + nvl(p_qta_seduto, 0) + nvl(p_qta_dolci, 0);
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
select trunc(data) as data
|
||||||
|
into v_data_evento
|
||||||
|
from eventi where id = p_event_id;
|
||||||
|
exception when no_data_found then
|
||||||
|
rollback;
|
||||||
|
RETURN '{"type":"error","code":"'||SQLCODE||'","stack":"'||SQLERRM||'","message":"Evento non trovato"}';
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
select qta_giac
|
||||||
|
into v_qta_giac
|
||||||
|
from articoli
|
||||||
|
where COD_ARTICOLO = v_cod_art;
|
||||||
|
exception when no_data_found then
|
||||||
|
rollback;
|
||||||
|
RETURN '{"type":"error","code":"'||SQLCODE||'","stack":"'||SQLERRM||'","message":"Articolo non trovato"}';
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
select count(*)
|
||||||
|
into v_num_evt_imp
|
||||||
|
from V_IMPEGNI_ARTICOLI
|
||||||
|
where COD_ARTICOLO = v_cod_art
|
||||||
|
and data between v_data_evento - 2 and v_data_evento + 2;
|
||||||
|
|
||||||
|
v_qta_imp := nvl(f_get_qta_impegnata (v_cod_art, v_data_evento - 2, v_data_evento + 2 ) , 0);
|
||||||
|
|
||||||
|
--insert impegno articolo
|
||||||
|
begin
|
||||||
|
insert into eventi_det_prel (id_evento, cod_articolo,QTA_MAN_APE,QTA_MAN_SEDU,QTA_MAN_BUFDOL, COSTO_ARTICOLO)
|
||||||
|
values (p_event_id, p_articolo_add, p_qta_aperitivo, p_qta_seduto, p_qta_dolci, f_get_costo_articolo(v_cod_art, v_data_evento));
|
||||||
|
|
||||||
|
-- aggiorna liste prelievo
|
||||||
|
EVENTI_AGGIORNA_QTA_LISTA(
|
||||||
|
P_ID_EVENTO => p_event_id
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Controlla banalmente se sono stati prelevati su altri eventi
|
||||||
|
if v_qta_imp + v_qta_da_imp > v_qta_giac then
|
||||||
|
RETURN '{"type":"warning","message":"Attenzione: Non hai abbastanza articoli di questo tipo a magazzino"}';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Se trovo articoli già impegnati in quel giorno mostro un messaggio - 16/11/2022
|
||||||
|
-- Continuo lo stesso ma do un messaggio di errore anzichè di successo
|
||||||
|
if(v_qta_imp > 0 and v_num_evt_imp > 0) then
|
||||||
|
RETURN '{"type":"warning","code":"'||SQLCODE||'","stack":"'||SQLERRM||'","message":"Attenzione! Articolo '||p_articolo_add||' già impegnato '||v_num_evt_imp||' '||(case when v_num_evt_imp > 1 then 'volte' else 'volta' end)||' dal '||to_char(v_data_evento - 2, 'dd-mm-yyyy')||' al '||to_char(v_data_evento + 2, 'dd-mm-yyyy')||'"}';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
RETURN '{"type":"success","message":"Articolo aggiunto con successo"}';
|
||||||
|
exception when others then
|
||||||
|
RETURN '{"type":"success","message":"Articolo aggiunto con errori: '||replace(replace(SQLERRM, 'ORA-20000: Errore:', ''), '-20000 - ', '')||'"}';
|
||||||
|
end;
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
return '{"type":"error","code":"","stack":"","message":"Errore sconosciuto"}';
|
||||||
|
end f_list_prelievo_add_articolo;```
|
||||||
38
docs/functions/F_MAX_NUMERO_EVENTI_RAGGIUNTO.md
Normal file
38
docs/functions/F_MAX_NUMERO_EVENTI_RAGGIUNTO.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# F_MAX_NUMERO_EVENTI_RAGGIUNTO
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_MAX_NUMERO_EVENTI_RAGGIUNTO
|
||||||
|
(
|
||||||
|
P_GIORNO IN DATE
|
||||||
|
) RETURN NUMBER AS
|
||||||
|
v_max_eventi TB_CALENDAR_LOCKS.max_eventi%TYPE; -- Variable to hold the max_eventi value from TB_CALENDAR_LOCKS
|
||||||
|
v_event_count NUMBER; -- Variable to hold the count of events from EVENTI
|
||||||
|
BEGIN
|
||||||
|
-- Step 1: Check if P_GIORNO is present in TB_CALENDAR_LOCKS and get the max_eventi value for that day
|
||||||
|
BEGIN
|
||||||
|
SELECT max_eventi
|
||||||
|
INTO v_max_eventi
|
||||||
|
FROM TB_CALENDAR_LOCKS
|
||||||
|
WHERE giorno = P_GIORNO;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN NO_DATA_FOUND THEN
|
||||||
|
-- If the date is not found in TB_CALENDAR_LOCKS, return -1 (or some other code to indicate the absence)
|
||||||
|
RETURN -1;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Step 2: Count how many events occurred on P_GIORNO in the EVENTI table
|
||||||
|
SELECT COUNT(*)
|
||||||
|
INTO v_event_count
|
||||||
|
FROM EVENTI
|
||||||
|
WHERE TRUNC(DATA) = TRUNC(P_GIORNO); -- Use TRUNC to compare only the date part
|
||||||
|
|
||||||
|
-- Step 3: Compare the event count with the max_eventi and return the appropriate result
|
||||||
|
IF v_event_count >= v_max_eventi THEN
|
||||||
|
RETURN 1; -- Maximum number of events has been reached or exceeded
|
||||||
|
ELSE
|
||||||
|
RETURN 0; -- Maximum number of events has not been reached
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
END F_MAX_NUMERO_EVENTI_RAGGIUNTO;```
|
||||||
36
docs/functions/F_MAX_NUM_EVENTI_CONFERMATI.md
Normal file
36
docs/functions/F_MAX_NUM_EVENTI_CONFERMATI.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# F_MAX_NUM_EVENTI_CONFERMATI
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_MAX_NUM_EVENTI_CONFERMATI
|
||||||
|
(
|
||||||
|
P_EVT_DATE IN DATE
|
||||||
|
, P_MAX_EVT_NUM NUMBER
|
||||||
|
, P_BYPASS IN NUMBER
|
||||||
|
) RETURN NUMBER AS
|
||||||
|
|
||||||
|
v_evt_cnt number;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
-- function bypass
|
||||||
|
if P_BYPASS > 0 then
|
||||||
|
return 0;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select
|
||||||
|
count(e.id) as evt_cnt
|
||||||
|
into v_evt_cnt
|
||||||
|
from eventi e
|
||||||
|
join vw_event_color c on c.id = e.id
|
||||||
|
where e.data = P_EVT_DATE
|
||||||
|
and c.status = 'Confermato';
|
||||||
|
|
||||||
|
if v_evt_cnt >= P_MAX_EVT_NUM then
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
END F_MAX_NUM_EVENTI_CONFERMATI;```
|
||||||
433
docs/functions/F_REP_ALLESTIMENTI.md
Normal file
433
docs/functions/F_REP_ALLESTIMENTI.md
Normal file
@@ -0,0 +1,433 @@
|
|||||||
|
# F_REP_ALLESTIMENTI
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "F_REP_ALLESTIMENTI" ( p_data_in IN varchar2 default to_char(sysdate,'YYYYMMD'),
|
||||||
|
p_data_fi IN varchar2 default to_char(sysdate + 30,'YYYYMMD')
|
||||||
|
)
|
||||||
|
RETURN t_rep_allestimenti_tab PIPELINED AS
|
||||||
|
|
||||||
|
v_data_in varchar2(100);
|
||||||
|
v_data_fi varchar2(100);
|
||||||
|
|
||||||
|
cursor c_evento is
|
||||||
|
with t as (--select e.id, e.data, l.location, e.torta, e.confettata, e.stampa_menu
|
||||||
|
select e.id, e.data, l.location, e.torta,
|
||||||
|
e.altro_a as confettata,
|
||||||
|
e.sedia as stampa_menu
|
||||||
|
from eventi e
|
||||||
|
left join location l on e.id_location = l.id
|
||||||
|
--where data >= sysdate
|
||||||
|
where e.data between to_date(v_data_in,'YYYYMMDD') and to_date(v_data_fi,'YYYYMMDD')
|
||||||
|
and e.stato in (300, 400) -- 300 Scheda Confermata, 400 Confermato (Lista)
|
||||||
|
and e.disabled = 0
|
||||||
|
and e.deleted = 0
|
||||||
|
order by data, to_number(to_char(e.ora_evento,'HH24MI'))
|
||||||
|
)
|
||||||
|
, q as (select t.* , rownum as order_id
|
||||||
|
from t
|
||||||
|
order by data
|
||||||
|
)
|
||||||
|
, r as (select
|
||||||
|
case when order_id =1 then id else null end as id1,
|
||||||
|
case when order_id =2 then id else null end as id2,
|
||||||
|
case when order_id =3 then id else null end as id3,
|
||||||
|
case when order_id =4 then id else null end as id4,
|
||||||
|
case when order_id =5 then id else null end as id5,
|
||||||
|
case when order_id =6 then id else null end as id6,
|
||||||
|
case when order_id =7 then id else null end as id7,
|
||||||
|
case when order_id =8 then id else null end as id8,
|
||||||
|
case when order_id =9 then id else null end as id9,
|
||||||
|
case when order_id =10 then id else null end as id10,
|
||||||
|
case when order_id =11 then id else null end as id11,
|
||||||
|
case when order_id =12 then id else null end as id12,
|
||||||
|
|
||||||
|
case when order_id =1 then data else null end as data1,
|
||||||
|
case when order_id =2 then data else null end as data2,
|
||||||
|
case when order_id =3 then data else null end as data3,
|
||||||
|
case when order_id =4 then data else null end as data4,
|
||||||
|
case when order_id =5 then data else null end as data5,
|
||||||
|
case when order_id =6 then data else null end as data6,
|
||||||
|
case when order_id =7 then data else null end as data7,
|
||||||
|
case when order_id =8 then data else null end as data8,
|
||||||
|
case when order_id =9 then data else null end as data9,
|
||||||
|
case when order_id =10 then data else null end as data10,
|
||||||
|
case when order_id =11 then data else null end as data11,
|
||||||
|
case when order_id =12 then data else null end as data12,
|
||||||
|
|
||||||
|
case when order_id =1 then location else null end as location1,
|
||||||
|
case when order_id =2 then location else null end as location2,
|
||||||
|
case when order_id =3 then location else null end as location3,
|
||||||
|
case when order_id =4 then location else null end as location4,
|
||||||
|
case when order_id =5 then location else null end as location5,
|
||||||
|
case when order_id =6 then location else null end as location6,
|
||||||
|
case when order_id =7 then location else null end as location7,
|
||||||
|
case when order_id =8 then location else null end as location8,
|
||||||
|
case when order_id =9 then location else null end as location9,
|
||||||
|
case when order_id =10 then location else null end as location10,
|
||||||
|
case when order_id =11 then location else null end as location11,
|
||||||
|
case when order_id =12 then location else null end as location12,
|
||||||
|
|
||||||
|
case when order_id =1 then torta else null end as torta1,
|
||||||
|
case when order_id =2 then torta else null end as torta2,
|
||||||
|
case when order_id =3 then torta else null end as torta3,
|
||||||
|
case when order_id =4 then torta else null end as torta4,
|
||||||
|
case when order_id =5 then torta else null end as torta5,
|
||||||
|
case when order_id =6 then torta else null end as torta6,
|
||||||
|
case when order_id =7 then torta else null end as torta7,
|
||||||
|
case when order_id =8 then torta else null end as torta8,
|
||||||
|
case when order_id =9 then torta else null end as torta9,
|
||||||
|
case when order_id =10 then torta else null end as torta10,
|
||||||
|
case when order_id =11 then torta else null end as torta11,
|
||||||
|
case when order_id =12 then torta else null end as torta12,
|
||||||
|
|
||||||
|
case when order_id =1 then confettata else null end as confettata1,
|
||||||
|
case when order_id =2 then confettata else null end as confettata2,
|
||||||
|
case when order_id =3 then confettata else null end as confettata3,
|
||||||
|
case when order_id =4 then confettata else null end as confettata4,
|
||||||
|
case when order_id =5 then confettata else null end as confettata5,
|
||||||
|
case when order_id =6 then confettata else null end as confettata6,
|
||||||
|
case when order_id =7 then confettata else null end as confettata7,
|
||||||
|
case when order_id =8 then confettata else null end as confettata8,
|
||||||
|
case when order_id =9 then confettata else null end as confettata9,
|
||||||
|
case when order_id =10 then confettata else null end as confettata10,
|
||||||
|
case when order_id =11 then confettata else null end as confettata11,
|
||||||
|
case when order_id =12 then confettata else null end as confettata12,
|
||||||
|
|
||||||
|
case when order_id =1 then stampa_menu else null end as stampa_menu1,
|
||||||
|
case when order_id =2 then stampa_menu else null end as stampa_menu2,
|
||||||
|
case when order_id =3 then stampa_menu else null end as stampa_menu3,
|
||||||
|
case when order_id =4 then stampa_menu else null end as stampa_menu4,
|
||||||
|
case when order_id =5 then stampa_menu else null end as stampa_menu5,
|
||||||
|
case when order_id =6 then stampa_menu else null end as stampa_menu6,
|
||||||
|
case when order_id =7 then stampa_menu else null end as stampa_menu7,
|
||||||
|
case when order_id =8 then stampa_menu else null end as stampa_menu8,
|
||||||
|
case when order_id =9 then stampa_menu else null end as stampa_menu9,
|
||||||
|
case when order_id =10 then stampa_menu else null end as stampa_menu10,
|
||||||
|
case when order_id =11 then stampa_menu else null end as stampa_menu11,
|
||||||
|
case when order_id =12 then stampa_menu else null end as stampa_menu12
|
||||||
|
from q
|
||||||
|
)
|
||||||
|
select min(id1) as id1,
|
||||||
|
min(id2) as id2,
|
||||||
|
min(id3) as id3,
|
||||||
|
min(id4) as id4,
|
||||||
|
min(id5) as id5,
|
||||||
|
min(id6) as id6,
|
||||||
|
min(id7) as id7,
|
||||||
|
min(id8) as id8,
|
||||||
|
min(id9) as id9,
|
||||||
|
min(id10) as id10,
|
||||||
|
min(id11) as id11,
|
||||||
|
min(id12) as id12,
|
||||||
|
|
||||||
|
min(data1) as d1,
|
||||||
|
min(data2) as d2,
|
||||||
|
min(data3) as d3,
|
||||||
|
min(data4) as d4,
|
||||||
|
min(data5) as d5,
|
||||||
|
min(data6) as d6,
|
||||||
|
min(data7) as d7,
|
||||||
|
min(data8) as d8,
|
||||||
|
min(data9) as d9,
|
||||||
|
min(data10) as d10,
|
||||||
|
min(data11) as d11,
|
||||||
|
min(data12) as d12,
|
||||||
|
|
||||||
|
min(location1) as l1,
|
||||||
|
min(location2) as l2,
|
||||||
|
min(location3) as l3,
|
||||||
|
min(location4) as l4,
|
||||||
|
min(location5) as l5,
|
||||||
|
min(location6) as l6,
|
||||||
|
min(location7) as l7,
|
||||||
|
min(location8) as l8,
|
||||||
|
min(location9) as l9,
|
||||||
|
min(location10) as l10,
|
||||||
|
min(location11) as l11,
|
||||||
|
min(location12) as l12,
|
||||||
|
|
||||||
|
min(torta1) as t1,
|
||||||
|
min(torta2) as t2,
|
||||||
|
min(torta3) as t3,
|
||||||
|
min(torta4) as t4,
|
||||||
|
min(torta5) as t5,
|
||||||
|
min(torta6) as t6,
|
||||||
|
min(torta7) as t7,
|
||||||
|
min(torta8) as t8,
|
||||||
|
min(torta9) as t9,
|
||||||
|
min(torta10) as t10,
|
||||||
|
min(torta11) as t11,
|
||||||
|
min(torta12) as t12,
|
||||||
|
|
||||||
|
min(confettata1) as c1,
|
||||||
|
min(confettata2) as c2,
|
||||||
|
min(confettata3) as c3,
|
||||||
|
min(confettata4) as c4,
|
||||||
|
min(confettata5) as c5,
|
||||||
|
min(confettata6) as c6,
|
||||||
|
min(confettata7) as c7,
|
||||||
|
min(confettata8) as c8,
|
||||||
|
min(confettata9) as c9,
|
||||||
|
min(confettata10) as c10,
|
||||||
|
min(confettata11) as c11,
|
||||||
|
min(confettata12) as c12,
|
||||||
|
|
||||||
|
min(stampa_menu1) as SM1,
|
||||||
|
min(stampa_menu2) as SM2,
|
||||||
|
min(stampa_menu3) as SM3,
|
||||||
|
min(stampa_menu4) as SM4,
|
||||||
|
min(stampa_menu5) as SM5,
|
||||||
|
min(stampa_menu6) as SM6,
|
||||||
|
min(stampa_menu7) as SM7,
|
||||||
|
min(stampa_menu8) as SM8,
|
||||||
|
min(stampa_menu9) as SM9,
|
||||||
|
min(stampa_menu10) as SM10,
|
||||||
|
min(stampa_menu11) as SM11,
|
||||||
|
min(stampa_menu12) as SM12
|
||||||
|
from r;
|
||||||
|
|
||||||
|
c_evt c_evento%ROWTYPE;
|
||||||
|
|
||||||
|
type v_TOVAGLIATO_AR IS VARRAY(12) OF VARCHAR2(4000);
|
||||||
|
v_TOVAGLIATO v_TOVAGLIATO_AR;
|
||||||
|
|
||||||
|
C1 varchar2(100);
|
||||||
|
C2 varchar2(100);
|
||||||
|
C3 varchar2(100);
|
||||||
|
C4 varchar2(100);
|
||||||
|
C5 varchar2(100);
|
||||||
|
C6 varchar2(100);
|
||||||
|
C7 varchar2(100);
|
||||||
|
C8 varchar2(100);
|
||||||
|
C9 varchar2(100);
|
||||||
|
C10 varchar2(100);
|
||||||
|
C11 varchar2(100);
|
||||||
|
C12 varchar2(100);
|
||||||
|
|
||||||
|
type v_TOVAGLIOLO_AR IS VARRAY(12) OF VARCHAR2(1000);
|
||||||
|
v_TOVAGLIOLO v_TOVAGLIOLO_AR;
|
||||||
|
|
||||||
|
type v_AN_GELATO_AR IS VARRAY(12) OF VARCHAR2(1000);
|
||||||
|
v_AN_GELATO v_AN_GELATO_AR;
|
||||||
|
type v_AN_GELATO2_AR IS VARRAY(12) OF VARCHAR2(1000);
|
||||||
|
v_AN_GELATO2 v_AN_GELATO2_AR;
|
||||||
|
|
||||||
|
type v_AN_OPENBAR_AR IS VARRAY(12) OF VARCHAR2(1000);
|
||||||
|
v_AN_OPENBAR v_AN_OPENBAR_AR;
|
||||||
|
type v_AN_RUM_AR IS VARRAY(12) OF VARCHAR2(1000);
|
||||||
|
v_AN_RUM v_AN_RUM_AR;
|
||||||
|
|
||||||
|
T1 varchar2(100);
|
||||||
|
T2 varchar2(100);
|
||||||
|
T3 varchar2(100);
|
||||||
|
T4 varchar2(100);
|
||||||
|
T5 varchar2(100);
|
||||||
|
T6 varchar2(100);
|
||||||
|
T7 varchar2(100);
|
||||||
|
T8 varchar2(100);
|
||||||
|
T9 varchar2(100);
|
||||||
|
T10 varchar2(100);
|
||||||
|
T11 varchar2(100);
|
||||||
|
T12 varchar2(100);
|
||||||
|
|
||||||
|
v_appo varchar2(100);
|
||||||
|
|
||||||
|
v_dato varchar2(100);
|
||||||
|
v_id_str varchar2(100);
|
||||||
|
v_id number;
|
||||||
|
v_qry varchar2(1000);
|
||||||
|
|
||||||
|
type v_IDEVT_AR IS VARRAY(12) OF number;
|
||||||
|
v_IDEVT v_IDEVT_AR;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
--default su date
|
||||||
|
if p_data_in is null then
|
||||||
|
v_data_in := to_char(sysdate,'YYYYMMD');
|
||||||
|
else
|
||||||
|
v_data_in := p_data_in;
|
||||||
|
end if;
|
||||||
|
if p_data_fi is null then
|
||||||
|
v_data_fi := to_char(sysdate + 30,'YYYYMMD');
|
||||||
|
else
|
||||||
|
v_data_fi := p_data_fi;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
v_TOVAGLIATO := v_TOVAGLIATO_AR(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
|
||||||
|
v_TOVAGLIOLO := v_TOVAGLIOLO_AR(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
|
||||||
|
v_AN_GELATO := v_AN_GELATO_AR(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
|
||||||
|
v_AN_GELATO2 := v_AN_GELATO2_AR(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
|
||||||
|
v_AN_OPENBAR := v_AN_OPENBAR_AR(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
|
||||||
|
v_AN_RUM := v_AN_RUM_AR(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
|
||||||
|
v_IDEVT := v_IDEVT_AR(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
|
||||||
|
|
||||||
|
open c_evento;
|
||||||
|
fetch c_evento into c_evt;
|
||||||
|
--exit when c_evento%NOTFOUND;
|
||||||
|
|
||||||
|
--caricare su vettore gli id:
|
||||||
|
v_IDEVT(1) := c_evt.id1;
|
||||||
|
v_IDEVT(2) := c_evt.id2;
|
||||||
|
v_IDEVT(3) := c_evt.id3;
|
||||||
|
v_IDEVT(4) := c_evt.id4;
|
||||||
|
v_IDEVT(5) := c_evt.id5;
|
||||||
|
v_IDEVT(6) := c_evt.id6;
|
||||||
|
v_IDEVT(7) := c_evt.id7;
|
||||||
|
v_IDEVT(8) := c_evt.id8;
|
||||||
|
v_IDEVT(9) := c_evt.id9;
|
||||||
|
v_IDEVT(10) := c_evt.id10;
|
||||||
|
v_IDEVT(11) := c_evt.id11;
|
||||||
|
v_IDEVT(12) := c_evt.id12;
|
||||||
|
|
||||||
|
FOR i in 1 .. 12 LOOP
|
||||||
|
v_dato := '';
|
||||||
|
|
||||||
|
v_id := to_char(v_IDEVT(i));
|
||||||
|
|
||||||
|
v_TOVAGLIATO(i) := f_get_tovagliato_allestimento ('TVB', v_IDEVT(i) ) ;
|
||||||
|
v_AN_GELATO(i) := f_get_angolo_allestimento ('AN-GELAT', v_IDEVT(i) ) ;
|
||||||
|
v_AN_GELATO2(i) := f_get_angolo_allestimento ('AN-GEL-BOM', v_IDEVT(i) ) ;
|
||||||
|
--v_AN_OPENBAR(i) := f_get_angolo_allestimento ('OPEN-B', v_IDEVT(i) ) ;
|
||||||
|
v_AN_OPENBAR(i) := f_get_angolo_allestimento_OB ('%OPEN BAR%', v_IDEVT(i) ) ;
|
||||||
|
v_AN_RUM(i) := f_get_angolo_allestimento ('AN-RUM-CI', v_IDEVT(i) ) ;
|
||||||
|
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
PIPE ROW(t_rep_allestimenti_row(c_evt.D1 ,
|
||||||
|
c_evt.D2 ,
|
||||||
|
c_evt.D3 ,
|
||||||
|
c_evt.D4 ,
|
||||||
|
c_evt.D5 ,
|
||||||
|
c_evt.D6 ,
|
||||||
|
c_evt.D7 ,
|
||||||
|
c_evt.D8 ,
|
||||||
|
c_evt.D9 ,
|
||||||
|
c_evt.D10 ,
|
||||||
|
c_evt.D11 ,
|
||||||
|
c_evt.D12 ,
|
||||||
|
|
||||||
|
c_evt.L1 ,
|
||||||
|
c_evt.L2 ,
|
||||||
|
c_evt.L3 ,
|
||||||
|
c_evt.L4 ,
|
||||||
|
c_evt.L5 ,
|
||||||
|
c_evt.L6 ,
|
||||||
|
c_evt.L7 ,
|
||||||
|
c_evt.L8 ,
|
||||||
|
c_evt.L9 ,
|
||||||
|
c_evt.L10 ,
|
||||||
|
c_evt.L11 ,
|
||||||
|
c_evt.L12 ,
|
||||||
|
|
||||||
|
v_TOVAGLIATO(1),
|
||||||
|
v_TOVAGLIATO(2),
|
||||||
|
v_TOVAGLIATO(3),
|
||||||
|
v_TOVAGLIATO(4),
|
||||||
|
v_TOVAGLIATO(5),
|
||||||
|
v_TOVAGLIATO(6),
|
||||||
|
v_TOVAGLIATO(7),
|
||||||
|
v_TOVAGLIATO(8),
|
||||||
|
v_TOVAGLIATO(9),
|
||||||
|
v_TOVAGLIATO(10),
|
||||||
|
v_TOVAGLIATO(11),
|
||||||
|
v_TOVAGLIATO(12),
|
||||||
|
|
||||||
|
c_evt.C1 ,
|
||||||
|
c_evt.C2 ,
|
||||||
|
c_evt.C3 ,
|
||||||
|
c_evt.C4 ,
|
||||||
|
c_evt.C5 ,
|
||||||
|
c_evt.C6 ,
|
||||||
|
c_evt.C7 ,
|
||||||
|
c_evt.C8 ,
|
||||||
|
c_evt.C9 ,
|
||||||
|
c_evt.C10 ,
|
||||||
|
c_evt.C11 ,
|
||||||
|
c_evt.C12 ,
|
||||||
|
|
||||||
|
v_TOVAGLIOLO(1),
|
||||||
|
v_TOVAGLIOLO(2),
|
||||||
|
v_TOVAGLIOLO(3),
|
||||||
|
v_TOVAGLIOLO(4),
|
||||||
|
v_TOVAGLIOLO(5),
|
||||||
|
v_TOVAGLIOLO(6),
|
||||||
|
v_TOVAGLIOLO(7),
|
||||||
|
v_TOVAGLIOLO(8),
|
||||||
|
v_TOVAGLIOLO(9),
|
||||||
|
v_TOVAGLIOLO(10),
|
||||||
|
v_TOVAGLIOLO(11),
|
||||||
|
v_TOVAGLIOLO(12),
|
||||||
|
|
||||||
|
v_AN_GELATO(1) || ', ' || v_AN_GELATO2(1),
|
||||||
|
v_AN_GELATO(2) || ', ' || v_AN_GELATO2(2),
|
||||||
|
v_AN_GELATO(3) || ', ' || v_AN_GELATO2(3),
|
||||||
|
v_AN_GELATO(4) || ', ' || v_AN_GELATO2(4),
|
||||||
|
v_AN_GELATO(5) || ', ' || v_AN_GELATO2(5),
|
||||||
|
v_AN_GELATO(6) || ', ' || v_AN_GELATO2(6),
|
||||||
|
v_AN_GELATO(7) || ', ' || v_AN_GELATO2(7),
|
||||||
|
v_AN_GELATO(8) || ', ' || v_AN_GELATO2(8),
|
||||||
|
v_AN_GELATO(9) || ', ' || v_AN_GELATO2(9),
|
||||||
|
v_AN_GELATO(10) || ', ' || v_AN_GELATO2(10),
|
||||||
|
v_AN_GELATO(11) || ', ' || v_AN_GELATO2(11),
|
||||||
|
v_AN_GELATO(12) || ', ' || v_AN_GELATO2(12),
|
||||||
|
|
||||||
|
v_AN_OPENBAR(1),
|
||||||
|
v_AN_OPENBAR(2),
|
||||||
|
v_AN_OPENBAR(3),
|
||||||
|
v_AN_OPENBAR(4),
|
||||||
|
v_AN_OPENBAR(5),
|
||||||
|
v_AN_OPENBAR(6),
|
||||||
|
v_AN_OPENBAR(7),
|
||||||
|
v_AN_OPENBAR(8),
|
||||||
|
v_AN_OPENBAR(9),
|
||||||
|
v_AN_OPENBAR(10),
|
||||||
|
v_AN_OPENBAR(11),
|
||||||
|
v_AN_OPENBAR(12),
|
||||||
|
|
||||||
|
v_AN_RUM(1),
|
||||||
|
v_AN_RUM(2),
|
||||||
|
v_AN_RUM(3),
|
||||||
|
v_AN_RUM(4),
|
||||||
|
v_AN_RUM(5),
|
||||||
|
v_AN_RUM(6),
|
||||||
|
v_AN_RUM(7),
|
||||||
|
v_AN_RUM(8),
|
||||||
|
v_AN_RUM(9),
|
||||||
|
v_AN_RUM(10),
|
||||||
|
v_AN_RUM(11),
|
||||||
|
v_AN_RUM(12),
|
||||||
|
|
||||||
|
c_evt.T1 ,
|
||||||
|
c_evt.T2 ,
|
||||||
|
c_evt.T3 ,
|
||||||
|
c_evt.T4 ,
|
||||||
|
c_evt.T5 ,
|
||||||
|
c_evt.T6 ,
|
||||||
|
c_evt.T7 ,
|
||||||
|
c_evt.T8 ,
|
||||||
|
c_evt.T9 ,
|
||||||
|
c_evt.T10 ,
|
||||||
|
c_evt.T11 ,
|
||||||
|
c_evt.T12 ,
|
||||||
|
|
||||||
|
c_evt.SM1 ,
|
||||||
|
c_evt.SM2 ,
|
||||||
|
c_evt.SM3 ,
|
||||||
|
c_evt.SM4 ,
|
||||||
|
c_evt.SM5 ,
|
||||||
|
c_evt.SM6 ,
|
||||||
|
c_evt.SM7 ,
|
||||||
|
c_evt.SM8 ,
|
||||||
|
c_evt.SM9 ,
|
||||||
|
c_evt.SM10 ,
|
||||||
|
c_evt.SM11 ,
|
||||||
|
c_evt.SM12
|
||||||
|
));
|
||||||
|
|
||||||
|
close c_evento;
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
|
||||||
|
END;```
|
||||||
245
docs/functions/F_REP_CUCINA.md
Normal file
245
docs/functions/F_REP_CUCINA.md
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
# F_REP_CUCINA
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "F_REP_CUCINA" (p_data_in IN varchar2,p_data_fi IN varchar2)
|
||||||
|
RETURN t_rep_cucina_tab PIPELINED AS
|
||||||
|
|
||||||
|
|
||||||
|
cursor c_evento is
|
||||||
|
select e.id,
|
||||||
|
e.data,
|
||||||
|
l.LOCATION,
|
||||||
|
e.cliente,
|
||||||
|
t.DESCRIZIONE,
|
||||||
|
e.ORA_CERIMONIA,
|
||||||
|
e.ORA_EVENTO,
|
||||||
|
e.ALLERGIE,
|
||||||
|
e.torta,
|
||||||
|
e.CONFETTATA,
|
||||||
|
e.STAMPA_MENU,
|
||||||
|
e.extra_info,
|
||||||
|
e.cliente_email,
|
||||||
|
e.cliente_tel,
|
||||||
|
e.referente_tel,
|
||||||
|
e.distanza_location,
|
||||||
|
e.buffet_iniziale,
|
||||||
|
e.buffet_finale,
|
||||||
|
e.primi,
|
||||||
|
e.secondi,
|
||||||
|
e.vini,
|
||||||
|
e.extra_costi
|
||||||
|
from eventi e
|
||||||
|
left join location l on e.id_location = l.id
|
||||||
|
join tb_tipi_evento t on e.cod_tipo = t.cod_tipo
|
||||||
|
where e.data between to_date(p_data_in,'YYYYMMDD') and to_date(p_data_fi,'YYYYMMDD')
|
||||||
|
and e.stato = 300 -- Considero soltanto le schede confermate
|
||||||
|
and e.disabled = 0
|
||||||
|
and e.deleted = 0;
|
||||||
|
|
||||||
|
|
||||||
|
v_data date;
|
||||||
|
v_LOCATION varchar2(4000);
|
||||||
|
v_cliente varchar2(4000);
|
||||||
|
v_DESCRIZIONE varchar2(4000);
|
||||||
|
v_ORA_CERIMONIA varchar2(4000);
|
||||||
|
v_ORA_EVENTO varchar2(4000);
|
||||||
|
v_TOT_ADULTI number;
|
||||||
|
v_TOT_KINDER number;
|
||||||
|
v_TOT_BABY number;
|
||||||
|
v_TOT_STAFF number;
|
||||||
|
v_TOT_INVITATI number;
|
||||||
|
v_ALLERGIE varchar2(4000);
|
||||||
|
v_TORTA varchar2(4000);
|
||||||
|
v_CONFETTATA varchar2(4000);
|
||||||
|
v_STAMPA_MENU varchar2(4000);
|
||||||
|
v_angoli varchar2(4000);
|
||||||
|
v_EXTRA_INFO varchar2(4000);
|
||||||
|
v_NOTE_ADULTI varchar2(4000);
|
||||||
|
v_NOTE_KINDER varchar2(4000);
|
||||||
|
v_NOTE_BABY varchar2(4000);
|
||||||
|
v_NOTE_STAFF varchar2(4000);
|
||||||
|
v_cliente_email varchar2(4000) := '';
|
||||||
|
v_cliente_tel varchar2(4000) := '';
|
||||||
|
v_referente_tel varchar2(4000) := '';
|
||||||
|
v_distanza_location varchar2(4000) := '';
|
||||||
|
v_buffet_iniziale varchar2(4000) := '';
|
||||||
|
v_buffet_finale varchar2(4000) := '';
|
||||||
|
v_primi varchar2(4000) := '';
|
||||||
|
v_secondi varchar2(4000) := '';
|
||||||
|
v_vini varchar2(4000) := '';
|
||||||
|
v_extra_costi varchar2(4000) := '';
|
||||||
|
v_event_id number;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
for c in c_evento
|
||||||
|
loop
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
v_TOT_ADULTI := 0;
|
||||||
|
v_TOT_KINDER := 0;
|
||||||
|
v_TOT_BABY := 0;
|
||||||
|
v_TOT_STAFF := 0;
|
||||||
|
v_TOT_INVITATI := 0;
|
||||||
|
v_angoli := 0;
|
||||||
|
v_NOTE_ADULTI := '';
|
||||||
|
v_NOTE_KINDER := '';
|
||||||
|
v_NOTE_BABY := '';
|
||||||
|
v_NOTE_STAFF := '';
|
||||||
|
|
||||||
|
v_cliente_email := c.cliente_email;
|
||||||
|
v_cliente_tel := c.cliente_tel;
|
||||||
|
v_referente_tel := c.referente_tel;
|
||||||
|
v_distanza_location := c.distanza_location;
|
||||||
|
v_buffet_iniziale := c.buffet_iniziale;
|
||||||
|
v_buffet_finale := c.buffet_finale;
|
||||||
|
v_primi := c.primi;
|
||||||
|
v_secondi := c.secondi;
|
||||||
|
v_vini := c.vini;
|
||||||
|
v_extra_costi := c.extra_costi;
|
||||||
|
v_event_id := c.id;
|
||||||
|
|
||||||
|
--ospiti
|
||||||
|
select nvl(sum(o.NUMERO),0)
|
||||||
|
into v_TOT_ADULTI
|
||||||
|
from eventi e
|
||||||
|
join eventi_det_ospiti o on e.id = o.id_evento
|
||||||
|
--join tb_tipi_ospiti tos on o.cod_tipo_ospite = tos.COD_TIPO
|
||||||
|
where e.id = c.id
|
||||||
|
and o.cod_tipo_ospite = 8; -- adulti
|
||||||
|
|
||||||
|
begin
|
||||||
|
select o.NOTE
|
||||||
|
into v_NOTE_ADULTI
|
||||||
|
from eventi e
|
||||||
|
join eventi_det_ospiti o on e.id = o.id_evento
|
||||||
|
where e.id = c.id
|
||||||
|
and o.cod_tipo_ospite = 8; -- adulti
|
||||||
|
|
||||||
|
exception when no_data_found then null;
|
||||||
|
end;
|
||||||
|
|
||||||
|
select nvl(sum(o.NUMERO),0)
|
||||||
|
into v_TOT_KINDER
|
||||||
|
from eventi e
|
||||||
|
join eventi_det_ospiti o on e.id = o.id_evento
|
||||||
|
--join tb_tipi_ospiti tos on o.cod_tipo_ospite = tos.COD_TIPO
|
||||||
|
where e.id = c.id
|
||||||
|
and o.cod_tipo_ospite = 5; --Kinder
|
||||||
|
|
||||||
|
begin
|
||||||
|
select o.NOTE
|
||||||
|
into v_NOTE_KINDER
|
||||||
|
from eventi e
|
||||||
|
join eventi_det_ospiti o on e.id = o.id_evento
|
||||||
|
where e.id = c.id
|
||||||
|
and o.cod_tipo_ospite = 5; --Kinder
|
||||||
|
|
||||||
|
exception when no_data_found then null;
|
||||||
|
end;
|
||||||
|
|
||||||
|
select nvl(sum(o.NUMERO),0)
|
||||||
|
into v_TOT_BABY
|
||||||
|
from eventi e
|
||||||
|
join eventi_det_ospiti o on e.id = o.id_evento
|
||||||
|
--join tb_tipi_ospiti tos on o.cod_tipo_ospite = tos.COD_TIPO
|
||||||
|
where e.id = c.id
|
||||||
|
and o.cod_tipo_ospite = 6; -- Baby
|
||||||
|
|
||||||
|
begin
|
||||||
|
select o.NOTE
|
||||||
|
into v_NOTE_BABY
|
||||||
|
from eventi e
|
||||||
|
join eventi_det_ospiti o on e.id = o.id_evento
|
||||||
|
where e.id = c.id
|
||||||
|
and o.cod_tipo_ospite = 6; -- Baby
|
||||||
|
|
||||||
|
exception when no_data_found then null;
|
||||||
|
end;
|
||||||
|
|
||||||
|
select nvl(sum(o.NUMERO),0)
|
||||||
|
into v_TOT_STAFF
|
||||||
|
from eventi e
|
||||||
|
join eventi_det_ospiti o on e.id = o.id_evento
|
||||||
|
--join tb_tipi_ospiti tos on o.cod_tipo_ospite = tos.COD_TIPO
|
||||||
|
where e.id = c.id
|
||||||
|
and o.cod_tipo_ospite = 7; -- Staff
|
||||||
|
|
||||||
|
begin
|
||||||
|
select o.NOTE
|
||||||
|
into v_NOTE_STAFF
|
||||||
|
from eventi e
|
||||||
|
join eventi_det_ospiti o on e.id = o.id_evento
|
||||||
|
where e.id = c.id
|
||||||
|
and o.cod_tipo_ospite = 7; -- Staff
|
||||||
|
|
||||||
|
exception when no_data_found then null;
|
||||||
|
end;
|
||||||
|
|
||||||
|
select nvl(e.tot_ospiti,0)
|
||||||
|
into v_TOT_INVITATI
|
||||||
|
from eventi e
|
||||||
|
where e.id = c.id;
|
||||||
|
|
||||||
|
--angoli "speciali"
|
||||||
|
v_angoli := '';
|
||||||
|
for a in ( select trim(substr(a.descrizione || ' - ' || p.note,1,1000)) descrizione from eventi e
|
||||||
|
join eventi_det_prel p on e.id=p.id_evento
|
||||||
|
join articoli a on p.cod_articolo=a.cod_articolo
|
||||||
|
where a.flg_cucina = 1
|
||||||
|
and e.id = c.id
|
||||||
|
)
|
||||||
|
loop
|
||||||
|
v_angoli := a.descrizione || ', ' || v_angoli ;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
PIPE ROW(t_rep_cucina_row( c.data,c.location,c.cliente,
|
||||||
|
c.DESCRIZIONE,
|
||||||
|
to_char(c.ORA_CERIMONIA,'HH24:MI'),
|
||||||
|
to_char(c.ORA_EVENTO,'HH24:MI'),
|
||||||
|
v_TOT_ADULTI ,
|
||||||
|
v_TOT_KINDER ,
|
||||||
|
v_TOT_BABY ,
|
||||||
|
v_TOT_STAFF ,
|
||||||
|
v_TOT_INVITATI ,
|
||||||
|
c.ALLERGIE ,
|
||||||
|
c.TORTA ,
|
||||||
|
c.CONFETTATA ,
|
||||||
|
c.STAMPA_MENU ,
|
||||||
|
v_angoli,
|
||||||
|
c.extra_info ,
|
||||||
|
|
||||||
|
v_NOTE_ADULTI ,
|
||||||
|
v_NOTE_KINDER ,
|
||||||
|
v_NOTE_BABY ,
|
||||||
|
v_NOTE_STAFF ,
|
||||||
|
v_cliente_email ,
|
||||||
|
v_cliente_tel ,
|
||||||
|
v_referente_tel ,
|
||||||
|
v_distanza_location ,
|
||||||
|
v_buffet_iniziale ,
|
||||||
|
v_buffet_finale ,
|
||||||
|
v_primi ,
|
||||||
|
v_secondi ,
|
||||||
|
v_vini ,
|
||||||
|
v_extra_costi ,
|
||||||
|
v_event_id
|
||||||
|
));
|
||||||
|
|
||||||
|
--exception when others
|
||||||
|
-- then null;
|
||||||
|
|
||||||
|
exception when others
|
||||||
|
then
|
||||||
|
RAISE_APPLICATION_ERROR(-20000, 'Errore: ' || SQLCODE || ' - ' || SUBSTR(SQLERRM, 1 , 64));
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
|
||||||
|
END;```
|
||||||
20
docs/functions/F_USER_IN_ROLE.md
Normal file
20
docs/functions/F_USER_IN_ROLE.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# F_USER_IN_ROLE
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_USER_IN_ROLE
|
||||||
|
(
|
||||||
|
P_USER IN VARCHAR2
|
||||||
|
, P_ROLE IN VARCHAR2
|
||||||
|
) RETURN NUMBER AS
|
||||||
|
v_has_role number := 0;
|
||||||
|
BEGIN
|
||||||
|
select count(column_value)
|
||||||
|
into v_has_role
|
||||||
|
from tb_config, table(split(strvalue, ':'))
|
||||||
|
where upper(name) = upper(P_ROLE)
|
||||||
|
and upper(column_value) = upper(P_USER);
|
||||||
|
|
||||||
|
return case when v_has_role > 0 then 1 else 0 end;
|
||||||
|
END F_USER_IN_ROLE;```
|
||||||
15
docs/functions/F_USER_IN_ROLE_STR.md
Normal file
15
docs/functions/F_USER_IN_ROLE_STR.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# F_USER_IN_ROLE_STR
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_USER_IN_ROLE_STR
|
||||||
|
(
|
||||||
|
P_USER IN VARCHAR2
|
||||||
|
, P_ROLE IN VARCHAR2
|
||||||
|
) RETURN VARCHAR2 AS
|
||||||
|
v_has_role number := 0;
|
||||||
|
BEGIN
|
||||||
|
return case when F_USER_IN_ROLE(P_USER, P_ROLE) > 0 then 'true' else 'false' end;
|
||||||
|
END F_USER_IN_ROLE_STR;
|
||||||
|
```
|
||||||
19
docs/functions/GET_PARAM_VALUE.md
Normal file
19
docs/functions/GET_PARAM_VALUE.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# GET_PARAM_VALUE
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
function get_param_value(p_name varchar2)
|
||||||
|
return varchar2 as
|
||||||
|
v_result varchar2(255);
|
||||||
|
begin
|
||||||
|
select strvalue
|
||||||
|
into v_result
|
||||||
|
from tb_config
|
||||||
|
where upper(name) = upper(p_name);
|
||||||
|
|
||||||
|
return v_result;
|
||||||
|
exception when others then
|
||||||
|
return null;
|
||||||
|
end;
|
||||||
|
```
|
||||||
36
docs/functions/MY_INSTR.md
Normal file
36
docs/functions/MY_INSTR.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# MY_INSTR
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
function my_instr( p_value varchar2,
|
||||||
|
p_delim varchar2 )
|
||||||
|
return number
|
||||||
|
as
|
||||||
|
|
||||||
|
i number;
|
||||||
|
|
||||||
|
l_length number;
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
if p_value is null then
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
i := 1;
|
||||||
|
|
||||||
|
l_length := length(p_value);
|
||||||
|
|
||||||
|
for i in 1..l_length
|
||||||
|
loop
|
||||||
|
if substr(p_value, i, length(p_delim)) = p_delim then
|
||||||
|
return i;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
end;
|
||||||
|
```
|
||||||
127
docs/functions/README.md
Normal file
127
docs/functions/README.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# Funzioni Database
|
||||||
|
|
||||||
|
Questa cartella contiene la documentazione di tutte le 23 funzioni del database.
|
||||||
|
|
||||||
|
## Funzioni Calcolo Quantità e Disponibilità
|
||||||
|
|
||||||
|
| Funzione | Ritorno | Descrizione |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| [F_GET_QTA_IMPEGNATA](F_GET_QTA_IMPEGNATA.md) | NUMBER | Quantità impegnata di un articolo in un range di date |
|
||||||
|
| [F_GET_TOT_OSPITI](F_GET_TOT_OSPITI.md) | NUMBER | Totale ospiti per evento (opzionale per tipo) |
|
||||||
|
| [F_GET_OSPITI](F_GET_OSPITI.md) | TABLE | Dettaglio ospiti per evento (funzione pipelined) |
|
||||||
|
| [F_LIST_PRELIEVO_ADD_ARTICOLO](F_LIST_PRELIEVO_ADD_ARTICOLO.md) | VARCHAR2 (JSON) | Aggiunge articolo alla lista prelievo con validazioni |
|
||||||
|
|
||||||
|
## Funzioni Calcolo Costi
|
||||||
|
|
||||||
|
| Funzione | Ritorno | Descrizione |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| [F_GET_COSTO_ARTICOLO](F_GET_COSTO_ARTICOLO.md) | NUMBER | Costo unitario articolo a una data specifica |
|
||||||
|
|
||||||
|
## Funzioni Validazione
|
||||||
|
|
||||||
|
| Funzione | Ritorno | Descrizione |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| [F_EVENTO_SCADUTO](F_EVENTO_SCADUTO.md) | NUMBER (0/1) | Verifica se preventivo è scaduto |
|
||||||
|
| [F_MAX_NUMERO_EVENTI_RAGGIUNTO](F_MAX_NUMERO_EVENTI_RAGGIUNTO.md) | NUMBER (-1/0/1) | Verifica limite eventi giornaliero |
|
||||||
|
| [F_MAX_NUM_EVENTI_CONFERMATI](F_MAX_NUM_EVENTI_CONFERMATI.md) | NUMBER (0/1) | Verifica limite eventi confermati |
|
||||||
|
| [F_CI_SONO_EVENTI_CONFERMATI](F_CI_SONO_EVENTI_CONFERMATI.md) | NUMBER (0/1) | Check esistenza eventi confermati in data/location |
|
||||||
|
|
||||||
|
## Funzioni Report
|
||||||
|
|
||||||
|
| Funzione | Ritorno | Descrizione |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| [F_REP_ALLESTIMENTI](F_REP_ALLESTIMENTI.md) | TABLE | Dati per report allestimenti (pipelined) |
|
||||||
|
| [F_REP_CUCINA](F_REP_CUCINA.md) | TABLE | Dati per report cucina (pipelined) |
|
||||||
|
| [F_GET_ANGOLO_ALLESTIMENTO](F_GET_ANGOLO_ALLESTIMENTO.md) | VARCHAR2 | Descrizione angolo allestimento |
|
||||||
|
| [F_GET_ANGOLO_ALLESTIMENTO_OB](F_GET_ANGOLO_ALLESTIMENTO_OB.md) | VARCHAR2 | Descrizione angolo open bar |
|
||||||
|
| [F_GET_TOVAGLIATO_ALLESTIMENTO](F_GET_TOVAGLIATO_ALLESTIMENTO.md) | VARCHAR2 | Descrizione tovagliato |
|
||||||
|
|
||||||
|
## Funzioni Autorizzazione
|
||||||
|
|
||||||
|
| Funzione | Ritorno | Descrizione |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| [F_USER_IN_ROLE](F_USER_IN_ROLE.md) | NUMBER (0/1) | Verifica appartenenza utente a ruolo |
|
||||||
|
| [F_USER_IN_ROLE_STR](F_USER_IN_ROLE_STR.md) | VARCHAR2 | Verifica ruolo (ritorna stringa) |
|
||||||
|
|
||||||
|
## Funzioni Utility
|
||||||
|
|
||||||
|
| Funzione | Ritorno | Descrizione |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| [F_DAY_TO_NAME](F_DAY_TO_NAME.md) | VARCHAR2 | Converte numero giorno in nome italiano |
|
||||||
|
| [STRING_TO_TABLE_ENUM](STRING_TO_TABLE_ENUM.md) | TABLE | Converte stringa delimitata in tabella |
|
||||||
|
| [GET_PARAM_VALUE](GET_PARAM_VALUE.md) | VARCHAR2 | Recupera valore parametro da TB_CONFIG |
|
||||||
|
| [SPLIT](SPLIT.md) | TABLE | Split stringa in elementi |
|
||||||
|
| [MY_INSTR](MY_INSTR.md) | NUMBER | Funzione INSTR personalizzata |
|
||||||
|
| [CLOB2BLOB](CLOB2BLOB.md) | BLOB | Conversione CLOB → BLOB |
|
||||||
|
| [EXTDATE_GET_ITA](EXTDATE_GET_ITA.md) | VARCHAR2 | Formatta data in italiano esteso |
|
||||||
|
|
||||||
|
## Dettaglio Funzioni Critiche
|
||||||
|
|
||||||
|
### F_GET_QTA_IMPEGNATA
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_GET_QTA_IMPEGNATA(
|
||||||
|
p_codart VARCHAR2,
|
||||||
|
p_data_from DATE,
|
||||||
|
p_data_to DATE DEFAULT NULL
|
||||||
|
) RETURN NUMBER
|
||||||
|
```
|
||||||
|
|
||||||
|
**Logica:**
|
||||||
|
- Interroga `V_IMPEGNI_ARTICOLI`
|
||||||
|
- Somma quantità impegnate nel range di date
|
||||||
|
- Se `p_data_to` è NULL, usa `p_data_from`
|
||||||
|
|
||||||
|
### F_EVENT0_SCADUTO
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_EVENTO_SCADUTO(
|
||||||
|
DATA_SCADENZA IN DATE,
|
||||||
|
STATO_EVENTO IN NUMBER,
|
||||||
|
STATO_FROM IN NUMBER,
|
||||||
|
STATO_TO IN NUMBER
|
||||||
|
) RETURN NUMBER
|
||||||
|
```
|
||||||
|
|
||||||
|
**Logica:**
|
||||||
|
- Ritorna 1 se `TRUNC(DATA_SCADENZA) <= TRUNC(SYSDATE)`
|
||||||
|
AND `STATO_EVENTO BETWEEN STATO_FROM AND STATO_TO`
|
||||||
|
- Altrimenti ritorna 0
|
||||||
|
|
||||||
|
### F_LIST_PRELIEVO_ADD_ARTICOLO
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_LIST_PRELIEVO_ADD_ARTICOLO(
|
||||||
|
p_event_id NUMBER,
|
||||||
|
p_articolo_add VARCHAR2,
|
||||||
|
p_qta_aperitivo NUMBER := 0,
|
||||||
|
p_qta_seduto NUMBER := 0,
|
||||||
|
p_qta_dolci NUMBER := 0
|
||||||
|
) RETURN VARCHAR2
|
||||||
|
```
|
||||||
|
|
||||||
|
**Logica:**
|
||||||
|
1. Verifica esistenza evento
|
||||||
|
2. Verifica esistenza articolo
|
||||||
|
3. Recupera giacenza articolo
|
||||||
|
4. Controlla impegni in date vicine (±2 giorni)
|
||||||
|
5. Inserisce record in `EVENTI_DET_PREL`
|
||||||
|
6. Chiama `EVENTI_AGGIORNA_QTA_LISTA`
|
||||||
|
7. Ritorna JSON con esito:
|
||||||
|
- `{"type":"success","message":"..."}`
|
||||||
|
- `{"type":"warning","message":"..."}`
|
||||||
|
- `{"type":"error","code":"...","stack":"...","message":"..."}`
|
||||||
|
|
||||||
|
### F_GET_COSTO_ARTICOLO
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION F_GET_COSTO_ARTICOLO(
|
||||||
|
p_cod_articolo VARCHAR2,
|
||||||
|
p_date DATE
|
||||||
|
) RETURN NUMBER
|
||||||
|
```
|
||||||
|
|
||||||
|
**Logica:**
|
||||||
|
1. Cerca costo in `COSTI_ARTICOLI` alla data esatta
|
||||||
|
2. Se non trovato, prende ultimo costo disponibile
|
||||||
|
3. Se non trovato nulla, ritorna 0
|
||||||
46
docs/functions/SPLIT.md
Normal file
46
docs/functions/SPLIT.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# SPLIT
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "SPLIT"
|
||||||
|
(
|
||||||
|
p_list varchar2,
|
||||||
|
p_del varchar2 := ','
|
||||||
|
) return string_list
|
||||||
|
is
|
||||||
|
l_idx integer;
|
||||||
|
l_list varchar2(32767) := p_list;
|
||||||
|
|
||||||
|
l_value varchar2(32767);
|
||||||
|
|
||||||
|
l_retval string_list;
|
||||||
|
begin
|
||||||
|
|
||||||
|
l_retval := string_list();
|
||||||
|
|
||||||
|
loop
|
||||||
|
|
||||||
|
--l_idx := instr(l_list,p_del);
|
||||||
|
l_idx := my_instr(l_list,p_del);
|
||||||
|
|
||||||
|
l_retval.extend;
|
||||||
|
|
||||||
|
if l_idx > 0 then
|
||||||
|
--pipe row(substr(l_list,1,l_idx-1));
|
||||||
|
--l_list := substr(l_list,l_idx+length(p_del));
|
||||||
|
l_retval(l_retval.count) := substr(l_list, 1, l_idx - 1);
|
||||||
|
l_list := substr(l_list,l_idx+length(p_del));
|
||||||
|
else
|
||||||
|
--pipe row(l_list);
|
||||||
|
--exit;
|
||||||
|
l_retval(l_retval.count) := l_list;
|
||||||
|
exit;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return l_retval;
|
||||||
|
|
||||||
|
end split;
|
||||||
|
```
|
||||||
26
docs/functions/STRING_TO_TABLE_ENUM.md
Normal file
26
docs/functions/STRING_TO_TABLE_ENUM.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# STRING_TO_TABLE_ENUM
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
FUNCTION "STRING_TO_TABLE_ENUM" (p_string VARCHAR2, v_level in number default 0, p_separator varchar2 default ':') RETURN ENUM_TABLE_TYPE pipelined IS
|
||||||
|
conta number := 0;
|
||||||
|
BEGIN
|
||||||
|
FOR c IN ( select ROW_NUMBER() OVER (ORDER BY ROWNUM) id, result
|
||||||
|
from (
|
||||||
|
with test as (
|
||||||
|
select p_string col
|
||||||
|
from dual
|
||||||
|
)
|
||||||
|
select nvl(regexp_substr(col, '[^' || p_separator || ']+', 1, level), '') result
|
||||||
|
from test
|
||||||
|
connect by level <= length(regexp_replace(col, '[^' || p_separator || ']+')) + 1)
|
||||||
|
)
|
||||||
|
LOOP
|
||||||
|
conta := conta + 1;
|
||||||
|
if v_level = 0 or ( v_level = conta ) then
|
||||||
|
pipe row(enum_table_object(c.id,c.result));
|
||||||
|
end if;
|
||||||
|
END LOOP;
|
||||||
|
RETURN;
|
||||||
|
END STRING_TO_TABLE_ENUM;```
|
||||||
422
docs/index.md
Normal file
422
docs/index.md
Normal file
@@ -0,0 +1,422 @@
|
|||||||
|
# Apollinare Catering - Documentazione Completa
|
||||||
|
|
||||||
|
Questa documentazione contiene l'estrazione completa di tutti gli oggetti del database Oracle e dell'applicazione APEX di Apollinare Catering & Banqueting.
|
||||||
|
|
||||||
|
## [Application Overview](APPLICATION_OVERVIEW.md)
|
||||||
|
|
||||||
|
**Apollinare Catering & Banqueting Management Software** è un gestionale completo per aziende di catering che gestisce l'intero ciclo di vita di un evento: dalla richiesta del cliente, al preventivo, alla conferma, fino all'esecuzione.
|
||||||
|
|
||||||
|
### Funzionalità Principali
|
||||||
|
|
||||||
|
| Area | Descrizione |
|
||||||
|
| --------------------- | ------------------------------------------- |
|
||||||
|
| **Gestione Eventi** | Creazione, workflow stati, versioning |
|
||||||
|
| **Gestione Ospiti** | Tipologie ospiti, conteggi, coefficienti |
|
||||||
|
| **Lista Prelievo** | Calcolo automatico quantità materiale |
|
||||||
|
| **Risorse/Staff** | Pianificazione personale per evento |
|
||||||
|
| **Acconti/Pagamenti** | Sistema caparre 30%-50%-20%, solleciti |
|
||||||
|
| **Calendario** | Vista eventi, limiti giornalieri, conflitti |
|
||||||
|
| **Reporting** | Schede evento, preventivi, report cucina |
|
||||||
|
|
||||||
|
### Proposta SaaS: CaterPro
|
||||||
|
|
||||||
|
La documentazione include una proposta per trasformare Apollinare in **CaterPro**, una piattaforma SaaS multi-tenant:
|
||||||
|
|
||||||
|
- **Target**: Piccole, medie e grandi aziende di catering
|
||||||
|
- **Stack**: .NET 8 + React TypeScript + PostgreSQL/Oracle
|
||||||
|
- **Pricing**: Da €49/mese (Basic) a €399/mese (Enterprise)
|
||||||
|
- **Roadmap**: 10-14 mesi per feature parity + SaaS
|
||||||
|
|
||||||
|
Leggi la [documentazione completa](APPLICATION_OVERVIEW.md) per dettagli su architettura, funzionalità e roadmap.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Struttura della Documentazione
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/
|
||||||
|
├── apex/ # Applicazione APEX
|
||||||
|
│ ├── README.md # Overview applicazione
|
||||||
|
│ ├── pages/ # 56 pagine
|
||||||
|
│ ├── processes/ # 98 processi
|
||||||
|
│ ├── lovs/ # 12 List of Values
|
||||||
|
│ ├── javascript/ # Librerie JavaScript
|
||||||
|
│ ├── authorization/ # 5 schemi autorizzazione
|
||||||
|
│ ├── dynamic-actions/ # Azioni dinamiche
|
||||||
|
│ ├── items/ # Items condivisi
|
||||||
|
│ ├── regions/ # Regioni condivise
|
||||||
|
│ └── navigation/ # Navigazione
|
||||||
|
├── tables/ # 32 tabelle
|
||||||
|
├── views/ # 26 viste
|
||||||
|
├── procedures/ # 11 stored procedures
|
||||||
|
├── functions/ # 23 funzioni
|
||||||
|
├── packages/ # 17 packages
|
||||||
|
├── triggers/ # 19 triggers
|
||||||
|
├── sequences/ # 22 sequences
|
||||||
|
└── types/ # 10 tipi custom
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## APEX Application Documentation
|
||||||
|
|
||||||
|
### [APEX Application Overview](apex/README.md)
|
||||||
|
|
||||||
|
**Application:** APCB Project (ID: 112)
|
||||||
|
**APEX Version:** 21.1.0
|
||||||
|
**Schema:** APOLLINARECATERINGPROD
|
||||||
|
|
||||||
|
| Component | Count |
|
||||||
|
| --------------- | ----- |
|
||||||
|
| Pages | 56 |
|
||||||
|
| Items | 302 |
|
||||||
|
| Processes | 98 |
|
||||||
|
| Regions | 151 |
|
||||||
|
| Buttons | 119 |
|
||||||
|
| Dynamic Actions | 62 |
|
||||||
|
| LOVs | 12 |
|
||||||
|
|
||||||
|
### Key APEX Documentation
|
||||||
|
|
||||||
|
- [APEX README](apex/README.md) - Application overview and navigation
|
||||||
|
- [Processes Documentation](apex/processes/README.md) - All 98 processes with PL/SQL code
|
||||||
|
- [LOVs Documentation](apex/lovs/README.md) - 12 List of Values definitions
|
||||||
|
- [JavaScript Libraries](apex/javascript/README.md) - Custom ajaxUtils.js and iframeObj.js
|
||||||
|
- [Authorization Schemes](apex/authorization/README.md) - 5 security schemes
|
||||||
|
|
||||||
|
### Critical APEX Pages
|
||||||
|
|
||||||
|
| Page | Name | Description |
|
||||||
|
| ------ | ---------------- | ------------------------------------------------- |
|
||||||
|
| 1 | Home | Dashboard principale |
|
||||||
|
| **22** | **Nuovo Evento** | **Pagina più complessa (108 items, 32 processi)** |
|
||||||
|
| 9 | Liste | Lista eventi |
|
||||||
|
| 12 | Calendario | Calendario eventi |
|
||||||
|
| 35 | Schede | Schede evento |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Indice per Categoria
|
||||||
|
|
||||||
|
### [Tabelle](tables/README.md) (32)
|
||||||
|
|
||||||
|
Tabelle principali del dominio business:
|
||||||
|
|
||||||
|
- [EVENTI](tables/EVENTI.md) - Tabella principale eventi
|
||||||
|
- [EVENTI_DET_PREL](tables/EVENTI_DET_PREL.md) - Liste prelievo
|
||||||
|
- [EVENTI_DET_OSPITI](tables/EVENTI_DET_OSPITI.md) - Dettaglio ospiti
|
||||||
|
- [EVENTI_DET_RIS](tables/EVENTI_DET_RIS.md) - Risorse assegnate
|
||||||
|
- [EVENTI_DET_DEGUST](tables/EVENTI_DET_DEGUST.md) - Degustazioni
|
||||||
|
- [EVENTI_ACCONTI](tables/EVENTI_ACCONTI.md) - Gestione acconti/pagamenti
|
||||||
|
- [EVENTI_ALTRICOSTI](tables/EVENTI_ALTRICOSTI.md) - Altri costi
|
||||||
|
- [EVENTI_ALLEG](tables/EVENTI_ALLEG.md) - Allegati
|
||||||
|
- [ARTICOLI](tables/ARTICOLI.md) - Catalogo articoli
|
||||||
|
- [COSTI_ARTICOLI](tables/COSTI_ARTICOLI.md) - Storico costi
|
||||||
|
- [CLIENTI](tables/CLIENTI.md) - Anagrafica clienti
|
||||||
|
- [LOCATION](tables/LOCATION.md) - Location eventi
|
||||||
|
- [RISORSE](tables/RISORSE.md) - Personale
|
||||||
|
|
||||||
|
Tabelle di lookup:
|
||||||
|
|
||||||
|
- [TB_TIPI_MAT](tables/TB_TIPI_MAT.md) - Tipi materiale
|
||||||
|
- [TB_CODICI_CATEG](tables/TB_CODICI_CATEG.md) - Categorie
|
||||||
|
- [TB_TIPI_EVENTO](tables/TB_TIPI_EVENTO.md) - Tipi evento
|
||||||
|
- [TB_TIPI_OSPITI](tables/TB_TIPI_OSPITI.md) - Tipi ospiti
|
||||||
|
- [TB_TIPI_RISORSA](tables/TB_TIPI_RISORSA.md) - Tipi risorsa
|
||||||
|
- [TB_TIPI_PASTO](tables/TB_TIPI_PASTO.md) - Tipi pasto
|
||||||
|
- [TB_CALENDAR_LOCKS](tables/TB_CALENDAR_LOCKS.md) - Limiti calendario
|
||||||
|
- [TB_CONFIG](tables/TB_CONFIG.md) - Configurazioni
|
||||||
|
|
||||||
|
Tabelle di sistema:
|
||||||
|
|
||||||
|
- [USERS_READONLY](tables/USERS_READONLY.md) - Permessi utenti
|
||||||
|
- [XLIB_LOGS](tables/XLIB_LOGS.md) - Log applicazione
|
||||||
|
- [XLIB_COMPONENTS](tables/XLIB_COMPONENTS.md) - Componenti
|
||||||
|
- [XLIB_JASPERREPORTS_CONF](tables/XLIB_JASPERREPORTS_CONF.md) - Config report
|
||||||
|
- [XLIB_JASPERREPORTS_DEMOS](tables/XLIB_JASPERREPORTS_DEMOS.md) - Demo report
|
||||||
|
|
||||||
|
### [Viste](views/README.md) (26)
|
||||||
|
|
||||||
|
Viste per calcolo costi:
|
||||||
|
|
||||||
|
- [GET_COSTO_ART_BY_EVT](views/GET_COSTO_ART_BY_EVT.md) - Costo articoli per evento
|
||||||
|
- [GET_COSTO_ART_EVT](views/GET_COSTO_ART_EVT.md) - Costo articoli aggregato
|
||||||
|
- [GET_COSTO_CATEG_EVT](views/GET_COSTO_CATEG_EVT.md) - Costo per categoria
|
||||||
|
- [GET_COSTO_DEGUS_EVT](views/GET_COSTO_DEGUS_EVT.md) - Costo degustazioni
|
||||||
|
- [GET_COSTO_OSPITI_EVT](views/GET_COSTO_OSPITI_EVT.md) - Costo ospiti
|
||||||
|
- [GET_COSTO_RIS_EVT](views/GET_COSTO_RIS_EVT.md) - Costo risorse
|
||||||
|
- [GET_COSTO_TIPI_EVT](views/GET_COSTO_TIPI_EVT.md) - Costo per tipo
|
||||||
|
- [GET_ULTIMI_COSTI](views/GET_ULTIMI_COSTI.md) - Ultimi costi articoli
|
||||||
|
|
||||||
|
Viste per eventi:
|
||||||
|
|
||||||
|
- [GET_EVT_DATA](views/GET_EVT_DATA.md) - Dati evento completi
|
||||||
|
- [GET_EVT_DATA_PRINT](views/GET_EVT_DATA_PRINT.md) - Dati per stampa
|
||||||
|
- [GET_PREL_ART_TOT](views/GET_PREL_ART_TOT.md) - Totali prelievo
|
||||||
|
- [GET_PREL_BY_EVT](views/GET_PREL_BY_EVT.md) - Prelievi per evento
|
||||||
|
|
||||||
|
Viste per calendario e stato:
|
||||||
|
|
||||||
|
- [VW_CALENDARIO_EVENTI](views/VW_CALENDARIO_EVENTI.md) - Vista calendario
|
||||||
|
- [VW_EVENT_COLOR](views/VW_EVENT_COLOR.md) - Colori stati
|
||||||
|
- [VW_EVENTI_STATUSES](views/VW_EVENTI_STATUSES.md) - Stati eventi
|
||||||
|
|
||||||
|
Viste per giacenze:
|
||||||
|
|
||||||
|
- [V_IMPEGNI_ARTICOLI](views/V_IMPEGNI_ARTICOLI.md) - Impegni articoli
|
||||||
|
- [V_IMPEGNI_ARTICOLI_LOC](views/V_IMPEGNI_ARTICOLI_LOC.md) - Impegni per location
|
||||||
|
|
||||||
|
Viste per report:
|
||||||
|
|
||||||
|
- [V_REP_ALLESTIMENTI](views/V_REP_ALLESTIMENTI.md) - Report allestimenti
|
||||||
|
- [VW_REP_DEGUSTAZIONI](views/VW_REP_DEGUSTAZIONI.md) - Report degustazioni
|
||||||
|
- [V_GRIGLIA](views/V_GRIGLIA.md) - Vista griglia
|
||||||
|
- [GET_REPORT_CONSUNTIVO_PER_DATA](views/GET_REPORT_CONSUNTIVO_PER_DATA.md) - Consuntivo
|
||||||
|
|
||||||
|
Viste per utenti/permessi:
|
||||||
|
|
||||||
|
- [GET_CONSUNTIVI_USERS](views/GET_CONSUNTIVI_USERS.md) - Utenti consuntivi
|
||||||
|
- [GET_GESTORI_USERS](views/GET_GESTORI_USERS.md) - Utenti gestori
|
||||||
|
- [GET_USERS_LIST](views/GET_USERS_LIST.md) - Lista utenti
|
||||||
|
|
||||||
|
Viste per pagamenti:
|
||||||
|
|
||||||
|
- [GET_EVENTI_DA_PAGARE_ENTRO_65GG](views/GET_EVENTI_DA_PAGARE_ENTRO_65GG.md) - Eventi da sollecitare
|
||||||
|
|
||||||
|
### [Stored Procedures](procedures/README.md) (11)
|
||||||
|
|
||||||
|
Business logic principale:
|
||||||
|
|
||||||
|
- [EVENTI_AGGIORNA_QTA_LISTA](procedures/EVENTI_AGGIORNA_QTA_LISTA.md) - Ricalcolo quantità lista prelievo
|
||||||
|
- [EVENTI_AGGIORNA_TOT_OSPITI](procedures/EVENTI_AGGIORNA_TOT_OSPITI.md) - Aggiorna totale ospiti
|
||||||
|
- [EVENTI_COPIA](procedures/EVENTI_COPIA.md) - Duplicazione evento
|
||||||
|
- [EVENTI_RICALCOLA_ACCONTI](procedures/EVENTI_RICALCOLA_ACCONTI.md) - Ricalcolo acconti
|
||||||
|
- [EVENTO_ELIMINA_PRELIEVI](procedures/EVENTO_ELIMINA_PRELIEVI.md) - Elimina prelievi
|
||||||
|
- [LISTE_COPIA](procedures/LISTE_COPIA.md) - Copia liste tra eventi
|
||||||
|
- [P_CANCEL_SAME_LOCATION_EVENTS](procedures/P_CANCEL_SAME_LOCATION_EVENTS.md) - Annulla eventi stessa location
|
||||||
|
|
||||||
|
Utility:
|
||||||
|
|
||||||
|
- [ROWSORT_TIPI](procedures/ROWSORT_TIPI.md) - Ordinamento tipi
|
||||||
|
- [HTPPRN](procedures/HTPPRN.md) - Stampa HTTP
|
||||||
|
- [SEND_DATA_TO_DROPBOX](procedures/SEND_DATA_TO_DROPBOX.md) - Export Dropbox
|
||||||
|
- [XLOG](procedures/XLOG.md) - Logging
|
||||||
|
|
||||||
|
### [Funzioni](functions/README.md) (23)
|
||||||
|
|
||||||
|
Calcolo quantità e disponibilità:
|
||||||
|
|
||||||
|
- [F_GET_QTA_IMPEGNATA](functions/F_GET_QTA_IMPEGNATA.md) - Quantità impegnata
|
||||||
|
- [F_GET_TOT_OSPITI](functions/F_GET_TOT_OSPITI.md) - Totale ospiti
|
||||||
|
- [F_GET_OSPITI](functions/F_GET_OSPITI.md) - Dettaglio ospiti (pipelined)
|
||||||
|
- [F_LIST_PRELIEVO_ADD_ARTICOLO](functions/F_LIST_PRELIEVO_ADD_ARTICOLO.md) - Aggiunta articolo
|
||||||
|
|
||||||
|
Calcolo costi:
|
||||||
|
|
||||||
|
- [F_GET_COSTO_ARTICOLO](functions/F_GET_COSTO_ARTICOLO.md) - Costo articolo a data
|
||||||
|
|
||||||
|
Validazioni:
|
||||||
|
|
||||||
|
- [F_EVENTO_SCADUTO](functions/F_EVENTO_SCADUTO.md) - Verifica scadenza
|
||||||
|
- [F_MAX_NUMERO_EVENTI_RAGGIUNTO](functions/F_MAX_NUMERO_EVENTI_RAGGIUNTO.md) - Limite eventi
|
||||||
|
- [F_MAX_NUM_EVENTI_CONFERMATI](functions/F_MAX_NUM_EVENTI_CONFERMATI.md) - Limite confermati
|
||||||
|
- [F_CI_SONO_EVENTI_CONFERMATI](functions/F_CI_SONO_EVENTI_CONFERMATI.md) - Check confermati
|
||||||
|
|
||||||
|
Report:
|
||||||
|
|
||||||
|
- [F_REP_ALLESTIMENTI](functions/F_REP_ALLESTIMENTI.md) - Report allestimenti
|
||||||
|
- [F_REP_CUCINA](functions/F_REP_CUCINA.md) - Report cucina
|
||||||
|
- [F_GET_ANGOLO_ALLESTIMENTO](functions/F_GET_ANGOLO_ALLESTIMENTO.md) - Angolo allestimento
|
||||||
|
- [F_GET_ANGOLO_ALLESTIMENTO_OB](functions/F_GET_ANGOLO_ALLESTIMENTO_OB.md) - Angolo open bar
|
||||||
|
- [F_GET_TOVAGLIATO_ALLESTIMENTO](functions/F_GET_TOVAGLIATO_ALLESTIMENTO.md) - Tovagliato
|
||||||
|
|
||||||
|
Autorizzazioni:
|
||||||
|
|
||||||
|
- [F_USER_IN_ROLE](functions/F_USER_IN_ROLE.md) - Verifica ruolo utente
|
||||||
|
- [F_USER_IN_ROLE_STR](functions/F_USER_IN_ROLE_STR.md) - Ruolo utente (stringa)
|
||||||
|
|
||||||
|
Utility:
|
||||||
|
|
||||||
|
- [F_DAY_TO_NAME](functions/F_DAY_TO_NAME.md) - Giorno in italiano
|
||||||
|
- [STRING_TO_TABLE_ENUM](functions/STRING_TO_TABLE_ENUM.md) - Stringa a tabella
|
||||||
|
- [GET_PARAM_VALUE](functions/GET_PARAM_VALUE.md) - Valore parametro
|
||||||
|
- [SPLIT](functions/SPLIT.md) - Split stringa
|
||||||
|
- [MY_INSTR](functions/MY_INSTR.md) - Instr custom
|
||||||
|
- [CLOB2BLOB](functions/CLOB2BLOB.md) - Conversione CLOB
|
||||||
|
- [EXTDATE_GET_ITA](functions/EXTDATE_GET_ITA.md) - Data in italiano
|
||||||
|
|
||||||
|
### [Packages](packages/README.md) (17)
|
||||||
|
|
||||||
|
Business:
|
||||||
|
|
||||||
|
- [MAIL_PKG](packages/MAIL_PKG.md) - Gestione invio email automatiche
|
||||||
|
|
||||||
|
Utility esterne:
|
||||||
|
|
||||||
|
- [UTL_BASE64](packages/UTL_BASE64.md) - Encoding Base64
|
||||||
|
|
||||||
|
JasperReports:
|
||||||
|
|
||||||
|
- [XLIB_JASPERREPORTS](packages/XLIB_JASPERREPORTS.md) - Integrazione JasperReports
|
||||||
|
- [XLIB_JASPERREPORTS_IMG](packages/XLIB_JASPERREPORTS_IMG.md) - Immagini report
|
||||||
|
|
||||||
|
HTTP/Componenti:
|
||||||
|
|
||||||
|
- [XLIB_HTTP](packages/XLIB_HTTP.md) - Chiamate HTTP
|
||||||
|
- [XLIB_COMPONENT](packages/XLIB_COMPONENT.md) - Componenti
|
||||||
|
- [XLIB_LOG](packages/XLIB_LOG.md) - Logging
|
||||||
|
|
||||||
|
JSON (libreria PLJSON):
|
||||||
|
|
||||||
|
- [PLJSON_DYN](packages/PLJSON_DYN.md)
|
||||||
|
- [PLJSON_EXT](packages/PLJSON_EXT.md)
|
||||||
|
- [PLJSON_HELPER](packages/PLJSON_HELPER.md)
|
||||||
|
- [PLJSON_ML](packages/PLJSON_ML.md)
|
||||||
|
- [PLJSON_OBJECT_CACHE](packages/PLJSON_OBJECT_CACHE.md)
|
||||||
|
- [PLJSON_PARSER](packages/PLJSON_PARSER.md)
|
||||||
|
- [PLJSON_PRINTER](packages/PLJSON_PRINTER.md)
|
||||||
|
- [PLJSON_UT](packages/PLJSON_UT.md)
|
||||||
|
- [PLJSON_UTIL_PKG](packages/PLJSON_UTIL_PKG.md)
|
||||||
|
- [PLJSON_XML](packages/PLJSON_XML.md)
|
||||||
|
|
||||||
|
### [Triggers](triggers/README.md) (19)
|
||||||
|
|
||||||
|
Generazione ID:
|
||||||
|
|
||||||
|
- [EVENTI_TRG](triggers/EVENTI_TRG.md) - ID eventi + inizializzazione
|
||||||
|
- [EVENTI_AI_TRG](triggers/EVENTI_AI_TRG.md) - Creazione ospiti default
|
||||||
|
- [EVENTI_DET_PREL_TRG](triggers/EVENTI_DET_PREL_TRG.md) - ID prelievi
|
||||||
|
- [EVENTI_DET_RIS_TRG](triggers/EVENTI_DET_RIS_TRG.md) - ID risorse
|
||||||
|
- [EVENTI_DET_DEGUST_TRG](triggers/EVENTI_DET_DEGUST_TRG.md) - ID degustazioni
|
||||||
|
- [EVENTI_ACCONTI_TRG](triggers/EVENTI_ACCONTI_TRG.md) - ID acconti
|
||||||
|
- [EVENTI_ALTRICOSTI_TRG](triggers/EVENTI_ALTRICOSTI_TRG.md) - ID altri costi
|
||||||
|
- [EVENTI_ALLEG_TRG](triggers/EVENTI_ALLEG_TRG.md) - ID allegati
|
||||||
|
- [CLIENTI_TRG](triggers/CLIENTI_TRG.md) - ID clienti
|
||||||
|
- [LOCATION_TRG](triggers/LOCATION_TRG.md) - ID location
|
||||||
|
- [RISORSE_TRG](triggers/RISORSE_TRG.md) - ID risorse
|
||||||
|
- [ARTICOLI_DET_REGOLE_TRG](triggers/ARTICOLI_DET_REGOLE_TRG.md) - ID regole articoli
|
||||||
|
- [TB_TIPI_PASTO_TRG](triggers/TB_TIPI_PASTO_TRG.md) - ID tipi pasto
|
||||||
|
|
||||||
|
Business logic:
|
||||||
|
|
||||||
|
- [EVENTI_DET_OSPITI_TRG_AI](triggers/EVENTI_DET_OSPITI_TRG_AI.md) - Aggiornamento ospiti
|
||||||
|
- [EVENTI_DET_PREL_QTA_TOT_TRG](triggers/EVENTI_DET_PREL_QTA_TOT_TRG.md) - Calcolo quantità totale
|
||||||
|
|
||||||
|
Ordinamento:
|
||||||
|
|
||||||
|
- [ADD_COD_STEP](triggers/ADD_COD_STEP.md) - Ordine tipi materiale
|
||||||
|
- [ON_DELETE_REORDER](triggers/ON_DELETE_REORDER.md) - Riordino dopo delete
|
||||||
|
|
||||||
|
Sistema:
|
||||||
|
|
||||||
|
- [BI_GL_SCHEMA_CHANGES](triggers/BI_GL_SCHEMA_CHANGES.md) - Log modifiche schema
|
||||||
|
- [XLIB_LOGS_BI_TRG](triggers/XLIB_LOGS_BI_TRG.md) - Log applicazione
|
||||||
|
|
||||||
|
### [Sequences](sequences/README.md) (22)
|
||||||
|
|
||||||
|
Tutte le sequence del database.
|
||||||
|
|
||||||
|
### [Types](types/README.md) (10)
|
||||||
|
|
||||||
|
Tipi custom:
|
||||||
|
|
||||||
|
- [T_DET_OSPITI_ROW](types/T_DET_OSPITI_ROW.md) / [T_DET_OSPITI_TAB](types/T_DET_OSPITI_TAB.md) - Tipo per F_GET_OSPITI
|
||||||
|
- [T_REP_ALLESTIMENTI_ROW](types/T_REP_ALLESTIMENTI_ROW.md) / [T_REP_ALLESTIMENTI_TAB](types/T_REP_ALLESTIMENTI_TAB.md) - Tipo per F_REP_ALLESTIMENTI
|
||||||
|
- [T_REP_CUCINA_ROW](types/T_REP_CUCINA_ROW.md) / [T_REP_CUCINA_TAB](types/T_REP_CUCINA_TAB.md) - Tipo per F_REP_CUCINA
|
||||||
|
- [STRING_LIST](types/STRING_LIST.md) - Lista stringhe
|
||||||
|
- [ENUM_TABLE_OBJECT](types/ENUM_TABLE_OBJECT.md) / [ENUM_TABLE_TYPE](types/ENUM_TABLE_TYPE.md) - Tipi per STRING_TO_TABLE_ENUM
|
||||||
|
- [XLIB_VC2_ARRAY_T](types/XLIB_VC2_ARRAY_T.md) - Array varchar2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schema ER Semplificato
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐
|
||||||
|
│ CLIENTI │
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||||
|
│ LOCATION │◄────│ EVENTI │────►│TB_TIPI_EVENTO│
|
||||||
|
└─────────────┘ └──────┬──────┘ └─────────────┘
|
||||||
|
│
|
||||||
|
┌─────────────────┼─────────────────┐
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│EVENTI_DET_OSPITI│ │ EVENTI_DET_PREL │ │ EVENTI_DET_RIS │
|
||||||
|
└─────────────────┘ └────────┬────────┘ └────────┬────────┘
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│ TB_TIPI_OSPITI │ │ ARTICOLI │ │ RISORSE │
|
||||||
|
└─────────────────┘ └────────┬────────┘ └─────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ TB_CODICI_CATEG │
|
||||||
|
└────────┬────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ TB_TIPI_MAT │
|
||||||
|
└─────────────────┘
|
||||||
|
|
||||||
|
┌─────────────────┬─────────────────┐
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│EVENTI_DET_DEGUST│ │ EVENTI_ACCONTI │ │EVENTI_ALTRICOSTI│
|
||||||
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workflow Stati Evento
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────┐
|
||||||
|
│ PREVENTIVO │ (100) - Bianco
|
||||||
|
└──────┬───────┘
|
||||||
|
│ Degustazione
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│SCHEDA EVENTO │ (200) - Celeste
|
||||||
|
│(preparazione)│
|
||||||
|
└──────┬───────┘
|
||||||
|
│ Prima caparra
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ SCHEDA │ (300) - Giallo
|
||||||
|
│ CONFERMATA │
|
||||||
|
└──────┬───────┘
|
||||||
|
│ Quasi confermato
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│SCHEDA QUASI │ (350) - Arancio
|
||||||
|
│ CONFERMATA │
|
||||||
|
└──────┬───────┘
|
||||||
|
│ Conferma definitiva
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ CONFERMATO │ (400) - Verde
|
||||||
|
└──────────────┘
|
||||||
|
|
||||||
|
│ Rifiuto/Scadenza
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│NON ACCETTATO/│ (900) - Viola
|
||||||
|
│ SUPERATO │
|
||||||
|
└──────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Note per lo Sviluppo
|
||||||
|
|
||||||
|
1. **Packages PLJSON\_\***: Libreria esterna per parsing JSON, può essere sostituita con funzionalità native .NET
|
||||||
|
|
||||||
|
2. **Packages XLIB\_\***: Componenti per integrazione JasperReports, da valutare sostituzione con report .NET
|
||||||
|
|
||||||
|
3. **Trigger per ID**: In .NET usare Identity columns o GUID
|
||||||
|
|
||||||
|
4. **Calcolo quantità**: La logica in `EVENTI_AGGIORNA_QTA_LISTA` è critica e deve essere portata fedelmente
|
||||||
|
|
||||||
|
5. **Sistema acconti**: Le percentuali 30%-50%-20% sono hardcoded, valutare parametrizzazione
|
||||||
392
docs/packages/MAIL_PKG.md
Normal file
392
docs/packages/MAIL_PKG.md
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
# MAIL_PKG
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE MAIL_PKG AS
|
||||||
|
--==================================================================================
|
||||||
|
-- SPECIFICA DEL PACKAGE
|
||||||
|
-- Aggiunta delle nuove procedure per il reminder della seconda caparra.
|
||||||
|
-- Ultima modifica: 26/07/2024
|
||||||
|
--==================================================================================
|
||||||
|
|
||||||
|
-- Procedura generica per inviare email
|
||||||
|
procedure send_custom_mail(p_recipients varchar2, p_subject varchar2, p_body varchar2);
|
||||||
|
|
||||||
|
-- Procedure esistenti
|
||||||
|
PROCEDURE send_richiesta_riscontro_preventivo (
|
||||||
|
p_style_id NUMBER DEFAULT 1,
|
||||||
|
p_evento_id NUMBER
|
||||||
|
);
|
||||||
|
PROCEDURE send_richiesta_riscontro_preventivo_job;
|
||||||
|
|
||||||
|
PROCEDURE send_richiesta_riscontro_post_degustazione (
|
||||||
|
p_style_id NUMBER DEFAULT 1,
|
||||||
|
p_evento_id NUMBER
|
||||||
|
);
|
||||||
|
PROCEDURE send_richiesta_riscontro_post_degustazione_job;
|
||||||
|
|
||||||
|
-- ===============================================================================
|
||||||
|
-- NUOVE PROCEDURE PER IL REMINDER DELLA SECONDA CAPARRA
|
||||||
|
-- Data creazione: 26/07/2024
|
||||||
|
-- ===============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @descr Costruisce e invia la mail di sollecito per la seconda caparra per un dato evento.
|
||||||
|
* @param p_style_id ID dello stile HTML da applicare alla mail.
|
||||||
|
* @param p_evento_id ID dell'evento per cui inviare la notifica.
|
||||||
|
*/
|
||||||
|
PROCEDURE send_reminder_seconda_caparra (
|
||||||
|
p_style_id NUMBER DEFAULT 1,
|
||||||
|
p_evento_id NUMBER
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @descr Job che seleziona gli eventi per cui inviare il sollecito della seconda caparra.
|
||||||
|
* Il primo invio avviene 65 giorni prima dell'evento.
|
||||||
|
* Gli invii successivi avvengono ogni 5 giorni fino alla data dell'evento,
|
||||||
|
* se la seconda caparra non risulta ancora pagata.
|
||||||
|
*/
|
||||||
|
PROCEDURE send_reminder_seconda_caparra_job;
|
||||||
|
|
||||||
|
END MAIL_PKG;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE BODY MAIL_PKG AS
|
||||||
|
--==================================================================================
|
||||||
|
-- BODY DEL PACKAGE
|
||||||
|
-- Implementazione delle nuove procedure e mantenimento di quelle esistenti.
|
||||||
|
-- Ultima modifica: 25/07/2024
|
||||||
|
--==================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @descr Procedura di utility generica per inviare una mail tramite APEX_MAIL.
|
||||||
|
* @param p_recipients Lista di destinatari separati da virgola.
|
||||||
|
* @param p_subject Oggetto della mail.
|
||||||
|
* @param p_body Corpo della mail (può contenere HTML).
|
||||||
|
*/
|
||||||
|
procedure send_custom_mail(p_recipients varchar2, p_subject varchar2, p_body varchar2) AS
|
||||||
|
BEGIN
|
||||||
|
-- Se non ci sono destinatari, interrompe l'esecuzione.
|
||||||
|
if trim(p_recipients) is null
|
||||||
|
then
|
||||||
|
return;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Utilizza il package APEX_MAIL per comporre e inviare l'email.
|
||||||
|
APEX_MAIL.SEND(
|
||||||
|
p_to => p_recipients,
|
||||||
|
p_from => 'noreply@apollinarecatering.it',
|
||||||
|
p_bcc => 'monia@apollinarecatering.it, matrimonio@apollinarecatering.it',
|
||||||
|
--p_bcc => 'monia@apollinarecatering.it, maria@apollinarecatering.it', -- Copia conoscenza nascosta
|
||||||
|
p_subj => p_subject,
|
||||||
|
p_body => p_body,
|
||||||
|
p_body_html => p_body -- Il corpo viene inviato sia come testo che come HTML.
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Forza l'invio immediato delle mail presenti nella coda di APEX.
|
||||||
|
APEX_MAIL.PUSH_QUEUE;
|
||||||
|
END send_custom_mail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @descr Invia una mail di sollecito per avere un riscontro su un preventivo inviato per eventi in stato preventivo (100) o scheda confermata (200).
|
||||||
|
* @param p_style_id ID dello stile HTML da usare per il corpo della mail.
|
||||||
|
* @param p_evento_id ID dell'evento a cui la mail fa riferimento.
|
||||||
|
*/
|
||||||
|
PROCEDURE send_richiesta_riscontro_preventivo (
|
||||||
|
p_style_id NUMBER DEFAULT 1,
|
||||||
|
p_evento_id NUMBER
|
||||||
|
) AS
|
||||||
|
v_evento eventi%ROWTYPE;
|
||||||
|
v_location location%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
-- Imposta la lingua e il formato della data della sessione per garantire la corretta formattazione.
|
||||||
|
EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_LANGUAGE="ITALIAN"';
|
||||||
|
EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT="DD-MON-YYYY"';
|
||||||
|
|
||||||
|
-- Recupera i dettagli dell'evento e della location.
|
||||||
|
BEGIN
|
||||||
|
-- Seleziona i dati dell'evento solo se le mail sono abilitate (mail_enabled > 0).
|
||||||
|
SELECT e.* INTO v_evento
|
||||||
|
FROM eventi e
|
||||||
|
WHERE e.id = p_evento_id
|
||||||
|
AND e.stato in (100, 200)
|
||||||
|
AND e.mail_enabled > 0;
|
||||||
|
|
||||||
|
-- Seleziona i dati della location associata all'evento.
|
||||||
|
SELECT l.* INTO v_location
|
||||||
|
FROM location l
|
||||||
|
WHERE l.id = v_evento.id_location;
|
||||||
|
EXCEPTION
|
||||||
|
-- Se l'evento non viene trovato (o ha le mail disabilitate), la procedura termina.
|
||||||
|
WHEN NO_DATA_FOUND THEN RETURN;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Inizializza il corpo della mail e imposta lo stile HTML.
|
||||||
|
CMN_MAIL_HTMLUTILS.mailbody := '';
|
||||||
|
CMN_MAIL_HTMLUTILS.set_style(p_style_id);
|
||||||
|
|
||||||
|
-- Costruisce il corpo della mail paragrafo per paragrafo utilizzando il package di utility.
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('Gentilissimi,');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph(
|
||||||
|
'in seguito all''invio della nostra proposta per il vostro evento, '||
|
||||||
|
'desideriamo sapere se avete avuto modo di valutarla e se siete interessati ai nostri servizi.'
|
||||||
|
);
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph(
|
||||||
|
'Saremmo lieti di incontrarvi per una degustazione, così da potervi presentare al meglio le nostre offerte. '||
|
||||||
|
'Potete prenotare una delle date disponibili direttamente tramite il nostro sito: '||
|
||||||
|
'<a href="https://www.apollinarecatering.it/degustazioni/">Degustazioni</a>.'
|
||||||
|
);
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph(
|
||||||
|
'Per qualsiasi ulteriore informazione o chiarimento potete scriverci a '||
|
||||||
|
'<a href="mailto:info@apollinarecatering.it">info@apollinarecatering.it</a>.'
|
||||||
|
);
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('<b>Si prega di non rispondere direttamente a questa email.</b>');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('Cordiali saluti,');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('<b>Ufficio Commerciale</b>');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('📞 +39 0743 45 449');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('<b>Apollinare Catering</b>');
|
||||||
|
|
||||||
|
-- Invia la mail usando APEX_MAIL, componendo un oggetto dinamico.
|
||||||
|
APEX_MAIL.SEND(
|
||||||
|
p_to => v_evento.cliente_email,
|
||||||
|
p_from => 'noreply@apollinarecatering.it',
|
||||||
|
p_bcc => 'monia@apollinarecatering.it, matrimonio@apollinarecatering.it',
|
||||||
|
--p_bcc => 'monia@apollinarecatering.it, maria@apollinarecatering.it',
|
||||||
|
p_subj => 'Apollinare – richiesta riscontro per evento del '||
|
||||||
|
TO_CHAR(v_evento.data, 'DD/MM/YYYY')||' presso '||v_location.location,
|
||||||
|
p_body => CMN_MAIL_HTMLUTILS.mailbody,
|
||||||
|
p_body_html => CMN_MAIL_HTMLUTILS.mailbody
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Forza l'invio immediato dalla coda di APEX.
|
||||||
|
APEX_MAIL.PUSH_QUEUE;
|
||||||
|
END send_richiesta_riscontro_preventivo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @descr Invia una mail di sollecito dopo che il cliente ha partecipato a una degustazione.
|
||||||
|
* @param p_style_id ID dello stile HTML da usare per il corpo della mail.
|
||||||
|
* @param p_evento_id ID dell'evento a cui la mail fa riferimento.
|
||||||
|
*/
|
||||||
|
PROCEDURE send_richiesta_riscontro_post_degustazione (
|
||||||
|
p_style_id NUMBER DEFAULT 1,
|
||||||
|
p_evento_id NUMBER
|
||||||
|
) AS
|
||||||
|
v_evento eventi%ROWTYPE;
|
||||||
|
v_location location%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
-- Imposta la lingua e il formato della data della sessione.
|
||||||
|
EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_LANGUAGE="ITALIAN"';
|
||||||
|
EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT="DD-MON-YYYY"';
|
||||||
|
|
||||||
|
-- Recupera i dettagli dell'evento e della location.
|
||||||
|
BEGIN
|
||||||
|
-- Seleziona i dati dell'evento solo se le mail sono abilitate.
|
||||||
|
SELECT e.* INTO v_evento
|
||||||
|
FROM eventi e
|
||||||
|
WHERE e.id = p_evento_id
|
||||||
|
AND e.stato in (200)
|
||||||
|
AND e.mail_enabled > 0;
|
||||||
|
|
||||||
|
-- Seleziona i dati della location.
|
||||||
|
SELECT l.* INTO v_location
|
||||||
|
FROM location l
|
||||||
|
WHERE l.id = v_evento.id_location;
|
||||||
|
EXCEPTION
|
||||||
|
-- Se non trova l'evento, esce dalla procedura.
|
||||||
|
WHEN NO_DATA_FOUND THEN RETURN;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Inizializza il corpo della mail e imposta lo stile HTML.
|
||||||
|
CMN_MAIL_HTMLUTILS.mailbody := '';
|
||||||
|
CMN_MAIL_HTMLUTILS.set_style(p_style_id);
|
||||||
|
|
||||||
|
-- Costruisce il corpo della mail.
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('Gentilissimi,');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph(
|
||||||
|
'in seguito alla degustazione effettuata per il vostro evento, '||
|
||||||
|
'desideriamo sapere se la nostra proposta risponde alle vostre aspettative '||
|
||||||
|
'e se intendete procedere con la conferma dei servizi.'
|
||||||
|
);
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph(
|
||||||
|
'Per ogni ulteriore chiarimento siamo a vostra completa disposizione: '||
|
||||||
|
'<a href="mailto:info@apollinarecatering.it">info@apollinarecatering.it</a>.'
|
||||||
|
);
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('<b>Si prega di non rispondere direttamente a questa email.</b>');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('Cordiali saluti,');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('<b>Ufficio Commerciale</b>');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('📞 +39 0743 45 449');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('<b>Apollinare Catering</b>');
|
||||||
|
|
||||||
|
-- Invia la mail, componendo un oggetto dinamico con data e location.
|
||||||
|
APEX_MAIL.SEND(
|
||||||
|
p_to => v_evento.cliente_email,
|
||||||
|
p_from => 'noreply@apollinarecatering.it',
|
||||||
|
p_bcc => 'monia@apollinarecatering.it, matrimonio@apollinarecatering.it',
|
||||||
|
--p_bcc => 'monia@apollinarecatering.it, maria@apollinarecatering.it',
|
||||||
|
p_subj => 'Apollinare – riscontro post-degustazione evento del '||
|
||||||
|
TO_CHAR(v_evento.data, 'DD/MM/YYYY')||' presso '||v_location.location,
|
||||||
|
p_body => CMN_MAIL_HTMLUTILS.mailbody,
|
||||||
|
p_body_html => CMN_MAIL_HTMLUTILS.mailbody
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Forza l'invio immediato.
|
||||||
|
APEX_MAIL.PUSH_QUEUE;
|
||||||
|
END send_richiesta_riscontro_post_degustazione;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @descr Procedura schedulabile (job) che invia solleciti per i preventivi non confermati.
|
||||||
|
*/
|
||||||
|
PROCEDURE send_richiesta_riscontro_preventivo_job AS
|
||||||
|
BEGIN
|
||||||
|
-- Itera su tutti gli eventi che soddisfano i criteri per il sollecito.
|
||||||
|
FOR evt IN (
|
||||||
|
SELECT e.*
|
||||||
|
FROM eventi e
|
||||||
|
WHERE e.stato in (100) -- Stato: Preventivo non confermato
|
||||||
|
AND e.mail_enabled = 1 -- Mail abilitate
|
||||||
|
AND TRUNC(e.data_doc) = TRUNC(SYSDATE) - 10 -- Sono passati 10 giorni dalla data del documento.
|
||||||
|
)
|
||||||
|
LOOP
|
||||||
|
-- Per ogni evento trovato, chiama la procedura di invio mail.
|
||||||
|
send_richiesta_riscontro_preventivo(
|
||||||
|
p_style_id => 1,
|
||||||
|
p_evento_id => evt.id
|
||||||
|
);
|
||||||
|
END LOOP;
|
||||||
|
END send_richiesta_riscontro_preventivo_job;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @descr Procedura schedulabile (job) che invia solleciti dopo una degustazione.
|
||||||
|
*/
|
||||||
|
PROCEDURE send_richiesta_riscontro_post_degustazione_job AS
|
||||||
|
BEGIN
|
||||||
|
-- Itera su tutti gli eventi che soddisfano i criteri per il sollecito post-degustazione.
|
||||||
|
FOR evt IN (
|
||||||
|
SELECT e.*
|
||||||
|
FROM eventi e
|
||||||
|
JOIN ( -- Sottoquery per trovare la data della prima degustazione per ogni evento.
|
||||||
|
SELECT id_evento,
|
||||||
|
MIN(TRUNC(data)) AS min_data
|
||||||
|
FROM eventi_det_degust
|
||||||
|
GROUP BY id_evento ) dm
|
||||||
|
ON dm.id_evento = e.id
|
||||||
|
WHERE e.stato = 200 -- Stato: Scheda evento in preparazione
|
||||||
|
AND e.mail_enabled = 1 -- Mail abilitate
|
||||||
|
AND dm.min_data = TRUNC(SYSDATE) - 15 -- Sono passati 15 giorni dalla prima degustazione.
|
||||||
|
)
|
||||||
|
LOOP
|
||||||
|
-- Per ogni evento trovato, chiama la procedura di invio mail.
|
||||||
|
send_richiesta_riscontro_post_degustazione(
|
||||||
|
p_style_id => 1,
|
||||||
|
p_evento_id => evt.id
|
||||||
|
);
|
||||||
|
END LOOP;
|
||||||
|
END send_richiesta_riscontro_post_degustazione_job;
|
||||||
|
|
||||||
|
|
||||||
|
-- ===============================================================================
|
||||||
|
-- IMPLEMENTAZIONE NUOVE PROCEDURE
|
||||||
|
-- Data creazione: 26/07/2024
|
||||||
|
-- ===============================================================================
|
||||||
|
|
||||||
|
PROCEDURE send_reminder_seconda_caparra (
|
||||||
|
p_style_id NUMBER DEFAULT 1,
|
||||||
|
p_evento_id NUMBER
|
||||||
|
) AS
|
||||||
|
v_evento eventi%ROWTYPE;
|
||||||
|
v_location location%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_LANGUAGE="ITALIAN"';
|
||||||
|
EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT="DD-MON-YYYY"';
|
||||||
|
|
||||||
|
-- Recupero i dati dell'evento e della location
|
||||||
|
BEGIN
|
||||||
|
SELECT e.* INTO v_evento
|
||||||
|
FROM eventi e
|
||||||
|
WHERE e.id = p_evento_id
|
||||||
|
AND e.mail_enabled > 0;
|
||||||
|
|
||||||
|
SELECT l.* INTO v_location
|
||||||
|
FROM location l
|
||||||
|
WHERE l.id = v_evento.id_location;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN NO_DATA_FOUND THEN
|
||||||
|
-- Se l'evento non esiste o le mail sono disabilitate, esco.
|
||||||
|
RETURN;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Costruzione del corpo della mail
|
||||||
|
CMN_MAIL_HTMLUTILS.mailbody := '';
|
||||||
|
CMN_MAIL_HTMLUTILS.set_style(p_style_id);
|
||||||
|
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('Gentilissimi,');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph(
|
||||||
|
'sperando che tutto proceda per il meglio, desideriamo cortesemente ricordarvi la scadenza relativa alla seconda tranche di pagamento per il vostro evento.'
|
||||||
|
);
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph(
|
||||||
|
'Qualora non fosse ancora stato effettuato, vi invitiamo a procedere con il versamento della seconda caparra, previsto 60 giorni prima della data dell’evento, come da accordi e indicato nel preventivo.'
|
||||||
|
);
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph(
|
||||||
|
'Rimaniamo a disposizione per qualsiasi chiarimento e vi ringraziamo sin da ora per la preziosa collaborazione.'
|
||||||
|
);
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('Cordiali saluti,');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('<b>Ufficio Commerciale</b>');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('📞 +39 0743 45 449');
|
||||||
|
CMN_MAIL_HTMLUTILS.create_paragraph('<b>Apollinare Catering</b>');
|
||||||
|
|
||||||
|
-- Invio della mail
|
||||||
|
APEX_MAIL.SEND(
|
||||||
|
--p_to => v_evento.cliente_email,
|
||||||
|
p_to => 'amministrazione@apollinarecatering.it',
|
||||||
|
p_from => 'noreply@apollinarecatering.it',
|
||||||
|
p_bcc => 'monia@apollinarecatering.it, matrimonio@apollinarecatering.it',
|
||||||
|
--p_bcc => 'monia@apollinarecatering.it, maria@apollinarecatering.it',
|
||||||
|
p_subj => 'Apollinare – Promemoria pagamento per evento del '||
|
||||||
|
TO_CHAR(v_evento.data, 'DD/MM/YYYY'),
|
||||||
|
p_body => CMN_MAIL_HTMLUTILS.mailbody,
|
||||||
|
p_body_html => CMN_MAIL_HTMLUTILS.mailbody
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Invio immediato dalla coda
|
||||||
|
APEX_MAIL.PUSH_QUEUE;
|
||||||
|
|
||||||
|
END send_reminder_seconda_caparra;
|
||||||
|
|
||||||
|
|
||||||
|
PROCEDURE send_reminder_seconda_caparra_job AS
|
||||||
|
BEGIN
|
||||||
|
-- Scorro tutti gli eventi che necessitano del reminder.
|
||||||
|
-- La logica ora utilizza la vista GET_EVENTI_DA_PAGARE_ENTRO_65GG
|
||||||
|
-- per identificare gli eventi che non hanno saldato la caparra.
|
||||||
|
FOR evt IN (
|
||||||
|
SELECT
|
||||||
|
v.id,
|
||||||
|
v.data -- Seleziono la data per il calcolo del MOD
|
||||||
|
FROM
|
||||||
|
GET_EVENTI_DA_PAGARE_ENTRO_65GG v
|
||||||
|
JOIN
|
||||||
|
eventi e ON v.id = e.id -- Join per recuperare il flag mail_enabled
|
||||||
|
WHERE
|
||||||
|
-- La vista già filtra per stato, importi e finestra di 65 giorni.
|
||||||
|
-- Aggiungo solo le condizioni specifiche del job.
|
||||||
|
|
||||||
|
-- Le mail automatiche devono essere abilitate.
|
||||||
|
e.mail_enabled = 1
|
||||||
|
|
||||||
|
-- La logica MOD assicura l'invio periodico ogni 5 giorni.
|
||||||
|
AND MOD(65 - (TRUNC(v.data) - TRUNC(SYSDATE)), 5) = 0
|
||||||
|
)
|
||||||
|
LOOP
|
||||||
|
-- Per ogni evento trovato, chiamo la procedura di invio mail.
|
||||||
|
send_reminder_seconda_caparra(
|
||||||
|
p_style_id => 1,
|
||||||
|
p_evento_id => evt.id
|
||||||
|
);
|
||||||
|
END LOOP;
|
||||||
|
END send_reminder_seconda_caparra_job;
|
||||||
|
|
||||||
|
END MAIL_PKG;```
|
||||||
341
docs/packages/PLJSON_DYN.md
Normal file
341
docs/packages/PLJSON_DYN.md
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
# PLJSON_DYN
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package pljson_dyn authid current_user as
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Jonas Krogsboell
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
null_as_empty_string boolean not null := true; --varchar2
|
||||||
|
include_dates boolean not null := true; --date
|
||||||
|
include_clobs boolean not null := true;
|
||||||
|
include_blobs boolean not null := false;
|
||||||
|
include_arrays boolean not null := true; -- pljson_varray or pljson_narray
|
||||||
|
|
||||||
|
/* list with objects */
|
||||||
|
function executeList(stmt varchar2, bindvar pljson default null, cur_num number default null, bindvardateformats pljson default null) return pljson_list;
|
||||||
|
|
||||||
|
/* object with lists */
|
||||||
|
function executeObject(stmt varchar2, bindvar pljson default null, cur_num number default null) return pljson;
|
||||||
|
|
||||||
|
|
||||||
|
/* usage example:
|
||||||
|
* declare
|
||||||
|
* res json_list;
|
||||||
|
* begin
|
||||||
|
* res := json_dyn.executeList(
|
||||||
|
* 'select :bindme as one, :lala as two from dual where dummy in :arraybind',
|
||||||
|
* json('{bindme:"4", lala:123, arraybind:[1, 2, 3, "X"]}')
|
||||||
|
* );
|
||||||
|
* res.print;
|
||||||
|
* end;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* --11g functions
|
||||||
|
function executeList(stmt in out sys_refcursor) return json_list;
|
||||||
|
function executeObject(stmt in out sys_refcursor) return json;
|
||||||
|
*/
|
||||||
|
end pljson_dyn;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package body pljson_dyn as
|
||||||
|
/*
|
||||||
|
-- 11gR2
|
||||||
|
function executeList(stmt in out sys_refcursor) return json_list as
|
||||||
|
l_cur number;
|
||||||
|
begin
|
||||||
|
l_cur := dbms_sql.to_cursor_number(stmt);
|
||||||
|
return json_dyn.executeList(null, null, l_cur);
|
||||||
|
end;
|
||||||
|
|
||||||
|
-- 11gR2
|
||||||
|
function executeObject(stmt in out sys_refcursor) return json as
|
||||||
|
l_cur number;
|
||||||
|
begin
|
||||||
|
l_cur := dbms_sql.to_cursor_number(stmt);
|
||||||
|
return json_dyn.executeObject(null, null, l_cur);
|
||||||
|
end;
|
||||||
|
*/
|
||||||
|
|
||||||
|
procedure bind_json(l_cur number, bindvar pljson, bindvardateformats pljson default null) as
|
||||||
|
keylist pljson_list := bindvar.get_keys();
|
||||||
|
begin
|
||||||
|
for i in 1 .. keylist.count loop
|
||||||
|
if (bindvar.get(i).is_number()) then
|
||||||
|
dbms_sql.bind_variable(l_cur, ':'||keylist.get(i).get_string(), bindvar.get(i).get_number());
|
||||||
|
elsif (bindvar.get(i).is_array()) then
|
||||||
|
declare
|
||||||
|
v_bind dbms_sql.varchar2_table;
|
||||||
|
v_arr pljson_list := pljson_list(bindvar.get(i));
|
||||||
|
begin
|
||||||
|
for j in 1 .. v_arr.count loop
|
||||||
|
v_bind(j) := v_arr.get(j).value_of();
|
||||||
|
end loop;
|
||||||
|
dbms_sql.bind_array(l_cur, ':'||keylist.get(i).get_string(), v_bind);
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
if bindvardateformats is not null then
|
||||||
|
if bindvardateformats.exist(keylist.get(i).get_string()) then
|
||||||
|
dbms_sql.bind_variable(l_cur, ':'||keylist.get(i).get_string(), to_date(bindvar.get(i).value_of(), bindvardateformats.get(keylist.get(i).get_string()).get_string() ));
|
||||||
|
else
|
||||||
|
dbms_sql.bind_variable(l_cur, ':'||keylist.get(i).get_string(), bindvar.get(i).value_of());
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
dbms_sql.bind_variable(l_cur, ':'||keylist.get(i).get_string(), bindvar.get(i).value_of());
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end bind_json;
|
||||||
|
|
||||||
|
/* list with objects */
|
||||||
|
function executeList(stmt varchar2, bindvar pljson, cur_num number, bindvardateformats pljson default null) return pljson_list as
|
||||||
|
l_cur number;
|
||||||
|
l_dtbl dbms_sql.desc_tab3;
|
||||||
|
l_cnt number;
|
||||||
|
l_status number;
|
||||||
|
l_val varchar2(4000);
|
||||||
|
outer_list pljson_list := pljson_list();
|
||||||
|
inner_obj pljson;
|
||||||
|
conv number;
|
||||||
|
read_date date;
|
||||||
|
read_clob clob;
|
||||||
|
read_blob blob;
|
||||||
|
col_type number;
|
||||||
|
read_varray pljson_varray;
|
||||||
|
read_narray pljson_narray;
|
||||||
|
begin
|
||||||
|
if (cur_num is not null) then
|
||||||
|
l_cur := cur_num;
|
||||||
|
else
|
||||||
|
l_cur := dbms_sql.open_cursor;
|
||||||
|
dbms_sql.parse(l_cur, stmt, dbms_sql.native);
|
||||||
|
if (bindvar is not null) then bind_json(l_cur, bindvar, bindvardateformats); end if;
|
||||||
|
end if;
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2018-05-01 handling of varray, narray in select */
|
||||||
|
dbms_sql.describe_columns3(l_cur, l_cnt, l_dtbl);
|
||||||
|
for i in 1..l_cnt loop
|
||||||
|
col_type := l_dtbl(i).col_type;
|
||||||
|
--dbms_output.put_line(col_type);
|
||||||
|
if (col_type = 12) then
|
||||||
|
dbms_sql.define_column(l_cur, i, read_date);
|
||||||
|
elsif (col_type = 112) then
|
||||||
|
dbms_sql.define_column(l_cur, i, read_clob);
|
||||||
|
elsif (col_type = 113) then
|
||||||
|
dbms_sql.define_column(l_cur, i, read_blob);
|
||||||
|
elsif (col_type in (1, 2, 96)) then
|
||||||
|
dbms_sql.define_column(l_cur, i, l_val, 4000);
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2018-05-01 handling of pljson_varray in select */
|
||||||
|
elsif (col_type = 109 and l_dtbl(i).col_type_name = 'PLJSON_VARRAY') then
|
||||||
|
dbms_sql.define_column(l_cur, i, read_varray);
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2018-05-01 handling of pljson_narray in select */
|
||||||
|
elsif (col_type = 109 and l_dtbl(i).col_type_name = 'PLJSON_NARRAY') then
|
||||||
|
dbms_sql.define_column(l_cur, i, read_narray);
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2018-05-01 record unhandled col_type */
|
||||||
|
else
|
||||||
|
dbms_output.put_line('unhandled col_type =' || col_type);
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
if (cur_num is null) then l_status := dbms_sql.execute(l_cur); end if;
|
||||||
|
|
||||||
|
--loop through rows
|
||||||
|
while ( dbms_sql.fetch_rows(l_cur) > 0 ) loop
|
||||||
|
inner_obj := pljson(); --init for each row
|
||||||
|
inner_obj.check_for_duplicate := 0;
|
||||||
|
--loop through columns
|
||||||
|
for i in 1..l_cnt loop
|
||||||
|
case true
|
||||||
|
--handling string types
|
||||||
|
when l_dtbl(i).col_type in (1, 96) then -- varchar2
|
||||||
|
dbms_sql.column_value(l_cur, i, l_val);
|
||||||
|
if (l_val is null) then
|
||||||
|
if (null_as_empty_string) then
|
||||||
|
inner_obj.put(l_dtbl(i).col_name, ''); --treat as emptystring?
|
||||||
|
else
|
||||||
|
inner_obj.put(l_dtbl(i).col_name, pljson_null()); --null
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
inner_obj.put(l_dtbl(i).col_name, pljson_string(l_val)); --null
|
||||||
|
end if;
|
||||||
|
--dbms_output.put_line(l_dtbl(i).col_name||' --> '||l_val||'varchar2' ||l_dtbl(i).col_type);
|
||||||
|
--handling number types
|
||||||
|
when l_dtbl(i).col_type = 2 then -- number
|
||||||
|
dbms_sql.column_value(l_cur, i, l_val);
|
||||||
|
conv := l_val;
|
||||||
|
inner_obj.put(l_dtbl(i).col_name, conv);
|
||||||
|
-- dbms_output.put_line(l_dtbl(i).col_name||' --> '||l_val||'number ' ||l_dtbl(i).col_type);
|
||||||
|
when l_dtbl(i).col_type = 12 then -- date
|
||||||
|
if (include_dates) then
|
||||||
|
dbms_sql.column_value(l_cur, i, read_date);
|
||||||
|
inner_obj.put(l_dtbl(i).col_name, pljson_ext.to_json_string(read_date));
|
||||||
|
end if;
|
||||||
|
--dbms_output.put_line(l_dtbl(i).col_name||' --> '||l_val||'date ' ||l_dtbl(i).col_type);
|
||||||
|
when l_dtbl(i).col_type = 112 then --clob
|
||||||
|
if (include_clobs) then
|
||||||
|
dbms_sql.column_value(l_cur, i, read_clob);
|
||||||
|
inner_obj.put(l_dtbl(i).col_name, pljson_string(read_clob));
|
||||||
|
end if;
|
||||||
|
when l_dtbl(i).col_type = 113 then --blob
|
||||||
|
if (include_blobs) then
|
||||||
|
dbms_sql.column_value(l_cur, i, read_blob);
|
||||||
|
if (dbms_lob.getlength(read_blob) > 0) then
|
||||||
|
inner_obj.put(l_dtbl(i).col_name, pljson_ext.encode(read_blob));
|
||||||
|
else
|
||||||
|
inner_obj.put(l_dtbl(i).col_name, pljson_null());
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2018-05-01 handling of pljson_varray in select */
|
||||||
|
when l_dtbl(i).col_type = 109 and l_dtbl(i).col_type_name = 'PLJSON_VARRAY' then
|
||||||
|
if (include_arrays) then
|
||||||
|
dbms_sql.column_value(l_cur, i, read_varray);
|
||||||
|
inner_obj.put(l_dtbl(i).col_name, pljson_list(read_varray));
|
||||||
|
end if;
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2018-05-01 handling of pljson_narray in select */
|
||||||
|
when l_dtbl(i).col_type = 109 and l_dtbl(i).col_type_name = 'PLJSON_NARRAY' then
|
||||||
|
if (include_arrays) then
|
||||||
|
dbms_sql.column_value(l_cur, i, read_narray);
|
||||||
|
inner_obj.put(l_dtbl(i).col_name, pljson_list(read_narray));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
else null; --discard other types
|
||||||
|
end case;
|
||||||
|
end loop;
|
||||||
|
inner_obj.check_for_duplicate := 1;
|
||||||
|
outer_list.append(inner_obj);
|
||||||
|
end loop;
|
||||||
|
dbms_sql.close_cursor(l_cur);
|
||||||
|
return outer_list;
|
||||||
|
end executeList;
|
||||||
|
|
||||||
|
/* object with lists */
|
||||||
|
function executeObject(stmt varchar2, bindvar pljson, cur_num number) return pljson as
|
||||||
|
l_cur number;
|
||||||
|
l_dtbl dbms_sql.desc_tab;
|
||||||
|
l_cnt number;
|
||||||
|
l_status number;
|
||||||
|
l_val varchar2(4000);
|
||||||
|
inner_list_names pljson_list := pljson_list();
|
||||||
|
inner_list_data pljson_list := pljson_list();
|
||||||
|
data_list pljson_list;
|
||||||
|
outer_obj pljson := pljson();
|
||||||
|
conv number;
|
||||||
|
read_date date;
|
||||||
|
read_clob clob;
|
||||||
|
read_blob blob;
|
||||||
|
col_type number;
|
||||||
|
begin
|
||||||
|
if (cur_num is not null) then
|
||||||
|
l_cur := cur_num;
|
||||||
|
else
|
||||||
|
l_cur := dbms_sql.open_cursor;
|
||||||
|
dbms_sql.parse(l_cur, stmt, dbms_sql.native);
|
||||||
|
if (bindvar is not null) then bind_json(l_cur, bindvar); end if;
|
||||||
|
end if;
|
||||||
|
dbms_sql.describe_columns(l_cur, l_cnt, l_dtbl);
|
||||||
|
for i in 1..l_cnt loop
|
||||||
|
col_type := l_dtbl(i).col_type;
|
||||||
|
if (col_type = 12) then
|
||||||
|
dbms_sql.define_column(l_cur, i, read_date);
|
||||||
|
elsif (col_type = 112) then
|
||||||
|
dbms_sql.define_column(l_cur, i, read_clob);
|
||||||
|
elsif (col_type = 113) then
|
||||||
|
dbms_sql.define_column(l_cur, i, read_blob);
|
||||||
|
elsif (col_type in (1, 2, 96)) then
|
||||||
|
dbms_sql.define_column(l_cur, i, l_val, 4000);
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
if (cur_num is null) then l_status := dbms_sql.execute(l_cur); end if;
|
||||||
|
|
||||||
|
--build up name_list
|
||||||
|
for i in 1..l_cnt loop
|
||||||
|
case l_dtbl(i).col_type
|
||||||
|
when 1 then inner_list_names.append(l_dtbl(i).col_name);
|
||||||
|
when 96 then inner_list_names.append(l_dtbl(i).col_name);
|
||||||
|
when 2 then inner_list_names.append(l_dtbl(i).col_name);
|
||||||
|
when 12 then if (include_dates) then inner_list_names.append(l_dtbl(i).col_name); end if;
|
||||||
|
when 112 then if (include_clobs) then inner_list_names.append(l_dtbl(i).col_name); end if;
|
||||||
|
when 113 then if (include_blobs) then inner_list_names.append(l_dtbl(i).col_name); end if;
|
||||||
|
else null;
|
||||||
|
end case;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
--loop through rows
|
||||||
|
while ( dbms_sql.fetch_rows(l_cur) > 0 ) loop
|
||||||
|
data_list := pljson_list();
|
||||||
|
--loop through columns
|
||||||
|
for i in 1..l_cnt loop
|
||||||
|
case true
|
||||||
|
--handling string types
|
||||||
|
when l_dtbl(i).col_type in (1, 96) then -- varchar2
|
||||||
|
dbms_sql.column_value(l_cur, i, l_val);
|
||||||
|
if (l_val is null) then
|
||||||
|
if (null_as_empty_string) then
|
||||||
|
data_list.append(''); --treat as emptystring?
|
||||||
|
else
|
||||||
|
data_list.append(pljson_null()); --null
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
data_list.append(pljson_string(l_val)); --null
|
||||||
|
end if;
|
||||||
|
--dbms_output.put_line(l_dtbl(i).col_name||' --> '||l_val||'varchar2' ||l_dtbl(i).col_type);
|
||||||
|
--handling number types
|
||||||
|
when l_dtbl(i).col_type = 2 then -- number
|
||||||
|
dbms_sql.column_value(l_cur, i, l_val);
|
||||||
|
conv := l_val;
|
||||||
|
data_list.append(conv);
|
||||||
|
-- dbms_output.put_line(l_dtbl(i).col_name||' --> '||l_val||'number ' ||l_dtbl(i).col_type);
|
||||||
|
when l_dtbl(i).col_type = 12 then -- date
|
||||||
|
if (include_dates) then
|
||||||
|
dbms_sql.column_value(l_cur, i, read_date);
|
||||||
|
data_list.append(pljson_ext.to_json_string(read_date));
|
||||||
|
end if;
|
||||||
|
--dbms_output.put_line(l_dtbl(i).col_name||' --> '||l_val||'date ' ||l_dtbl(i).col_type);
|
||||||
|
when l_dtbl(i).col_type = 112 then --clob
|
||||||
|
if (include_clobs) then
|
||||||
|
dbms_sql.column_value(l_cur, i, read_clob);
|
||||||
|
data_list.append(pljson_string(read_clob));
|
||||||
|
end if;
|
||||||
|
when l_dtbl(i).col_type = 113 then --blob
|
||||||
|
if (include_blobs) then
|
||||||
|
dbms_sql.column_value(l_cur, i, read_blob);
|
||||||
|
if (dbms_lob.getlength(read_blob) > 0) then
|
||||||
|
data_list.append(pljson_ext.encode(read_blob));
|
||||||
|
else
|
||||||
|
data_list.append(pljson_null());
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
else null; --discard other types
|
||||||
|
end case;
|
||||||
|
end loop;
|
||||||
|
inner_list_data.append(data_list);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
outer_obj.put('names', inner_list_names);
|
||||||
|
outer_obj.put('data', inner_list_data);
|
||||||
|
dbms_sql.close_cursor(l_cur);
|
||||||
|
return outer_obj;
|
||||||
|
end executeObject;
|
||||||
|
|
||||||
|
end pljson_dyn;```
|
||||||
1105
docs/packages/PLJSON_EXT.md
Normal file
1105
docs/packages/PLJSON_EXT.md
Normal file
File diff suppressed because it is too large
Load Diff
475
docs/packages/PLJSON_HELPER.md
Normal file
475
docs/packages/PLJSON_HELPER.md
Normal file
@@ -0,0 +1,475 @@
|
|||||||
|
# PLJSON_HELPER
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package pljson_helper as
|
||||||
|
/* Example:
|
||||||
|
set serveroutput on;
|
||||||
|
declare
|
||||||
|
v_a json;
|
||||||
|
v_b json;
|
||||||
|
begin
|
||||||
|
v_a := json('{a:1, b:{a:null}, e:false}');
|
||||||
|
v_b := json('{c:3, e:{}, b:{b:2}}');
|
||||||
|
json_helper.merge(v_a, v_b).print(false);
|
||||||
|
end;
|
||||||
|
--
|
||||||
|
{"a":1,"b":{"a":null,"b":2},"e":{},"c":3}
|
||||||
|
*/
|
||||||
|
-- Recursive merge
|
||||||
|
-- Courtesy of Matt Nolan - edited by Jonas Krogsboell
|
||||||
|
function merge(p_a_json pljson, p_b_json pljson) return pljson;
|
||||||
|
|
||||||
|
-- Join two lists
|
||||||
|
-- json_helper.join(json_list('[1,2,3]'),json_list('[4,5,6]')) -> [1,2,3,4,5,6]
|
||||||
|
function join(p_a_list pljson_list, p_b_list pljson_list) return pljson_list;
|
||||||
|
|
||||||
|
-- keep only specific keys in json object
|
||||||
|
-- json_helper.keep(json('{a:1,b:2,c:3,d:4,e:5,f:6}'),json_list('["a","f","c"]')) -> {"a":1,"f":6,"c":3}
|
||||||
|
function keep(p_json pljson, p_keys pljson_list) return pljson;
|
||||||
|
|
||||||
|
-- remove specific keys in json object
|
||||||
|
-- json_helper.remove(json('{a:1,b:2,c:3,d:4,e:5,f:6}'),json_list('["a","f","c"]')) -> {"b":2,"d":4,"e":5}
|
||||||
|
function remove(p_json pljson, p_keys pljson_list) return pljson;
|
||||||
|
|
||||||
|
--equals
|
||||||
|
function equals(p_v1 pljson_element, p_v2 pljson_element, exact boolean default true) return boolean;
|
||||||
|
function equals(p_v1 pljson_element, p_v2 pljson, exact boolean default true) return boolean;
|
||||||
|
function equals(p_v1 pljson_element, p_v2 pljson_list, exact boolean default true) return boolean;
|
||||||
|
function equals(p_v1 pljson_element, p_v2 number) return boolean;
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
|
||||||
|
function equals(p_v1 pljson_element, p_v2 binary_double) return boolean;
|
||||||
|
function equals(p_v1 pljson_element, p_v2 varchar2) return boolean;
|
||||||
|
function equals(p_v1 pljson_element, p_v2 boolean) return boolean;
|
||||||
|
function equals(p_v1 pljson_element, p_v2 clob) return boolean;
|
||||||
|
function equals(p_v1 pljson, p_v2 pljson, exact boolean default true) return boolean;
|
||||||
|
function equals(p_v1 pljson_list, p_v2 pljson_list, exact boolean default true) return boolean;
|
||||||
|
|
||||||
|
--contains json, json_value
|
||||||
|
--contains json_list, json_value
|
||||||
|
function contains(p_v1 pljson, p_v2 pljson_element, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson, p_v2 pljson, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson, p_v2 pljson_list, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson, p_v2 number, exact boolean default false) return boolean;
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
|
||||||
|
function contains(p_v1 pljson, p_v2 binary_double, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson, p_v2 varchar2, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson, p_v2 boolean, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson, p_v2 clob, exact boolean default false) return boolean;
|
||||||
|
|
||||||
|
function contains(p_v1 pljson_list, p_v2 pljson_element, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 pljson, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 pljson_list, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 number, exact boolean default false) return boolean;
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
|
||||||
|
function contains(p_v1 pljson_list, p_v2 binary_double, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 varchar2, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 boolean, exact boolean default false) return boolean;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 clob, exact boolean default false) return boolean;
|
||||||
|
|
||||||
|
end pljson_helper;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package body pljson_helper as
|
||||||
|
|
||||||
|
--recursive merge
|
||||||
|
function merge(p_a_json pljson, p_b_json pljson) return pljson as
|
||||||
|
l_json pljson;
|
||||||
|
l_jv pljson_element;
|
||||||
|
l_indx number;
|
||||||
|
l_recursive pljson_element;
|
||||||
|
begin
|
||||||
|
--
|
||||||
|
-- Initialize our return object
|
||||||
|
--
|
||||||
|
l_json := p_a_json;
|
||||||
|
|
||||||
|
-- loop through p_b_json
|
||||||
|
l_indx := p_b_json.json_data.first;
|
||||||
|
loop
|
||||||
|
exit when l_indx is null;
|
||||||
|
l_jv := p_b_json.json_data(l_indx);
|
||||||
|
if (l_jv.is_object) then
|
||||||
|
--recursive
|
||||||
|
l_recursive := l_json.get(l_jv.mapname);
|
||||||
|
if (l_recursive is not null and l_recursive.is_object) then
|
||||||
|
l_json.put(l_jv.mapname, merge(pljson(l_recursive), pljson(l_jv)));
|
||||||
|
else
|
||||||
|
l_json.put(l_jv.mapname, l_jv);
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
l_json.put(l_jv.mapname, l_jv);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
--increment
|
||||||
|
l_indx := p_b_json.json_data.next(l_indx);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return l_json;
|
||||||
|
|
||||||
|
end merge;
|
||||||
|
|
||||||
|
-- join two lists
|
||||||
|
function join(p_a_list pljson_list, p_b_list pljson_list) return pljson_list as
|
||||||
|
l_json_list pljson_list := p_a_list;
|
||||||
|
begin
|
||||||
|
for indx in 1 .. p_b_list.count loop
|
||||||
|
l_json_list.append(p_b_list.get(indx));
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return l_json_list;
|
||||||
|
|
||||||
|
end join;
|
||||||
|
|
||||||
|
-- keep keys.
|
||||||
|
function keep(p_json pljson, p_keys pljson_list) return pljson as
|
||||||
|
l_json pljson := pljson();
|
||||||
|
mapname varchar2(4000);
|
||||||
|
begin
|
||||||
|
for i in 1 .. p_keys.count loop
|
||||||
|
mapname := p_keys.get(i).get_string();
|
||||||
|
if (p_json.exist(mapname)) then
|
||||||
|
l_json.put(mapname, p_json.get(mapname));
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return l_json;
|
||||||
|
end keep;
|
||||||
|
|
||||||
|
-- drop keys.
|
||||||
|
function remove(p_json pljson, p_keys pljson_list) return pljson as
|
||||||
|
l_json pljson := p_json;
|
||||||
|
begin
|
||||||
|
for i in 1 .. p_keys.count loop
|
||||||
|
l_json.remove(p_keys.get(i).get_string());
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return l_json;
|
||||||
|
end remove;
|
||||||
|
|
||||||
|
--equals functions
|
||||||
|
|
||||||
|
function equals(p_v1 pljson_element, p_v2 number) return boolean as
|
||||||
|
begin
|
||||||
|
if (p_v2 is null) then
|
||||||
|
return p_v1.is_null;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (not p_v1.is_number) then
|
||||||
|
return false;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return p_v2 = p_v1.get_number();
|
||||||
|
end;
|
||||||
|
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
|
||||||
|
function equals(p_v1 pljson_element, p_v2 binary_double) return boolean as
|
||||||
|
begin
|
||||||
|
if (p_v2 is null) then
|
||||||
|
return p_v1.is_null;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (not p_v1.is_number) then
|
||||||
|
return false;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return p_v2 = p_v1.get_double();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function equals(p_v1 pljson_element, p_v2 boolean) return boolean as
|
||||||
|
begin
|
||||||
|
if (p_v2 is null) then
|
||||||
|
return p_v1.is_null;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (not p_v1.is_bool) then
|
||||||
|
return false;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return p_v2 = p_v1.get_bool();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function equals(p_v1 pljson_element, p_v2 varchar2) return boolean as
|
||||||
|
begin
|
||||||
|
if (p_v2 is null) then
|
||||||
|
return (p_v1.is_null or p_v1.get_string() is null);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (not p_v1.is_string) then
|
||||||
|
return false;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return p_v2 = p_v1.get_string();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function equals(p_v1 pljson_element, p_v2 clob) return boolean as
|
||||||
|
my_clob clob;
|
||||||
|
res boolean;
|
||||||
|
begin
|
||||||
|
if (p_v2 is null) then
|
||||||
|
return p_v1.is_null;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (not p_v1.is_string) then
|
||||||
|
return false;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
/*
|
||||||
|
my_clob := empty_clob();
|
||||||
|
dbms_lob.createtemporary(my_clob, true);
|
||||||
|
p_v1.get_string(my_clob);
|
||||||
|
*/
|
||||||
|
my_clob := p_v1.get_clob();
|
||||||
|
res := dbms_lob.compare(p_v2, my_clob) = 0;
|
||||||
|
/*dbms_lob.freetemporary(my_clob);*/
|
||||||
|
return res;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function equals(p_v1 pljson_element, p_v2 pljson_element, exact boolean) return boolean as
|
||||||
|
begin
|
||||||
|
if (p_v2 is null or p_v2.is_null) then
|
||||||
|
return (p_v1 is null or p_v1.is_null);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (p_v2.is_number) then return equals(p_v1, p_v2.get_number); end if;
|
||||||
|
if (p_v2.is_bool) then return equals(p_v1, p_v2.get_bool); end if;
|
||||||
|
if (p_v2.is_object) then return equals(p_v1, pljson(p_v2), exact); end if;
|
||||||
|
if (p_v2.is_array) then return equals(p_v1, pljson_list(p_v2), exact); end if;
|
||||||
|
if (p_v2.is_string) then
|
||||||
|
if (treat(p_v2 as pljson_string).extended_str is null) then
|
||||||
|
return equals(p_v1, p_v2.get_string);
|
||||||
|
else
|
||||||
|
declare
|
||||||
|
my_clob clob; res boolean;
|
||||||
|
begin
|
||||||
|
/*
|
||||||
|
my_clob := empty_clob();
|
||||||
|
dbms_lob.createtemporary(my_clob, true);
|
||||||
|
p_v2.get_string(my_clob);
|
||||||
|
*/
|
||||||
|
my_clob := p_v2.get_clob();
|
||||||
|
res := equals(p_v1, my_clob);
|
||||||
|
/*dbms_lob.freetemporary(my_clob);*/
|
||||||
|
return res;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return false; --should never happen
|
||||||
|
end;
|
||||||
|
|
||||||
|
function equals(p_v1 pljson_element, p_v2 pljson_list, exact boolean) return boolean as
|
||||||
|
cmp pljson_list;
|
||||||
|
res boolean := true;
|
||||||
|
begin
|
||||||
|
-- p_v1.print(false);
|
||||||
|
-- p_v2.print(false);
|
||||||
|
-- dbms_output.put_line('labc1'||case when exact then 'X' else 'U' end);
|
||||||
|
|
||||||
|
if (p_v2 is null) then
|
||||||
|
return p_v1.is_null;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (not p_v1.is_array) then
|
||||||
|
return false;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- dbms_output.put_line('labc2'||case when exact then 'X' else 'U' end);
|
||||||
|
|
||||||
|
cmp := pljson_list(p_v1);
|
||||||
|
if (cmp.count != p_v2.count and exact) then return false; end if;
|
||||||
|
|
||||||
|
-- dbms_output.put_line('labc3'||case when exact then 'X' else 'U' end);
|
||||||
|
|
||||||
|
if (exact) then
|
||||||
|
for i in 1 .. cmp.count loop
|
||||||
|
res := equals(cmp.get(i), p_v2.get(i), exact);
|
||||||
|
if (not res) then return res; end if;
|
||||||
|
end loop;
|
||||||
|
else
|
||||||
|
-- dbms_output.put_line('labc4'||case when exact then 'X' else 'U' end);
|
||||||
|
if (p_v2.count > cmp.count) then return false; end if;
|
||||||
|
-- dbms_output.put_line('labc5'||case when exact then 'X' else 'U' end);
|
||||||
|
|
||||||
|
--match sublist here!
|
||||||
|
for x in 0 .. (cmp.count-p_v2.count) loop
|
||||||
|
-- dbms_output.put_line('labc7'||x);
|
||||||
|
|
||||||
|
for i in 1 .. p_v2.count loop
|
||||||
|
res := equals(cmp.get(x+i), p_v2.get(i), exact);
|
||||||
|
if (not res) then
|
||||||
|
goto next_index;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
<<next_index>>
|
||||||
|
null;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
-- dbms_output.put_line('labc7'||case when exact then 'X' else 'U' end);
|
||||||
|
|
||||||
|
return false; --no match
|
||||||
|
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function equals(p_v1 pljson_element, p_v2 pljson, exact boolean) return boolean as
|
||||||
|
cmp pljson;
|
||||||
|
res boolean := true;
|
||||||
|
begin
|
||||||
|
-- p_v1.print(false);
|
||||||
|
-- p_v2.print(false);
|
||||||
|
-- dbms_output.put_line('abc1');
|
||||||
|
|
||||||
|
if (p_v2 is null) then
|
||||||
|
return p_v1.is_null;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (not p_v1.is_object) then
|
||||||
|
return false;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
cmp := pljson(p_v1);
|
||||||
|
|
||||||
|
-- dbms_output.put_line('abc2');
|
||||||
|
|
||||||
|
if (cmp.count != p_v2.count and exact) then return false; end if;
|
||||||
|
|
||||||
|
-- dbms_output.put_line('abc3');
|
||||||
|
declare
|
||||||
|
k1 pljson_list := p_v2.get_keys();
|
||||||
|
key_index number;
|
||||||
|
begin
|
||||||
|
for i in 1 .. k1.count loop
|
||||||
|
key_index := cmp.index_of(k1.get(i).get_string());
|
||||||
|
if (key_index = -1) then return false; end if;
|
||||||
|
if (exact) then
|
||||||
|
if (not equals(p_v2.get(i), cmp.get(key_index), true)) then return false; end if;
|
||||||
|
else
|
||||||
|
--non exact
|
||||||
|
declare
|
||||||
|
v1 pljson_element := cmp.get(key_index);
|
||||||
|
v2 pljson_element := p_v2.get(i);
|
||||||
|
begin
|
||||||
|
-- dbms_output.put_line('abc3 1/2');
|
||||||
|
-- v1.print(false);
|
||||||
|
-- v2.print(false);
|
||||||
|
|
||||||
|
if (v1.is_object and v2.is_object) then
|
||||||
|
if (not equals(v1, v2, false)) then return false; end if;
|
||||||
|
elsif (v1.is_array and v2.is_array) then
|
||||||
|
if (not equals(v1, v2, false)) then return false; end if;
|
||||||
|
else
|
||||||
|
if (not equals(v1, v2, true)) then return false; end if;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
|
||||||
|
-- dbms_output.put_line('abc4');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function equals(p_v1 pljson, p_v2 pljson, exact boolean) return boolean as
|
||||||
|
begin
|
||||||
|
return equals(p_v1, p_v2, exact);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function equals(p_v1 pljson_list, p_v2 pljson_list, exact boolean) return boolean as
|
||||||
|
begin
|
||||||
|
return equals(p_v1, p_v2, exact);
|
||||||
|
end;
|
||||||
|
|
||||||
|
--contain
|
||||||
|
function contains(p_v1 pljson, p_v2 pljson_element, exact boolean) return boolean as
|
||||||
|
v_values pljson_list;
|
||||||
|
begin
|
||||||
|
if (equals(p_v1, p_v2, exact)) then return true; end if;
|
||||||
|
|
||||||
|
v_values := p_v1.get_values();
|
||||||
|
|
||||||
|
for i in 1 .. v_values.count loop
|
||||||
|
declare
|
||||||
|
v_val pljson_element := v_values.get(i);
|
||||||
|
begin
|
||||||
|
if (v_val.is_object) then
|
||||||
|
if (contains(pljson(v_val), p_v2, exact)) then return true; end if;
|
||||||
|
end if;
|
||||||
|
if (v_val.is_array) then
|
||||||
|
if (contains(pljson_list(v_val), p_v2, exact)) then return true; end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (equals(v_val, p_v2, exact)) then return true; end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function contains(p_v1 pljson_list, p_v2 pljson_element, exact boolean) return boolean as
|
||||||
|
begin
|
||||||
|
if (equals(p_v1, p_v2, exact)) then return true; end if;
|
||||||
|
|
||||||
|
for i in 1 .. p_v1.count loop
|
||||||
|
declare
|
||||||
|
v_val pljson_element := p_v1.get(i);
|
||||||
|
begin
|
||||||
|
if (v_val.is_object) then
|
||||||
|
if (contains(pljson(v_val), p_v2, exact)) then return true; end if;
|
||||||
|
end if;
|
||||||
|
if (v_val.is_array) then
|
||||||
|
if (contains(pljson_list(v_val), p_v2, exact)) then return true; end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (equals(v_val, p_v2, exact)) then return true; end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function contains(p_v1 pljson, p_v2 pljson, exact boolean ) return boolean as
|
||||||
|
begin return contains(p_v1, p_v2, exact); end;
|
||||||
|
function contains(p_v1 pljson, p_v2 pljson_list, exact boolean ) return boolean as
|
||||||
|
begin return contains(p_v1, p_v2, exact); end;
|
||||||
|
function contains(p_v1 pljson, p_v2 number, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, pljson_number(p_v2), exact); end;
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
|
||||||
|
function contains(p_v1 pljson, p_v2 binary_double, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, pljson_number(p_v2), exact); end;
|
||||||
|
function contains(p_v1 pljson, p_v2 varchar2, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, pljson_string(p_v2), exact); end;
|
||||||
|
function contains(p_v1 pljson, p_v2 boolean, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, pljson_bool(p_v2), exact); end;
|
||||||
|
function contains(p_v1 pljson, p_v2 clob, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, pljson_string(p_v2), exact); end;
|
||||||
|
|
||||||
|
function contains(p_v1 pljson_list, p_v2 pljson, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, p_v2, exact); end;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 pljson_list, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, p_v2, exact); end;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 number, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, pljson_number(p_v2), exact); end;
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
|
||||||
|
function contains(p_v1 pljson_list, p_v2 binary_double, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, pljson_number(p_v2), exact); end;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 varchar2, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, pljson_string(p_v2), exact); end;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 boolean, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, pljson_bool(p_v2), exact); end;
|
||||||
|
function contains(p_v1 pljson_list, p_v2 clob, exact boolean ) return boolean as begin
|
||||||
|
return contains(p_v1, pljson_string(p_v2), exact); end;
|
||||||
|
|
||||||
|
|
||||||
|
end pljson_helper;```
|
||||||
310
docs/packages/PLJSON_ML.md
Normal file
310
docs/packages/PLJSON_ML.md
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
# PLJSON_ML
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package pljson_ml as
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Jonas Krogsboell
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This package contains extra methods to lookup types and
|
||||||
|
an easy way of adding date values in json - without changing the structure */
|
||||||
|
|
||||||
|
jsonml_stylesheet xmltype := null;
|
||||||
|
|
||||||
|
function xml2json(xml in xmltype) return pljson_list;
|
||||||
|
function xmlstr2json(xmlstr in varchar2) return pljson_list;
|
||||||
|
|
||||||
|
end pljson_ml;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package body pljson_ml as
|
||||||
|
function get_jsonml_stylesheet return xmltype;
|
||||||
|
|
||||||
|
function xml2json(xml in xmltype) return pljson_list as
|
||||||
|
l_json xmltype;
|
||||||
|
l_returnvalue clob;
|
||||||
|
begin
|
||||||
|
l_json := xml.transform (get_jsonml_stylesheet);
|
||||||
|
l_returnvalue := l_json.getclobval();
|
||||||
|
l_returnvalue := dbms_xmlgen.convert (l_returnvalue, dbms_xmlgen.entity_decode);
|
||||||
|
--dbms_output.put_line(l_returnvalue);
|
||||||
|
return pljson_list(l_returnvalue);
|
||||||
|
end xml2json;
|
||||||
|
|
||||||
|
function xmlstr2json(xmlstr in varchar2) return pljson_list as
|
||||||
|
begin
|
||||||
|
return xml2json(xmltype(xmlstr));
|
||||||
|
end xmlstr2json;
|
||||||
|
|
||||||
|
function get_jsonml_stylesheet return xmltype as
|
||||||
|
begin
|
||||||
|
if (jsonml_stylesheet is null) then
|
||||||
|
jsonml_stylesheet := xmltype('<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
JsonML.xslt
|
||||||
|
|
||||||
|
Created: 2006-11-15-0551
|
||||||
|
Modified: 2009-02-14-0927
|
||||||
|
|
||||||
|
Released under an open-source license:
|
||||||
|
http://jsonml.org/License.htm
|
||||||
|
|
||||||
|
This transformation converts any XML document into JsonML.
|
||||||
|
It omits processing-instructions and comment-nodes.
|
||||||
|
|
||||||
|
To enable comment-nodes to be emitted as JavaScript comments,
|
||||||
|
uncomment the Comment() template.
|
||||||
|
-->
|
||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||||
|
|
||||||
|
<xsl:output method="text"
|
||||||
|
media-type="application/json"
|
||||||
|
encoding="UTF-8"
|
||||||
|
indent="no"
|
||||||
|
omit-xml-declaration="yes" />
|
||||||
|
|
||||||
|
<!-- constants -->
|
||||||
|
<xsl:variable name="XHTML"
|
||||||
|
select="''http://www.w3.org/1999/xhtml''" />
|
||||||
|
|
||||||
|
<xsl:variable name="START_ELEM"
|
||||||
|
select="''[''" />
|
||||||
|
|
||||||
|
<xsl:variable name="END_ELEM"
|
||||||
|
select="'']''" />
|
||||||
|
|
||||||
|
<xsl:variable name="VALUE_DELIM"
|
||||||
|
select="'',''" />
|
||||||
|
|
||||||
|
<xsl:variable name="START_ATTRIB"
|
||||||
|
select="''{''" />
|
||||||
|
|
||||||
|
<xsl:variable name="END_ATTRIB"
|
||||||
|
select="''}''" />
|
||||||
|
|
||||||
|
<xsl:variable name="NAME_DELIM"
|
||||||
|
select="'':''" />
|
||||||
|
|
||||||
|
<xsl:variable name="STRING_DELIM"
|
||||||
|
select="''"''" />
|
||||||
|
|
||||||
|
<xsl:variable name="START_COMMENT"
|
||||||
|
select="''/*''" />
|
||||||
|
|
||||||
|
<xsl:variable name="END_COMMENT"
|
||||||
|
select="''*/''" />
|
||||||
|
|
||||||
|
<!-- root-node -->
|
||||||
|
<xsl:template match="/">
|
||||||
|
<xsl:apply-templates select="*" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- comments -->
|
||||||
|
<xsl:template match="comment()">
|
||||||
|
<!-- uncomment to support JSON comments -->
|
||||||
|
<!--
|
||||||
|
<xsl:value-of select="$START_COMMENT" />
|
||||||
|
|
||||||
|
<xsl:value-of select="."
|
||||||
|
disable-output-escaping="yes" />
|
||||||
|
|
||||||
|
<xsl:value-of select="$END_COMMENT" />
|
||||||
|
-->
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- elements -->
|
||||||
|
<xsl:template match="*">
|
||||||
|
<xsl:value-of select="$START_ELEM" />
|
||||||
|
|
||||||
|
<!-- tag-name string -->
|
||||||
|
<xsl:value-of select="$STRING_DELIM" />
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="namespace-uri()=$XHTML">
|
||||||
|
<xsl:value-of select="local-name()" />
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:value-of select="name()" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
<xsl:value-of select="$STRING_DELIM" />
|
||||||
|
|
||||||
|
<!-- attribute object -->
|
||||||
|
<xsl:if test="count(@*)>0">
|
||||||
|
<xsl:value-of select="$VALUE_DELIM" />
|
||||||
|
<xsl:value-of select="$START_ATTRIB" />
|
||||||
|
<xsl:for-each select="@*">
|
||||||
|
<xsl:if test="position()>1">
|
||||||
|
<xsl:value-of select="$VALUE_DELIM" />
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:apply-templates select="." />
|
||||||
|
</xsl:for-each>
|
||||||
|
<xsl:value-of select="$END_ATTRIB" />
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<!-- child elements and text-nodes -->
|
||||||
|
<xsl:for-each select="*|text()">
|
||||||
|
<xsl:value-of select="$VALUE_DELIM" />
|
||||||
|
<xsl:apply-templates select="." />
|
||||||
|
</xsl:for-each>
|
||||||
|
|
||||||
|
<xsl:value-of select="$END_ELEM" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- text-nodes -->
|
||||||
|
<xsl:template match="text()">
|
||||||
|
<xsl:call-template name="escape-string">
|
||||||
|
<xsl:with-param name="value"
|
||||||
|
select="." />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- attributes -->
|
||||||
|
<xsl:template match="@*">
|
||||||
|
<xsl:value-of select="$STRING_DELIM" />
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="namespace-uri()=$XHTML">
|
||||||
|
<xsl:value-of select="local-name()" />
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:value-of select="name()" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
<xsl:value-of select="$STRING_DELIM" />
|
||||||
|
|
||||||
|
<xsl:value-of select="$NAME_DELIM" />
|
||||||
|
|
||||||
|
<xsl:call-template name="escape-string">
|
||||||
|
<xsl:with-param name="value"
|
||||||
|
select="." />
|
||||||
|
</xsl:call-template>
|
||||||
|
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- escape-string: quotes and escapes -->
|
||||||
|
<xsl:template name="escape-string">
|
||||||
|
<xsl:param name="value" />
|
||||||
|
|
||||||
|
<xsl:value-of select="$STRING_DELIM" />
|
||||||
|
|
||||||
|
<xsl:if test="string-length($value)>0">
|
||||||
|
<xsl:variable name="escaped-whacks">
|
||||||
|
<!-- escape backslashes -->
|
||||||
|
<xsl:call-template name="string-replace">
|
||||||
|
<xsl:with-param name="value"
|
||||||
|
select="$value" />
|
||||||
|
<xsl:with-param name="find"
|
||||||
|
select="''\''" />
|
||||||
|
<xsl:with-param name="replace"
|
||||||
|
select="''\\''" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:variable name="escaped-LF">
|
||||||
|
<!-- escape line feeds -->
|
||||||
|
<xsl:call-template name="string-replace">
|
||||||
|
<xsl:with-param name="value"
|
||||||
|
select="$escaped-whacks" />
|
||||||
|
<xsl:with-param name="find"
|
||||||
|
select="''
''" />
|
||||||
|
<xsl:with-param name="replace"
|
||||||
|
select="''\n''" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:variable name="escaped-CR">
|
||||||
|
<!-- escape carriage returns -->
|
||||||
|
<xsl:call-template name="string-replace">
|
||||||
|
<xsl:with-param name="value"
|
||||||
|
select="$escaped-LF" />
|
||||||
|
<xsl:with-param name="find"
|
||||||
|
select="''
''" />
|
||||||
|
<xsl:with-param name="replace"
|
||||||
|
select="''\r''" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:variable name="escaped-tabs">
|
||||||
|
<!-- escape tabs -->
|
||||||
|
<xsl:call-template name="string-replace">
|
||||||
|
<xsl:with-param name="value"
|
||||||
|
select="$escaped-CR" />
|
||||||
|
<xsl:with-param name="find"
|
||||||
|
select="''	''" />
|
||||||
|
<xsl:with-param name="replace"
|
||||||
|
select="''\t''" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:variable>
|
||||||
|
|
||||||
|
<!-- escape quotes -->
|
||||||
|
<xsl:call-template name="string-replace">
|
||||||
|
<xsl:with-param name="value"
|
||||||
|
select="$escaped-tabs" />
|
||||||
|
<xsl:with-param name="find"
|
||||||
|
select="''"''" />
|
||||||
|
<xsl:with-param name="replace"
|
||||||
|
select="''\"''" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
|
||||||
|
<xsl:value-of select="$STRING_DELIM" />
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- string-replace: replaces occurances of one string with another -->
|
||||||
|
<xsl:template name="string-replace">
|
||||||
|
<xsl:param name="value" />
|
||||||
|
<xsl:param name="find" />
|
||||||
|
<xsl:param name="replace" />
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="contains($value,$find)">
|
||||||
|
<!-- replace and call recursively on next -->
|
||||||
|
<xsl:value-of select="substring-before($value,$find)"
|
||||||
|
disable-output-escaping="yes" />
|
||||||
|
<xsl:value-of select="$replace"
|
||||||
|
disable-output-escaping="yes" />
|
||||||
|
<xsl:call-template name="string-replace">
|
||||||
|
<xsl:with-param name="value"
|
||||||
|
select="substring-after($value,$find)" />
|
||||||
|
<xsl:with-param name="find"
|
||||||
|
select="$find" />
|
||||||
|
<xsl:with-param name="replace"
|
||||||
|
select="$replace" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<!-- no replacement necessary -->
|
||||||
|
<xsl:value-of select="$value"
|
||||||
|
disable-output-escaping="yes" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>');
|
||||||
|
end if;
|
||||||
|
return jsonml_stylesheet;
|
||||||
|
end get_jsonml_stylesheet;
|
||||||
|
|
||||||
|
end pljson_ml;```
|
||||||
171
docs/packages/PLJSON_OBJECT_CACHE.md
Normal file
171
docs/packages/PLJSON_OBJECT_CACHE.md
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
# PLJSON_OBJECT_CACHE
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package pljson_object_cache as
|
||||||
|
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2020-04-18 object cache to speed up internal operations */
|
||||||
|
|
||||||
|
/* !!! NOTE: this package is used internally by pljson and it's not part of the api !!! */
|
||||||
|
|
||||||
|
/* index by string of "id.path" or "path" */
|
||||||
|
type pljson_element_tab is table of pljson_element index by varchar2(250);
|
||||||
|
|
||||||
|
last_id number := 0;
|
||||||
|
pljson_element_cache pljson_element_tab;
|
||||||
|
cache_reqs number := 0;
|
||||||
|
cache_hits number := 0;
|
||||||
|
cache_invalid_reqs number := 0;
|
||||||
|
|
||||||
|
type vset is table of varchar2(1) index by varchar2(250);
|
||||||
|
names_set vset;
|
||||||
|
|
||||||
|
procedure set_names_set(names pljson_varray);
|
||||||
|
function in_names_set(a_name varchar2) return boolean;
|
||||||
|
|
||||||
|
procedure reset;
|
||||||
|
procedure flush;
|
||||||
|
procedure print_stats;
|
||||||
|
function next_id return number;
|
||||||
|
function object_key(elem pljson_element, piece varchar2) return varchar2;
|
||||||
|
function get(key varchar2) return pljson_element;
|
||||||
|
procedure set(key varchar2, val pljson_element);
|
||||||
|
end;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package body pljson_object_cache as
|
||||||
|
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2020-04-18 object cache to speed up internal operations */
|
||||||
|
|
||||||
|
/* !!! NOTE: this package is used internally by pljson and it's not part of the api !!! */
|
||||||
|
|
||||||
|
procedure set_names_set(names pljson_varray) is
|
||||||
|
begin
|
||||||
|
if names.COUNT = 0 then
|
||||||
|
return;
|
||||||
|
end if;
|
||||||
|
for i in names.FIRST .. names.LAST loop
|
||||||
|
names_set(names(i)) := '1';
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function in_names_set(a_name varchar2) return boolean is
|
||||||
|
begin
|
||||||
|
if names_set.exists(a_name) then
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure reset is
|
||||||
|
begin
|
||||||
|
last_id := 0;
|
||||||
|
flush;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure flush is
|
||||||
|
begin
|
||||||
|
pljson_element_cache.delete;
|
||||||
|
cache_reqs := 0;
|
||||||
|
cache_hits := 0;
|
||||||
|
cache_invalid_reqs := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure print_stats is
|
||||||
|
begin
|
||||||
|
dbms_output.put_line('reqs = ' || cache_reqs);
|
||||||
|
dbms_output.put_line('hits = ' || cache_hits);
|
||||||
|
dbms_output.put_line('invalid reqs = ' || cache_invalid_reqs);
|
||||||
|
dbms_output.put_line('cache count = ' || pljson_element_cache.count);
|
||||||
|
dbms_output.put_line('id count = ' || last_id);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function next_id return number is
|
||||||
|
begin
|
||||||
|
last_id := last_id + 1;
|
||||||
|
return last_id;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function object_key(elem pljson_element, piece varchar2) return varchar2 is
|
||||||
|
key varchar2(250);
|
||||||
|
begin
|
||||||
|
if elem.object_id is null or elem.object_id = 0 then
|
||||||
|
cache_invalid_reqs := cache_invalid_reqs + 1;
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
key := to_char(elem.object_id)||'.'||piece;
|
||||||
|
return key;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function get(key varchar2) return pljson_element is
|
||||||
|
cache_key varchar2(32767);
|
||||||
|
begin
|
||||||
|
cache_key := key;
|
||||||
|
if cache_key is null then
|
||||||
|
cache_key := '$';
|
||||||
|
end if;
|
||||||
|
cache_reqs := cache_reqs + 1;
|
||||||
|
if pljson_element_cache.exists(cache_key) then
|
||||||
|
cache_hits := cache_hits + 1;
|
||||||
|
return pljson_element_cache(cache_key);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure set(key varchar2, val pljson_element) is
|
||||||
|
cache_key varchar2(32767);
|
||||||
|
begin
|
||||||
|
cache_key := key;
|
||||||
|
if cache_key is null then
|
||||||
|
cache_key := '$';
|
||||||
|
end if;
|
||||||
|
--dbms_output.put_line('caching: ' || cache_key);
|
||||||
|
pljson_element_cache(cache_key) := val;
|
||||||
|
end;
|
||||||
|
|
||||||
|
/*
|
||||||
|
-- experimental, ignore
|
||||||
|
-- to use with 'get_json_element'
|
||||||
|
|
||||||
|
function get_piece(elem pljson, piece varchar2) return pljson_element is
|
||||||
|
key varchar2(250);
|
||||||
|
val pljson_element;
|
||||||
|
begin
|
||||||
|
key := object_cache.object_key(elem, piece);
|
||||||
|
if key is null then
|
||||||
|
return elem.get(piece);
|
||||||
|
end if;
|
||||||
|
val := object_cache.get(key);
|
||||||
|
if val is not null then
|
||||||
|
return val;
|
||||||
|
else
|
||||||
|
val := elem.get(piece);
|
||||||
|
object_cache.set(key, val);
|
||||||
|
return val;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function get_piece(elem pljson_list, piece varchar2) return pljson_element is
|
||||||
|
key varchar2(250);
|
||||||
|
val pljson_element;
|
||||||
|
begin
|
||||||
|
key := object_cache.object_key(elem, piece);
|
||||||
|
if key is null then
|
||||||
|
return elem.get(piece);
|
||||||
|
end if;
|
||||||
|
val := object_cache.get(key);
|
||||||
|
if val is not null then
|
||||||
|
return val;
|
||||||
|
else
|
||||||
|
val := elem.get(piece);
|
||||||
|
object_cache.set(key, val);
|
||||||
|
return val;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
*/
|
||||||
|
end;```
|
||||||
986
docs/packages/PLJSON_PARSER.md
Normal file
986
docs/packages/PLJSON_PARSER.md
Normal file
@@ -0,0 +1,986 @@
|
|||||||
|
# PLJSON_PARSER
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package pljson_parser as
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Jonas Krogsboell
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Internal type for processing. */
|
||||||
|
/* scanner tokens:
|
||||||
|
'{', '}', ',', ':', '[', ']', STRING, NUMBER, TRUE, FALSE, NULL
|
||||||
|
*/
|
||||||
|
type rToken IS RECORD (
|
||||||
|
type_name VARCHAR2(7),
|
||||||
|
line PLS_INTEGER,
|
||||||
|
col PLS_INTEGER,
|
||||||
|
data VARCHAR2(32767),
|
||||||
|
data_overflow clob); -- max_string_size
|
||||||
|
|
||||||
|
type lTokens is table of rToken index by pls_integer;
|
||||||
|
type json_src is record (len number, offset number, offset_chars number, src varchar2(32767), s_clob clob);
|
||||||
|
|
||||||
|
json_strict boolean not null := false;
|
||||||
|
|
||||||
|
ucs2_exception EXCEPTION;
|
||||||
|
pragma exception_init(ucs2_exception, -22831);
|
||||||
|
|
||||||
|
function lengthcc(buf clob) return number;
|
||||||
|
|
||||||
|
function next_char(indx number, s in out nocopy json_src) return varchar2;
|
||||||
|
function next_char2(indx number, s in out nocopy json_src, amount number default 1) return varchar2;
|
||||||
|
function parseObj(tokens lTokens, indx in out nocopy pls_integer) return pljson;
|
||||||
|
|
||||||
|
function prepareClob(buf in clob) return pljson_parser.json_src;
|
||||||
|
function prepareVarchar2(buf in varchar2) return pljson_parser.json_src;
|
||||||
|
function lexer(jsrc in out nocopy json_src) return lTokens;
|
||||||
|
procedure print_token(t rToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Primary parsing method. It can parse a JSON object.</p>
|
||||||
|
*
|
||||||
|
* @return An instance of <code>pljson</code>.
|
||||||
|
* @throws PARSER_ERROR -20101 when invalid input found.
|
||||||
|
* @throws SCANNER_ERROR -20100 when lexing fails.
|
||||||
|
*/
|
||||||
|
function parser(str varchar2) return pljson;
|
||||||
|
function parse_list(str varchar2) return pljson_list;
|
||||||
|
function parse_any(str varchar2) return pljson_element;
|
||||||
|
function parser(str clob) return pljson;
|
||||||
|
function parse_list(str clob) return pljson_list;
|
||||||
|
function parse_any(str clob) return pljson_element;
|
||||||
|
procedure remove_duplicates(obj in out nocopy pljson);
|
||||||
|
function get_version return varchar2;
|
||||||
|
|
||||||
|
end pljson_parser;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package body pljson_parser as
|
||||||
|
/*
|
||||||
|
Copyright (c) 2009 Jonas Krogsboell
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
decimalpoint varchar2(1 char) := '.';
|
||||||
|
|
||||||
|
/* moved to package spec
|
||||||
|
ucs2_exception EXCEPTION;
|
||||||
|
pragma exception_init(ucs2_exception, -22831);
|
||||||
|
*/
|
||||||
|
|
||||||
|
function lengthcc(buf clob) return number as
|
||||||
|
offset number := 0;
|
||||||
|
len number := 0;
|
||||||
|
src varchar2(32767);
|
||||||
|
src_len number;
|
||||||
|
begin
|
||||||
|
while true loop
|
||||||
|
begin
|
||||||
|
src := dbms_lob.substr(buf, 4000, offset+1);
|
||||||
|
exception
|
||||||
|
when ucs2_exception then
|
||||||
|
src := dbms_lob.substr(buf, 3999, offset+1);
|
||||||
|
end;
|
||||||
|
exit when src is null;
|
||||||
|
len := len + length(src);
|
||||||
|
offset := offset + length2(src);
|
||||||
|
--dbms_output.put_line('offset = ' || offset || ' len = ' || len);
|
||||||
|
end loop;
|
||||||
|
return len;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure update_decimalpoint as
|
||||||
|
begin
|
||||||
|
select substr(value, 1, 1)
|
||||||
|
into decimalpoint
|
||||||
|
from nls_session_parameters
|
||||||
|
where parameter = 'NLS_NUMERIC_CHARACTERS';
|
||||||
|
end update_decimalpoint;
|
||||||
|
|
||||||
|
/* type json_src is record (len number, offset number, src varchar2(32767), s_clob clob); */
|
||||||
|
/* assertions
|
||||||
|
offset: contains 0-base offset of buffer,
|
||||||
|
so 1-st entry is offset + 1, 4000-th entry = offset + 4000
|
||||||
|
src: contains offset + 1 .. offset + 4000, ex. 1..4000, 4001..8000, etc.
|
||||||
|
*/
|
||||||
|
function next_char(indx number, s in out nocopy json_src) return varchar2 as
|
||||||
|
begin
|
||||||
|
if (indx > s.len) then return null; end if;
|
||||||
|
|
||||||
|
--right offset?
|
||||||
|
/* if (indx > 4000 + s.offset or indx < s.offset) then */
|
||||||
|
/* fix for issue #37 */
|
||||||
|
/* code before fix for issue #169
|
||||||
|
if (indx > 4000 + s.offset or indx <= s.offset) then
|
||||||
|
s.offset := indx - (indx mod 4000);
|
||||||
|
-- addon fix for issue #37
|
||||||
|
if s.offset = indx then
|
||||||
|
s.offset := s.offset - 4000;
|
||||||
|
end if;
|
||||||
|
s.src := dbms_lob.substr(s.s_clob, 4000, s.offset+1);
|
||||||
|
end if;
|
||||||
|
--read from s.src
|
||||||
|
return substr(s.src, indx-s.offset, 1);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* use of length, so works correctly for 4-byte unicode characters (issue #169) */
|
||||||
|
/* lengthc does not work (issue #190) */
|
||||||
|
if (indx > length(s.src) + s.offset_chars) then
|
||||||
|
while (indx > length(s.src) + s.offset_chars) loop
|
||||||
|
s.offset_chars := s.offset_chars + length(s.src);
|
||||||
|
s.offset := s.offset + length2(s.src);
|
||||||
|
/* exception check, so works correctly for 4-byte unicode characters (issue #169) */
|
||||||
|
begin
|
||||||
|
s.src := dbms_lob.substr(s.s_clob, 4000, s.offset+1);
|
||||||
|
exception
|
||||||
|
when ucs2_exception then
|
||||||
|
s.src := dbms_lob.substr(s.s_clob, 3999, s.offset+1);
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
elsif (indx <= s.offset_chars) then
|
||||||
|
s.offset_chars := 0;
|
||||||
|
s.offset := 0;
|
||||||
|
/* exception check, so works correctly for 4-byte unicode characters (issue #169) */
|
||||||
|
begin
|
||||||
|
s.src := dbms_lob.substr(s.s_clob, 4000, s.offset+1);
|
||||||
|
exception
|
||||||
|
when ucs2_exception then
|
||||||
|
s.src := dbms_lob.substr(s.s_clob, 3999, s.offset+1);
|
||||||
|
end;
|
||||||
|
while (indx > length(s.src) + s.offset_chars) loop
|
||||||
|
s.offset_chars := s.offset_chars + length(s.src);
|
||||||
|
s.offset := s.offset + length2(s.src);
|
||||||
|
/* exception check, so works correctly for 4-byte unicode characters (issue #169) */
|
||||||
|
begin
|
||||||
|
s.src := dbms_lob.substr(s.s_clob, 4000, s.offset+1);
|
||||||
|
exception
|
||||||
|
when ucs2_exception then
|
||||||
|
s.src := dbms_lob.substr(s.s_clob, 3999, s.offset+1);
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
end if;
|
||||||
|
--dbms_output.put_line('indx: ' || indx || ' offset: ' || s.offset || ' (chars: ' || s.offset_chars || ') src chars: ' || length(s.src));
|
||||||
|
--read from s.src
|
||||||
|
return substr(s.src, indx-s.offset_chars, 1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function next_char2(indx number, s in out nocopy json_src, amount number default 1) return varchar2 as
|
||||||
|
buf varchar2(32767) := '';
|
||||||
|
begin
|
||||||
|
for i in 1..amount loop
|
||||||
|
buf := buf || next_char(indx-1+i, s);
|
||||||
|
end loop;
|
||||||
|
return buf;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function prepareClob(buf clob) return pljson_parser.json_src as
|
||||||
|
temp pljson_parser.json_src;
|
||||||
|
begin
|
||||||
|
temp.s_clob := buf;
|
||||||
|
temp.offset_chars := 0;
|
||||||
|
temp.offset := 0;
|
||||||
|
/* exception check, so works correctly for 4-byte unicode characters (issue #169) */
|
||||||
|
begin
|
||||||
|
temp.src := dbms_lob.substr(buf, 4000, temp.offset+1);
|
||||||
|
exception
|
||||||
|
when ucs2_exception then
|
||||||
|
temp.src := dbms_lob.substr(buf, 3999, temp.offset+1);
|
||||||
|
end;
|
||||||
|
/* use of lengthcc, so works correctly for 4-byte unicode characters (issue #169) */
|
||||||
|
temp.len := lengthcc(buf); --dbms_lob.getlength(buf);
|
||||||
|
return temp;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function prepareVarchar2(buf varchar2) return pljson_parser.json_src as
|
||||||
|
temp pljson_parser.json_src;
|
||||||
|
begin
|
||||||
|
temp.s_clob := buf;
|
||||||
|
temp.offset_chars := 0;
|
||||||
|
temp.offset := 0;
|
||||||
|
temp.src := substr(buf, 1, 4000);
|
||||||
|
temp.len := length(buf);
|
||||||
|
return temp;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure debug(text varchar2) as
|
||||||
|
begin
|
||||||
|
dbms_output.put_line(text);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure print_token(t rToken) as
|
||||||
|
begin
|
||||||
|
dbms_output.put_line('Line: '||t.line||' - Column: '||t.col||' - Type: '||t.type_name||' - Content: '||t.data);
|
||||||
|
end print_token;
|
||||||
|
|
||||||
|
/* SCANNER FUNCTIONS START */
|
||||||
|
procedure s_error(text varchar2, line number, col number) as
|
||||||
|
begin
|
||||||
|
raise_application_error(-20100, 'JSON Scanner exception @ line: '||line||' column: '||col||' - '||text);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure s_error(text varchar2, tok rToken) as
|
||||||
|
begin
|
||||||
|
raise_application_error(-20100, 'JSON Scanner exception @ line: '||tok.line||' column: '||tok.col||' - '||text);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function mt(t varchar2, l pls_integer, c pls_integer, d varchar2) return rToken as
|
||||||
|
token rToken;
|
||||||
|
begin
|
||||||
|
token.type_name := t;
|
||||||
|
token.line := l;
|
||||||
|
token.col := c;
|
||||||
|
token.data := d;
|
||||||
|
return token;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function lexNumber(jsrc in out nocopy json_src, tok in out nocopy rToken, indx in out nocopy pls_integer) return pls_integer as
|
||||||
|
numbuf varchar2(4000) := '';
|
||||||
|
buf varchar2(4);
|
||||||
|
checkLoop boolean;
|
||||||
|
begin
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
if (buf = '-') then numbuf := '-'; indx := indx + 1; end if;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
--0 or [1-9]([0-9])*
|
||||||
|
if (buf = '0') then
|
||||||
|
numbuf := numbuf || '0'; indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
elsif (buf >= '1' and buf <= '9') then
|
||||||
|
numbuf := numbuf || buf; indx := indx + 1;
|
||||||
|
--read digits
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
while (buf >= '0' and buf <= '9') loop
|
||||||
|
numbuf := numbuf || buf; indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
end loop;
|
||||||
|
end if;
|
||||||
|
--fraction
|
||||||
|
if (buf = '.') then
|
||||||
|
numbuf := numbuf || buf; indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
checkLoop := FALSE;
|
||||||
|
while (buf >= '0' and buf <= '9') loop
|
||||||
|
checkLoop := TRUE;
|
||||||
|
numbuf := numbuf || buf; indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
end loop;
|
||||||
|
if (not checkLoop) then
|
||||||
|
s_error('Expected: digits in fraction', tok);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
--exp part
|
||||||
|
if (buf in ('e', 'E')) then
|
||||||
|
numbuf := numbuf || buf; indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
if (buf = '+' or buf = '-') then
|
||||||
|
numbuf := numbuf || buf; indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
end if;
|
||||||
|
checkLoop := FALSE;
|
||||||
|
while (buf >= '0' and buf <= '9') loop
|
||||||
|
checkLoop := TRUE;
|
||||||
|
numbuf := numbuf || buf; indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
end loop;
|
||||||
|
if (not checkLoop) then
|
||||||
|
s_error('Expected: digits in exp', tok);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
tok.data := numbuf;
|
||||||
|
return indx;
|
||||||
|
end lexNumber;
|
||||||
|
|
||||||
|
-- [a-zA-Z]([a-zA-Z0-9])*
|
||||||
|
function lexName(jsrc in out nocopy json_src, tok in out nocopy rToken, indx in out nocopy pls_integer) return pls_integer as
|
||||||
|
varbuf varchar2(32767) := '';
|
||||||
|
buf varchar(4);
|
||||||
|
num number;
|
||||||
|
begin
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
while (REGEXP_LIKE(buf, '^[[:alnum:]\_]$', 'i')) loop
|
||||||
|
varbuf := varbuf || buf;
|
||||||
|
indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
if (buf is null) then
|
||||||
|
goto retname;
|
||||||
|
--debug('Premature string ending');
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
<<retname>>
|
||||||
|
--could check for reserved keywords here
|
||||||
|
--debug(varbuf);
|
||||||
|
tok.data := varbuf;
|
||||||
|
return indx-1;
|
||||||
|
end lexName;
|
||||||
|
|
||||||
|
procedure updateClob(v_extended in out nocopy clob, v_str varchar2) as
|
||||||
|
begin
|
||||||
|
/* use of length2, so works correctly for 4-byte unicode characters (issue #169) */
|
||||||
|
dbms_lob.writeappend(v_extended, length2(v_str), v_str);
|
||||||
|
end updateClob;
|
||||||
|
|
||||||
|
function lexString(jsrc in out nocopy json_src, tok in out nocopy rToken, indx in out nocopy pls_integer, endChar char) return pls_integer as
|
||||||
|
v_extended clob := null; v_count number := 0;
|
||||||
|
varbuf varchar2(32767) := '';
|
||||||
|
buf varchar(4);
|
||||||
|
wrong boolean;
|
||||||
|
max_string_chars number := 5000; /* chunk size, less than this number may be copied */
|
||||||
|
begin
|
||||||
|
indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
while (buf != endChar) loop
|
||||||
|
--clob control
|
||||||
|
if (v_count > 8191) then --crazy oracle error (16383 is the highest working length with unistr - 8192 choosen to be safe)
|
||||||
|
if (v_extended is null) then
|
||||||
|
v_extended := empty_clob();
|
||||||
|
dbms_lob.createtemporary(v_extended, true);
|
||||||
|
end if;
|
||||||
|
updateClob(v_extended, unistr(varbuf));
|
||||||
|
varbuf := ''; v_count := 0;
|
||||||
|
end if;
|
||||||
|
if (buf = Chr(13) or buf = CHR(9) or buf = CHR(10)) then
|
||||||
|
s_error('Control characters not allowed (CHR(9),CHR(10),CHR(13))', tok);
|
||||||
|
end if;
|
||||||
|
if (buf = '\') then
|
||||||
|
--varbuf := varbuf || buf;
|
||||||
|
indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
case
|
||||||
|
when buf in ('\') then
|
||||||
|
varbuf := varbuf || buf || buf; v_count := v_count + 2;
|
||||||
|
indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
when buf in ('"', '/') then
|
||||||
|
varbuf := varbuf || buf; v_count := v_count + 1;
|
||||||
|
indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
when buf = '''' then
|
||||||
|
if (json_strict = false) then
|
||||||
|
varbuf := varbuf || buf; v_count := v_count + 1;
|
||||||
|
indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
else
|
||||||
|
s_error('strictmode - expected: " \ / b f n r t u ', tok);
|
||||||
|
end if;
|
||||||
|
when buf in ('b', 'f', 'n', 'r', 't') then
|
||||||
|
--backspace b = U+0008
|
||||||
|
--formfeed f = U+000C
|
||||||
|
--newline n = U+000A
|
||||||
|
--carret r = U+000D
|
||||||
|
--tabulator t = U+0009
|
||||||
|
case buf
|
||||||
|
when 'b' then varbuf := varbuf || chr(8);
|
||||||
|
when 'f' then varbuf := varbuf || chr(12);
|
||||||
|
when 'n' then varbuf := varbuf || chr(10);
|
||||||
|
when 'r' then varbuf := varbuf || chr(13);
|
||||||
|
when 't' then varbuf := varbuf || chr(9);
|
||||||
|
end case;
|
||||||
|
--varbuf := varbuf || buf;
|
||||||
|
v_count := v_count + 1;
|
||||||
|
indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
when buf = 'u' then
|
||||||
|
--four hexadecimal chars
|
||||||
|
declare
|
||||||
|
four varchar2(4);
|
||||||
|
begin
|
||||||
|
four := next_char2(indx+1, jsrc, 4);
|
||||||
|
wrong := FALSE;
|
||||||
|
if (upper(substr(four, 1, 1)) not in ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f')) then wrong := TRUE; end if;
|
||||||
|
if (upper(substr(four, 2, 1)) not in ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f')) then wrong := TRUE; end if;
|
||||||
|
if (upper(substr(four, 3, 1)) not in ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f')) then wrong := TRUE; end if;
|
||||||
|
if (upper(substr(four, 4, 1)) not in ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f')) then wrong := TRUE; end if;
|
||||||
|
if (wrong) then
|
||||||
|
s_error('expected: " \u([0-9][A-F]){4}', tok);
|
||||||
|
end if;
|
||||||
|
-- varbuf := varbuf || buf || four;
|
||||||
|
varbuf := varbuf || '\'||four;--chr(to_number(four,'XXXX'));
|
||||||
|
v_count := v_count + 5;
|
||||||
|
indx := indx + 5;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
s_error('expected: " \ / b f n r t u ', tok);
|
||||||
|
end case;
|
||||||
|
else
|
||||||
|
varbuf := varbuf || buf; v_count := v_count + 1;
|
||||||
|
indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
if (buf is null) then
|
||||||
|
s_error('string ending not found', tok);
|
||||||
|
--debug('Premature string ending');
|
||||||
|
end if;
|
||||||
|
|
||||||
|
--debug(varbuf);
|
||||||
|
--dbms_output.put_line(varbuf);
|
||||||
|
if (v_extended is not null) then
|
||||||
|
updateClob(v_extended, unistr(varbuf));
|
||||||
|
tok.data_overflow := v_extended;
|
||||||
|
-- tok.data := dbms_lob.substr(v_extended, 1, 32767);
|
||||||
|
/* may read less than "max_string_chars" characters but it's a sample so doesn't matter */
|
||||||
|
dbms_lob.read(v_extended, max_string_chars, 1, tok.data);
|
||||||
|
else
|
||||||
|
tok.data := unistr(varbuf);
|
||||||
|
end if;
|
||||||
|
return indx;
|
||||||
|
end lexString;
|
||||||
|
|
||||||
|
/* scanner tokens:
|
||||||
|
'{', '}', ',', ':', '[', ']', STRING, NUMBER, TRUE, FALSE, NULL
|
||||||
|
*/
|
||||||
|
function lexer(jsrc in out nocopy json_src) return lTokens as
|
||||||
|
tokens lTokens;
|
||||||
|
indx pls_integer := 1;
|
||||||
|
tok_indx pls_integer := 1;
|
||||||
|
buf varchar2(4);
|
||||||
|
lin_no number := 1;
|
||||||
|
col_no number := 0;
|
||||||
|
begin
|
||||||
|
while (indx <= jsrc.len) loop
|
||||||
|
--read into buf
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
col_no := col_no + 1;
|
||||||
|
--convert to switch case
|
||||||
|
case
|
||||||
|
when buf = '{' then tokens(tok_indx) := mt('{', lin_no, col_no, null); tok_indx := tok_indx + 1;
|
||||||
|
when buf = '}' then tokens(tok_indx) := mt('}', lin_no, col_no, null); tok_indx := tok_indx + 1;
|
||||||
|
when buf = ',' then tokens(tok_indx) := mt(',', lin_no, col_no, null); tok_indx := tok_indx + 1;
|
||||||
|
when buf = ':' then tokens(tok_indx) := mt(':', lin_no, col_no, null); tok_indx := tok_indx + 1;
|
||||||
|
when buf = '[' then tokens(tok_indx) := mt('[', lin_no, col_no, null); tok_indx := tok_indx + 1;
|
||||||
|
when buf = ']' then tokens(tok_indx) := mt(']', lin_no, col_no, null); tok_indx := tok_indx + 1;
|
||||||
|
when buf = 't' then
|
||||||
|
if (next_char2(indx, jsrc, 4) != 'true') then
|
||||||
|
if (json_strict = false and REGEXP_LIKE(buf, '^[[:alpha:]]$', 'i')) then
|
||||||
|
tokens(tok_indx) := mt('STRING', lin_no, col_no, null);
|
||||||
|
indx := lexName(jsrc, tokens(tok_indx), indx);
|
||||||
|
col_no := col_no + length(tokens(tok_indx).data) + 1;
|
||||||
|
tok_indx := tok_indx + 1;
|
||||||
|
else
|
||||||
|
s_error('Expected: ''true''', lin_no, col_no);
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
tokens(tok_indx) := mt('TRUE', lin_no, col_no, null); tok_indx := tok_indx + 1;
|
||||||
|
indx := indx + 3;
|
||||||
|
col_no := col_no + 3;
|
||||||
|
end if;
|
||||||
|
when buf = 'n' then
|
||||||
|
if (next_char2(indx, jsrc, 4) != 'null') then
|
||||||
|
if (json_strict = false and REGEXP_LIKE(buf, '^[[:alpha:]]$', 'i')) then
|
||||||
|
tokens(tok_indx) := mt('STRING', lin_no, col_no, null);
|
||||||
|
indx := lexName(jsrc, tokens(tok_indx), indx);
|
||||||
|
col_no := col_no + length(tokens(tok_indx).data) + 1;
|
||||||
|
tok_indx := tok_indx + 1;
|
||||||
|
else
|
||||||
|
s_error('Expected: ''null''', lin_no, col_no);
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
tokens(tok_indx) := mt('NULL', lin_no, col_no, null); tok_indx := tok_indx + 1;
|
||||||
|
indx := indx + 3;
|
||||||
|
col_no := col_no + 3;
|
||||||
|
end if;
|
||||||
|
when buf = 'f' then
|
||||||
|
if (next_char2(indx, jsrc, 5) != 'false') then
|
||||||
|
if (json_strict = false and REGEXP_LIKE(buf, '^[[:alpha:]]$', 'i')) then
|
||||||
|
tokens(tok_indx) := mt('STRING', lin_no, col_no, null);
|
||||||
|
indx := lexName(jsrc, tokens(tok_indx), indx);
|
||||||
|
col_no := col_no + length(tokens(tok_indx).data) + 1;
|
||||||
|
tok_indx := tok_indx + 1;
|
||||||
|
else
|
||||||
|
s_error('Expected: ''false''', lin_no, col_no);
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
tokens(tok_indx) := mt('FALSE', lin_no, col_no, null); tok_indx := tok_indx + 1;
|
||||||
|
indx := indx + 4;
|
||||||
|
col_no := col_no + 4;
|
||||||
|
end if;
|
||||||
|
/* -- 9 = TAB, 10 = \n, 13 = \r (Linux = \n, Windows = \r\n, Mac = \r */
|
||||||
|
when (buf = Chr(10)) then --linux newlines
|
||||||
|
lin_no := lin_no + 1;
|
||||||
|
col_no := 0;
|
||||||
|
|
||||||
|
when (buf = Chr(13)) then --Windows or Mac way
|
||||||
|
lin_no := lin_no + 1;
|
||||||
|
col_no := 0;
|
||||||
|
if (jsrc.len >= indx+1) then -- better safe than sorry
|
||||||
|
buf := next_char(indx+1, jsrc);
|
||||||
|
if (buf = Chr(10)) then --\r\n
|
||||||
|
indx := indx + 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when (buf = CHR(9)) then null; --tabbing
|
||||||
|
when (buf in ('-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) then --number
|
||||||
|
tokens(tok_indx) := mt('NUMBER', lin_no, col_no, null);
|
||||||
|
indx := lexNumber(jsrc, tokens(tok_indx), indx)-1;
|
||||||
|
col_no := col_no + length(tokens(tok_indx).data);
|
||||||
|
tok_indx := tok_indx + 1;
|
||||||
|
when buf = '"' then --string
|
||||||
|
tokens(tok_indx) := mt('STRING', lin_no, col_no, null);
|
||||||
|
indx := lexString(jsrc, tokens(tok_indx), indx, '"');
|
||||||
|
col_no := col_no + length(tokens(tok_indx).data) + 1;
|
||||||
|
tok_indx := tok_indx + 1;
|
||||||
|
when buf = '''' and json_strict = false then --string
|
||||||
|
tokens(tok_indx) := mt('STRING', lin_no, col_no, null);
|
||||||
|
indx := lexString(jsrc, tokens(tok_indx), indx, '''');
|
||||||
|
col_no := col_no + length(tokens(tok_indx).data) + 1; --hovsa her
|
||||||
|
tok_indx := tok_indx + 1;
|
||||||
|
when json_strict = false and REGEXP_LIKE(buf, '^[[:alpha:]]$', 'i') then
|
||||||
|
tokens(tok_indx) := mt('STRING', lin_no, col_no, null);
|
||||||
|
indx := lexName(jsrc, tokens(tok_indx), indx);
|
||||||
|
if (tokens(tok_indx).data_overflow is not null) then
|
||||||
|
/* use of lengthcc, so works correctly for 4-byte unicode characters (issue #169) */
|
||||||
|
col_no := col_no + lengthcc(tokens(tok_indx).data_overflow) + 1; --dbms_lob.getlength(tokens(tok_indx).data_overflow) + 1;
|
||||||
|
else
|
||||||
|
col_no := col_no + length(tokens(tok_indx).data) + 1;
|
||||||
|
end if;
|
||||||
|
tok_indx := tok_indx + 1;
|
||||||
|
when json_strict = false and buf||next_char(indx+1, jsrc) = '/*' then --strip comments
|
||||||
|
declare
|
||||||
|
saveindx number := indx;
|
||||||
|
un_esc clob;
|
||||||
|
begin
|
||||||
|
indx := indx + 1;
|
||||||
|
loop
|
||||||
|
indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc)||next_char(indx+1, jsrc);
|
||||||
|
exit when buf = '*/';
|
||||||
|
exit when buf is null;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
if (indx = saveindx+2) then
|
||||||
|
--enter unescaped mode
|
||||||
|
--dbms_output.put_line('Entering unescaped mode');
|
||||||
|
un_esc := empty_clob();
|
||||||
|
dbms_lob.createtemporary(un_esc, true);
|
||||||
|
indx := indx + 1;
|
||||||
|
loop
|
||||||
|
indx := indx + 1;
|
||||||
|
buf := next_char(indx, jsrc)||next_char(indx+1, jsrc)||next_char(indx+2, jsrc)||next_char(indx+3, jsrc);
|
||||||
|
exit when buf = '/**/';
|
||||||
|
if buf is null then
|
||||||
|
s_error('Unexpected sequence /**/ to end unescaped data: '||buf, lin_no, col_no);
|
||||||
|
end if;
|
||||||
|
buf := next_char(indx, jsrc);
|
||||||
|
/* use of length2, so works correctly for 4-byte unicode characters (issue #169) */
|
||||||
|
dbms_lob.writeappend(un_esc, length2(buf), buf);
|
||||||
|
end loop;
|
||||||
|
tokens(tok_indx) := mt('ESTRING', lin_no, col_no, null);
|
||||||
|
tokens(tok_indx).data_overflow := un_esc;
|
||||||
|
/* use of lengthcc, so works correctly for 4-byte unicode characters (issue #169) */
|
||||||
|
col_no := col_no + lengthcc(un_esc) + 1; --dbms_lob.getlength(un_esc) + 1; --note: line count won't work properly
|
||||||
|
tok_indx := tok_indx + 1;
|
||||||
|
indx := indx + 2;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
indx := indx + 1;
|
||||||
|
end;
|
||||||
|
when buf = ' ' then null; --space
|
||||||
|
else
|
||||||
|
s_error('Unexpected char: '||buf, lin_no, col_no);
|
||||||
|
end case;
|
||||||
|
|
||||||
|
indx := indx + 1;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
end lexer;
|
||||||
|
|
||||||
|
/* SCANNER END */
|
||||||
|
|
||||||
|
/* PARSER FUNCTIONS START */
|
||||||
|
procedure p_error(text varchar2, tok rToken) as
|
||||||
|
begin
|
||||||
|
raise_application_error(-20101, 'JSON Parser exception @ line: '||tok.line||' column: '||tok.col||' - '||text);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function parseArr(tokens lTokens, indx in out nocopy pls_integer) return pljson_list as
|
||||||
|
e_arr pljson_element_array := pljson_element_array();
|
||||||
|
ret_list pljson_list := pljson_list();
|
||||||
|
v_count number := 0;
|
||||||
|
tok rToken;
|
||||||
|
pv pljson_number;
|
||||||
|
begin
|
||||||
|
--value, value, value ]
|
||||||
|
if (indx > tokens.count) then p_error('more elements in array was excepted', tok); end if;
|
||||||
|
tok := tokens(indx);
|
||||||
|
while (tok.type_name != ']') loop
|
||||||
|
e_arr.extend;
|
||||||
|
v_count := v_count + 1;
|
||||||
|
case tok.type_name
|
||||||
|
when 'TRUE' then e_arr(v_count) := pljson_bool(true);
|
||||||
|
when 'FALSE' then e_arr(v_count) := pljson_bool(false);
|
||||||
|
when 'NULL' then e_arr(v_count) := pljson_null();
|
||||||
|
when 'STRING' then e_arr(v_count) := case when tok.data_overflow is not null then pljson_string(tok.data_overflow) else pljson_string(tok.data) end;
|
||||||
|
when 'ESTRING' then e_arr(v_count) := pljson_string(tok.data_overflow, false);
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
|
||||||
|
--when 'NUMBER' then e_arr(v_count) := pljson_number(to_number(replace(tok.data, '.', decimalpoint)));
|
||||||
|
when 'NUMBER' then
|
||||||
|
pv := pljson_number(0);
|
||||||
|
pv.parse_number(replace(tok.data, '.', decimalpoint));
|
||||||
|
e_arr(v_count) := pv;
|
||||||
|
when '[' then
|
||||||
|
declare e_list pljson_list; begin
|
||||||
|
indx := indx + 1;
|
||||||
|
e_list := parseArr(tokens, indx);
|
||||||
|
e_arr(v_count) := e_list;
|
||||||
|
end;
|
||||||
|
when '{' then
|
||||||
|
indx := indx + 1;
|
||||||
|
e_arr(v_count) := parseObj(tokens, indx);
|
||||||
|
else
|
||||||
|
p_error('Expected a value', tok);
|
||||||
|
end case;
|
||||||
|
indx := indx + 1;
|
||||||
|
if (indx > tokens.count) then p_error('] not found', tok); end if;
|
||||||
|
tok := tokens(indx);
|
||||||
|
if (tok.type_name = ',') then --advance
|
||||||
|
indx := indx + 1;
|
||||||
|
if (indx > tokens.count) then p_error('more elements in array was excepted', tok); end if;
|
||||||
|
tok := tokens(indx);
|
||||||
|
if (tok.type_name = ']') then --premature exit
|
||||||
|
p_error('Premature exit in array', tok);
|
||||||
|
end if;
|
||||||
|
elsif (tok.type_name != ']') then --error
|
||||||
|
p_error('Expected , or ]', tok);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
ret_list.list_data := e_arr;
|
||||||
|
return ret_list;
|
||||||
|
end parseArr;
|
||||||
|
|
||||||
|
function parseMem(tokens lTokens, indx in out pls_integer, mem_name varchar2, mem_indx number) return pljson_element as
|
||||||
|
mem pljson_element;
|
||||||
|
tok rToken;
|
||||||
|
pv pljson_number;
|
||||||
|
begin
|
||||||
|
tok := tokens(indx);
|
||||||
|
case tok.type_name
|
||||||
|
when 'TRUE' then mem := pljson_bool(true);
|
||||||
|
when 'FALSE' then mem := pljson_bool(false);
|
||||||
|
when 'NULL' then mem := pljson_null();
|
||||||
|
when 'STRING' then mem := case when tok.data_overflow is not null then pljson_string(tok.data_overflow) else pljson_string(tok.data) end;
|
||||||
|
when 'ESTRING' then mem := pljson_string(tok.data_overflow, false);
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
|
||||||
|
--when 'NUMBER' then mem := pljson_number(to_number(replace(tok.data, '.', decimalpoint)));
|
||||||
|
when 'NUMBER' then
|
||||||
|
pv := pljson_number(0);
|
||||||
|
pv.parse_number(replace(tok.data, '.', decimalpoint));
|
||||||
|
mem := pv;
|
||||||
|
when '[' then
|
||||||
|
declare
|
||||||
|
e_list pljson_list;
|
||||||
|
begin
|
||||||
|
indx := indx + 1;
|
||||||
|
e_list := parseArr(tokens, indx);
|
||||||
|
mem := e_list;
|
||||||
|
end;
|
||||||
|
when '{' then
|
||||||
|
indx := indx + 1;
|
||||||
|
mem := parseObj(tokens, indx);
|
||||||
|
else
|
||||||
|
p_error('Found '||tok.type_name, tok);
|
||||||
|
end case;
|
||||||
|
mem.mapname := mem_name;
|
||||||
|
mem.mapindx := mem_indx;
|
||||||
|
|
||||||
|
indx := indx + 1;
|
||||||
|
return mem;
|
||||||
|
end parseMem;
|
||||||
|
|
||||||
|
/*procedure test_duplicate_members(arr in json_member_array, mem_name in varchar2, wheretok rToken) as
|
||||||
|
begin
|
||||||
|
for i in 1 .. arr.count loop
|
||||||
|
if (arr(i).member_name = mem_name) then
|
||||||
|
p_error('Duplicate member name', wheretok);
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end test_duplicate_members;*/
|
||||||
|
|
||||||
|
function parseObj(tokens lTokens, indx in out nocopy pls_integer) return pljson as
|
||||||
|
type memmap is table of number index by varchar2(4000); -- i've read somewhere that this is not possible - but it is!
|
||||||
|
mymap memmap;
|
||||||
|
nullelemfound boolean := false;
|
||||||
|
|
||||||
|
obj pljson;
|
||||||
|
tok rToken;
|
||||||
|
mem_name varchar(4000);
|
||||||
|
arr pljson_element_array := pljson_element_array();
|
||||||
|
begin
|
||||||
|
--what to expect?
|
||||||
|
while (indx <= tokens.count) loop
|
||||||
|
tok := tokens(indx);
|
||||||
|
--debug('E: '||tok.type_name);
|
||||||
|
case tok.type_name
|
||||||
|
when 'STRING' then
|
||||||
|
--member
|
||||||
|
mem_name := substr(tok.data, 1, 4000);
|
||||||
|
begin
|
||||||
|
if (mem_name is null) then
|
||||||
|
if (nullelemfound) then
|
||||||
|
p_error('Duplicate empty member: ', tok);
|
||||||
|
else
|
||||||
|
nullelemfound := true;
|
||||||
|
end if;
|
||||||
|
elsif (mymap(mem_name) is not null) then
|
||||||
|
p_error('Duplicate member name: '||mem_name, tok);
|
||||||
|
end if;
|
||||||
|
exception
|
||||||
|
when no_data_found then mymap(mem_name) := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
indx := indx + 1;
|
||||||
|
if (indx > tokens.count) then p_error('Unexpected end of input', tok); end if;
|
||||||
|
tok := tokens(indx);
|
||||||
|
indx := indx + 1;
|
||||||
|
if (indx > tokens.count) then p_error('Unexpected end of input', tok); end if;
|
||||||
|
if (tok.type_name = ':') then
|
||||||
|
--parse
|
||||||
|
declare
|
||||||
|
jmb pljson_element;
|
||||||
|
x number;
|
||||||
|
begin
|
||||||
|
x := arr.count + 1;
|
||||||
|
jmb := parseMem(tokens, indx, mem_name, x);
|
||||||
|
arr.extend;
|
||||||
|
arr(x) := jmb;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
p_error('Expected '':''', tok);
|
||||||
|
end if;
|
||||||
|
--move indx forward if ',' is found
|
||||||
|
if (indx > tokens.count) then p_error('Unexpected end of input', tok); end if;
|
||||||
|
|
||||||
|
tok := tokens(indx);
|
||||||
|
if (tok.type_name = ',') then
|
||||||
|
--debug('found ,');
|
||||||
|
indx := indx + 1;
|
||||||
|
tok := tokens(indx);
|
||||||
|
if (tok.type_name = '}') then --premature exit
|
||||||
|
p_error('Premature exit in json object', tok);
|
||||||
|
end if;
|
||||||
|
elsif (tok.type_name != '}') then
|
||||||
|
p_error('A comma seperator is probably missing', tok);
|
||||||
|
end if;
|
||||||
|
when '}' then
|
||||||
|
obj := pljson();
|
||||||
|
obj.json_data := arr;
|
||||||
|
return obj;
|
||||||
|
else
|
||||||
|
p_error('Expected string or }', tok);
|
||||||
|
end case;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
p_error('} not found', tokens(indx-1));
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
function parser(str varchar2) return pljson as
|
||||||
|
tokens lTokens;
|
||||||
|
obj pljson;
|
||||||
|
indx pls_integer := 1;
|
||||||
|
jsrc json_src;
|
||||||
|
begin
|
||||||
|
update_decimalpoint();
|
||||||
|
jsrc := prepareVarchar2(str);
|
||||||
|
tokens := lexer(jsrc);
|
||||||
|
if (tokens(indx).type_name = '{') then
|
||||||
|
indx := indx + 1;
|
||||||
|
obj := parseObj(tokens, indx);
|
||||||
|
else
|
||||||
|
raise_application_error(-20101, 'JSON Parser exception - no { start found');
|
||||||
|
end if;
|
||||||
|
if (tokens.count != indx) then
|
||||||
|
p_error('} should end the JSON object', tokens(indx));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
end parser;
|
||||||
|
|
||||||
|
function parse_list(str varchar2) return pljson_list as
|
||||||
|
tokens lTokens;
|
||||||
|
obj pljson_list;
|
||||||
|
indx pls_integer := 1;
|
||||||
|
jsrc json_src;
|
||||||
|
begin
|
||||||
|
update_decimalpoint();
|
||||||
|
jsrc := prepareVarchar2(str);
|
||||||
|
tokens := lexer(jsrc);
|
||||||
|
if (tokens(indx).type_name = '[') then
|
||||||
|
indx := indx + 1;
|
||||||
|
obj := parseArr(tokens, indx);
|
||||||
|
else
|
||||||
|
raise_application_error(-20101, 'JSON List Parser exception - no [ start found');
|
||||||
|
end if;
|
||||||
|
if (tokens.count != indx) then
|
||||||
|
p_error('] should end the JSON List object', tokens(indx));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
end parse_list;
|
||||||
|
|
||||||
|
function parse_list(str clob) return pljson_list as
|
||||||
|
tokens lTokens;
|
||||||
|
obj pljson_list;
|
||||||
|
indx pls_integer := 1;
|
||||||
|
jsrc json_src;
|
||||||
|
begin
|
||||||
|
update_decimalpoint();
|
||||||
|
jsrc := prepareClob(str);
|
||||||
|
tokens := lexer(jsrc);
|
||||||
|
if (tokens(indx).type_name = '[') then
|
||||||
|
indx := indx + 1;
|
||||||
|
obj := parseArr(tokens, indx);
|
||||||
|
else
|
||||||
|
raise_application_error(-20101, 'JSON List Parser exception - no [ start found');
|
||||||
|
end if;
|
||||||
|
if (tokens.count != indx) then
|
||||||
|
p_error('] should end the JSON List object', tokens(indx));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
end parse_list;
|
||||||
|
|
||||||
|
function parser(str clob) return pljson as
|
||||||
|
tokens lTokens;
|
||||||
|
obj pljson;
|
||||||
|
indx pls_integer := 1;
|
||||||
|
jsrc json_src;
|
||||||
|
begin
|
||||||
|
update_decimalpoint();
|
||||||
|
--dbms_output.put_line('Using clob');
|
||||||
|
jsrc := prepareClob(str);
|
||||||
|
tokens := lexer(jsrc);
|
||||||
|
if (tokens(indx).type_name = '{') then
|
||||||
|
indx := indx + 1;
|
||||||
|
obj := parseObj(tokens, indx);
|
||||||
|
else
|
||||||
|
raise_application_error(-20101, 'JSON Parser exception - no { start found');
|
||||||
|
end if;
|
||||||
|
if (tokens.count != indx) then
|
||||||
|
p_error('} should end the JSON object', tokens(indx));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
end parser;
|
||||||
|
|
||||||
|
function parse_any(str varchar2) return pljson_element as
|
||||||
|
tokens lTokens;
|
||||||
|
obj pljson_list;
|
||||||
|
ret pljson_element;
|
||||||
|
indx pls_integer := 1;
|
||||||
|
jsrc json_src;
|
||||||
|
begin
|
||||||
|
update_decimalpoint();
|
||||||
|
jsrc := prepareVarchar2(str);
|
||||||
|
tokens := lexer(jsrc);
|
||||||
|
tokens(tokens.count+1).type_name := ']';
|
||||||
|
obj := parseArr(tokens, indx);
|
||||||
|
if (tokens.count != indx) then
|
||||||
|
p_error('] should end the JSON List object', tokens(indx));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return obj.head();
|
||||||
|
end parse_any;
|
||||||
|
|
||||||
|
function parse_any(str clob) return pljson_element as
|
||||||
|
tokens lTokens;
|
||||||
|
obj pljson_list;
|
||||||
|
indx pls_integer := 1;
|
||||||
|
jsrc json_src;
|
||||||
|
begin
|
||||||
|
update_decimalpoint();
|
||||||
|
jsrc := prepareClob(str);
|
||||||
|
tokens := lexer(jsrc);
|
||||||
|
tokens(tokens.count+1).type_name := ']';
|
||||||
|
obj := parseArr(tokens, indx);
|
||||||
|
if (tokens.count != indx) then
|
||||||
|
p_error('] should end the JSON List object', tokens(indx));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return obj.head();
|
||||||
|
end parse_any;
|
||||||
|
|
||||||
|
/* last entry is the one to keep */
|
||||||
|
procedure remove_duplicates(obj in out nocopy pljson) as
|
||||||
|
type memberlist is table of pljson_element index by varchar2(4000);
|
||||||
|
members memberlist;
|
||||||
|
nulljsonvalue pljson_element := null;
|
||||||
|
validated pljson := pljson();
|
||||||
|
indx varchar2(4000);
|
||||||
|
begin
|
||||||
|
for i in 1 .. obj.count loop
|
||||||
|
if (obj.get(i).mapname is null) then
|
||||||
|
nulljsonvalue := obj.get(i);
|
||||||
|
else
|
||||||
|
members(obj.get(i).mapname) := obj.get(i);
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
validated.check_duplicate(false);
|
||||||
|
indx := members.first;
|
||||||
|
loop
|
||||||
|
exit when indx is null;
|
||||||
|
validated.put(indx, members(indx));
|
||||||
|
indx := members.next(indx);
|
||||||
|
end loop;
|
||||||
|
if (nulljsonvalue is not null) then
|
||||||
|
validated.put('', nulljsonvalue);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
validated.check_for_duplicate := obj.check_for_duplicate;
|
||||||
|
|
||||||
|
obj := validated;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function get_version return varchar2 as
|
||||||
|
begin
|
||||||
|
return 'PL/JSON 3.5.2';
|
||||||
|
end get_version;
|
||||||
|
|
||||||
|
end pljson_parser;```
|
||||||
727
docs/packages/PLJSON_PRINTER.md
Normal file
727
docs/packages/PLJSON_PRINTER.md
Normal file
@@ -0,0 +1,727 @@
|
|||||||
|
# PLJSON_PRINTER
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package pljson_printer as
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Jonas Krogsboell
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
indent_string varchar2(10 char) := ' '; --chr(9); for tab
|
||||||
|
newline_char varchar2(2 char) := chr(13)||chr(10); -- Windows style
|
||||||
|
--newline_char varchar2(2) := chr(10); -- Mac style
|
||||||
|
--newline_char varchar2(2) := chr(13); -- Linux style
|
||||||
|
ascii_output boolean not null := true;
|
||||||
|
empty_string_as_null boolean not null := false;
|
||||||
|
escape_solidus boolean not null := false;
|
||||||
|
|
||||||
|
function pretty_print(obj pljson, spaces boolean default true, line_length number default 0) return varchar2;
|
||||||
|
function pretty_print_list(obj pljson_list, spaces boolean default true, line_length number default 0) return varchar2;
|
||||||
|
function pretty_print_any(json_part pljson_element, spaces boolean default true, line_length number default 0) return varchar2;
|
||||||
|
procedure pretty_print(obj pljson, spaces boolean default true, buf in out nocopy clob, line_length number default 0, erase_clob boolean default true);
|
||||||
|
procedure pretty_print_list(obj pljson_list, spaces boolean default true, buf in out nocopy clob, line_length number default 0, erase_clob boolean default true);
|
||||||
|
procedure pretty_print_any(json_part pljson_element, spaces boolean default true, buf in out nocopy clob, line_length number default 0, erase_clob boolean default true);
|
||||||
|
|
||||||
|
procedure dbms_output_clob(my_clob clob, delim varchar2, jsonp varchar2 default null);
|
||||||
|
procedure htp_output_clob(my_clob clob, jsonp varchar2 default null);
|
||||||
|
-- made public just for testing/profiling...
|
||||||
|
function escapeString(str varchar2) return varchar2;
|
||||||
|
|
||||||
|
end pljson_printer;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package body pljson_printer as
|
||||||
|
max_line_len number := 0;
|
||||||
|
cur_line_len number := 0;
|
||||||
|
|
||||||
|
-- associative array used inside escapeString to cache the escaped version of every character
|
||||||
|
-- escaped so far (example: char_map('"') contains the '\"' string)
|
||||||
|
-- (if the character does not need to be escaped, the character is stored unchanged in the array itself)
|
||||||
|
-- type Rmap_char is record(buf varchar2(40), len integer);
|
||||||
|
type Tmap_char_string is table of varchar2(40) index by varchar2(1 char); /* index by unicode char */
|
||||||
|
char_map Tmap_char_string;
|
||||||
|
-- since char_map the associative array is a global variable reused across multiple calls to escapeString,
|
||||||
|
-- i need to be able to detect that the escape_solidus or ascii_output global parameters have been changed,
|
||||||
|
-- in order to clear it and avoid using escape sequences that have been cached using the previous values
|
||||||
|
char_map_escape_solidus boolean := escape_solidus;
|
||||||
|
char_map_ascii_output boolean := ascii_output;
|
||||||
|
|
||||||
|
function llcheck(str in varchar2) return varchar2 as
|
||||||
|
begin
|
||||||
|
--dbms_output.put_line(cur_line_len || ' : ' || str);
|
||||||
|
if (max_line_len > 0 and length(str)+cur_line_len > max_line_len) then
|
||||||
|
cur_line_len := length(str);
|
||||||
|
return newline_char || str;
|
||||||
|
else
|
||||||
|
cur_line_len := cur_line_len + length(str);
|
||||||
|
return str;
|
||||||
|
end if;
|
||||||
|
end llcheck;
|
||||||
|
|
||||||
|
-- escapes a single character.
|
||||||
|
function escapeChar(ch char) return varchar2 deterministic is
|
||||||
|
result varchar2(20);
|
||||||
|
begin
|
||||||
|
--backspace b = U+0008
|
||||||
|
--formfeed f = U+000C
|
||||||
|
--newline n = U+000A
|
||||||
|
--carret r = U+000D
|
||||||
|
--tabulator t = U+0009
|
||||||
|
result := ch;
|
||||||
|
|
||||||
|
case ch
|
||||||
|
when chr( 8) then result := '\b';
|
||||||
|
when chr( 9) then result := '\t';
|
||||||
|
when chr(10) then result := '\n';
|
||||||
|
when chr(12) then result := '\f';
|
||||||
|
when chr(13) then result := '\r';
|
||||||
|
when chr(34) then result := '\"';
|
||||||
|
when chr(47) then if (escape_solidus) then result := '\/'; end if;
|
||||||
|
when chr(92) then result := '\\';
|
||||||
|
/* WARNING: ascii() returns PLS_INTEGER and large unicode code points can be negative */
|
||||||
|
else if (ascii(ch) >= 0 and ascii(ch) < 32) then
|
||||||
|
result := '\u' || replace(substr(to_char(ascii(ch), 'XXXX'), 2, 4), ' ', '0');
|
||||||
|
elsif (ascii_output) then
|
||||||
|
result := replace(asciistr(ch), '\', '\u');
|
||||||
|
end if;
|
||||||
|
end case;
|
||||||
|
return result;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function escapeString(str varchar2) return varchar2 as
|
||||||
|
sb varchar2(32767 byte) := '';
|
||||||
|
buf varchar2(40);
|
||||||
|
ch varchar2(1 char); /* unicode char */
|
||||||
|
begin
|
||||||
|
if (str is null) then return ''; end if;
|
||||||
|
|
||||||
|
-- clear the cache if global parameters have been changed
|
||||||
|
if char_map_escape_solidus <> escape_solidus or
|
||||||
|
char_map_ascii_output <> ascii_output
|
||||||
|
then
|
||||||
|
char_map.delete;
|
||||||
|
char_map_escape_solidus := escape_solidus;
|
||||||
|
char_map_ascii_output := ascii_output;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
for i in 1 .. length(str) loop
|
||||||
|
ch := substr(str, i, 1 ) ;
|
||||||
|
|
||||||
|
begin
|
||||||
|
-- it this char has already been processed, I have cached its escaped value
|
||||||
|
buf:=char_map(ch);
|
||||||
|
exception when no_Data_found then
|
||||||
|
-- otherwise, i convert the value and add it to the cache
|
||||||
|
buf := escapeChar(ch);
|
||||||
|
char_map(ch) := buf;
|
||||||
|
end;
|
||||||
|
|
||||||
|
sb := sb || buf;
|
||||||
|
end loop;
|
||||||
|
return sb;
|
||||||
|
end escapeString;
|
||||||
|
|
||||||
|
function newline(spaces boolean) return varchar2 as
|
||||||
|
begin
|
||||||
|
cur_line_len := 0;
|
||||||
|
if (spaces) then return newline_char; else return ''; end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
/* function get_schema return varchar2 as
|
||||||
|
begin
|
||||||
|
return sys_context('userenv', 'current_schema');
|
||||||
|
end;
|
||||||
|
*/
|
||||||
|
function tab(indent number, spaces boolean) return varchar2 as
|
||||||
|
i varchar(200) := '';
|
||||||
|
begin
|
||||||
|
if (not spaces) then return ''; end if;
|
||||||
|
for x in 1 .. indent loop i := i || indent_string; end loop;
|
||||||
|
return i;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function getCommaSep(spaces boolean) return varchar2 as
|
||||||
|
begin
|
||||||
|
if (spaces) then return ', '; else return ','; end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function getMemName(mem pljson_element, spaces boolean) return varchar2 as
|
||||||
|
begin
|
||||||
|
if (spaces) then
|
||||||
|
return llcheck('"'||escapeString(mem.mapname)||'"') || llcheck(' : ');
|
||||||
|
else
|
||||||
|
return llcheck('"'||escapeString(mem.mapname)||'"') || llcheck(':');
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
/* Clob method start here */
|
||||||
|
procedure add_to_clob(buf_lob in out nocopy clob, buf_str in out nocopy varchar2, str varchar2) as
|
||||||
|
begin
|
||||||
|
-- if (length(str) > 5000 - length(buf_str)) then
|
||||||
|
if (lengthb(str) > 32767 - lengthb(buf_str)) then
|
||||||
|
-- dbms_lob.writeappend(buf_lob, length2(buf_str), buf_str);
|
||||||
|
dbms_lob.append(buf_lob, buf_str);
|
||||||
|
buf_str := str;
|
||||||
|
else
|
||||||
|
buf_str := buf_str || str;
|
||||||
|
end if;
|
||||||
|
end add_to_clob;
|
||||||
|
|
||||||
|
procedure flush_clob(buf_lob in out nocopy clob, buf_str in out nocopy varchar2) as
|
||||||
|
begin
|
||||||
|
-- dbms_lob.writeappend(buf_lob, length2(buf_str), buf_str);
|
||||||
|
dbms_lob.append(buf_lob, buf_str);
|
||||||
|
end flush_clob;
|
||||||
|
|
||||||
|
procedure ppObj(obj pljson, indent number, buf in out nocopy clob, spaces boolean, buf_str in out nocopy varchar2);
|
||||||
|
|
||||||
|
procedure ppString(elem pljson_string, buf in out nocopy clob, buf_str in out nocopy varchar2) is
|
||||||
|
offset number := 1;
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2016-01-21 limit to 5000 chars */
|
||||||
|
v_str varchar(5000 char);
|
||||||
|
amount number := 5000; /* chunk size for use in escapeString, less than this number may be copied */
|
||||||
|
begin
|
||||||
|
if empty_string_as_null and elem.extended_str is null and elem.str is null then
|
||||||
|
add_to_clob(buf, buf_str, 'null');
|
||||||
|
else
|
||||||
|
add_to_clob(buf, buf_str, case when elem.num = 1 then '"' else '/**/' end);
|
||||||
|
if (elem.extended_str is not null) then --clob implementation
|
||||||
|
while (offset <= dbms_lob.getlength(elem.extended_str)) loop
|
||||||
|
dbms_lob.read(elem.extended_str, amount, offset, v_str);
|
||||||
|
if (elem.num = 1) then
|
||||||
|
add_to_clob(buf, buf_str, escapeString(v_str));
|
||||||
|
else
|
||||||
|
add_to_clob(buf, buf_str, v_str);
|
||||||
|
end if;
|
||||||
|
offset := offset + amount;
|
||||||
|
end loop;
|
||||||
|
else
|
||||||
|
if (elem.num = 1) then
|
||||||
|
while (offset <= length(elem.str)) loop
|
||||||
|
v_str:=substr(elem.str, offset, amount);
|
||||||
|
add_to_clob(buf, buf_str, escapeString(v_str));
|
||||||
|
offset := offset + amount;
|
||||||
|
end loop;
|
||||||
|
else
|
||||||
|
add_to_clob(buf, buf_str, elem.str);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
add_to_clob(buf, buf_str, case when elem.num = 1 then '"' else '/**/' end);
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ppEA(input pljson_list, indent number, buf in out nocopy clob, spaces boolean, buf_str in out nocopy varchar2) as
|
||||||
|
elem pljson_element;
|
||||||
|
arr pljson_element_array := input.list_data;
|
||||||
|
numbuf varchar2(4000);
|
||||||
|
begin
|
||||||
|
for y in 1 .. arr.count loop
|
||||||
|
elem := arr(y);
|
||||||
|
if (elem is not null) then
|
||||||
|
case elem.typeval
|
||||||
|
/* number */
|
||||||
|
when 4 then
|
||||||
|
numbuf := treat(elem as pljson_number).number_toString();
|
||||||
|
add_to_clob(buf, buf_str, llcheck(numbuf));
|
||||||
|
/* string */
|
||||||
|
when 3 then
|
||||||
|
ppString(treat(elem as pljson_string), buf, buf_str);
|
||||||
|
/* bool */
|
||||||
|
when 5 then
|
||||||
|
if (elem.get_bool()) then
|
||||||
|
add_to_clob(buf, buf_str, llcheck('true'));
|
||||||
|
else
|
||||||
|
add_to_clob(buf, buf_str, llcheck('false'));
|
||||||
|
end if;
|
||||||
|
/* null */
|
||||||
|
when 6 then
|
||||||
|
add_to_clob(buf, buf_str, llcheck('null'));
|
||||||
|
/* array */
|
||||||
|
when 2 then
|
||||||
|
add_to_clob(buf, buf_str, llcheck('['));
|
||||||
|
ppEA(treat(elem as pljson_list), indent, buf, spaces, buf_str);
|
||||||
|
add_to_clob(buf, buf_str, llcheck(']'));
|
||||||
|
/* object */
|
||||||
|
when 1 then
|
||||||
|
ppObj(treat(elem as pljson), indent, buf, spaces, buf_str);
|
||||||
|
else
|
||||||
|
add_to_clob(buf, buf_str, llcheck(elem.get_type));
|
||||||
|
end case;
|
||||||
|
end if;
|
||||||
|
if (y != arr.count) then add_to_clob(buf, buf_str, llcheck(getCommaSep(spaces))); end if;
|
||||||
|
end loop;
|
||||||
|
end ppEA;
|
||||||
|
|
||||||
|
procedure ppMem(mem pljson_element, indent number, buf in out nocopy clob, spaces boolean, buf_str in out nocopy varchar2) as
|
||||||
|
numbuf varchar2(4000);
|
||||||
|
begin
|
||||||
|
add_to_clob(buf, buf_str, llcheck(tab(indent, spaces)) || llcheck(getMemName(mem, spaces)));
|
||||||
|
case mem.typeval
|
||||||
|
/* number */
|
||||||
|
when 4 then
|
||||||
|
numbuf := treat(mem as pljson_number).number_toString();
|
||||||
|
add_to_clob(buf, buf_str, llcheck(numbuf));
|
||||||
|
/* string */
|
||||||
|
when 3 then
|
||||||
|
ppString(treat(mem as pljson_string), buf, buf_str);
|
||||||
|
/* bool */
|
||||||
|
when 5 then
|
||||||
|
if (mem.get_bool()) then
|
||||||
|
add_to_clob(buf, buf_str, llcheck('true'));
|
||||||
|
else
|
||||||
|
add_to_clob(buf, buf_str, llcheck('false'));
|
||||||
|
end if;
|
||||||
|
/* null */
|
||||||
|
when 6 then
|
||||||
|
add_to_clob(buf, buf_str, llcheck('null'));
|
||||||
|
/* array */
|
||||||
|
when 2 then
|
||||||
|
add_to_clob(buf, buf_str, llcheck('['));
|
||||||
|
ppEA(treat(mem as pljson_list), indent, buf, spaces, buf_str);
|
||||||
|
add_to_clob(buf, buf_str, llcheck(']'));
|
||||||
|
/* object */
|
||||||
|
when 1 then
|
||||||
|
ppObj(treat(mem as pljson), indent, buf, spaces, buf_str);
|
||||||
|
else
|
||||||
|
add_to_clob(buf, buf_str, llcheck(mem.get_type));
|
||||||
|
end case;
|
||||||
|
end ppMem;
|
||||||
|
|
||||||
|
procedure ppObj(obj pljson, indent number, buf in out nocopy clob, spaces boolean, buf_str in out nocopy varchar2) as
|
||||||
|
begin
|
||||||
|
add_to_clob(buf, buf_str, llcheck('{') || newline(spaces));
|
||||||
|
for m in 1 .. obj.json_data.count loop
|
||||||
|
ppMem(obj.json_data(m), indent+1, buf, spaces, buf_str);
|
||||||
|
if (m != obj.json_data.count) then
|
||||||
|
add_to_clob(buf, buf_str, llcheck(',') || newline(spaces));
|
||||||
|
else
|
||||||
|
add_to_clob(buf, buf_str, newline(spaces));
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
add_to_clob(buf, buf_str, llcheck(tab(indent, spaces)) || llcheck('}')); -- || chr(13);
|
||||||
|
end ppObj;
|
||||||
|
|
||||||
|
procedure pretty_print(obj pljson, spaces boolean default true, buf in out nocopy clob, line_length number default 0, erase_clob boolean default true) as
|
||||||
|
buf_str varchar2(32767);
|
||||||
|
amount number := dbms_lob.getlength(buf);
|
||||||
|
begin
|
||||||
|
if (erase_clob and amount > 0) then
|
||||||
|
dbms_lob.trim(buf, 0);
|
||||||
|
-- dbms_lob.erase(buf, amount);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
max_line_len := line_length;
|
||||||
|
cur_line_len := 0;
|
||||||
|
ppObj(obj, 0, buf, spaces, buf_str);
|
||||||
|
flush_clob(buf, buf_str);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure pretty_print_list(obj pljson_list, spaces boolean default true, buf in out nocopy clob, line_length number default 0, erase_clob boolean default true) as
|
||||||
|
buf_str varchar2(32767);
|
||||||
|
amount number := dbms_lob.getlength(buf);
|
||||||
|
begin
|
||||||
|
if (erase_clob and amount > 0) then
|
||||||
|
dbms_lob.trim(buf, 0);
|
||||||
|
-- dbms_lob.erase(buf, amount);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
max_line_len := line_length;
|
||||||
|
cur_line_len := 0;
|
||||||
|
add_to_clob(buf, buf_str, llcheck('['));
|
||||||
|
ppEA(obj, 0, buf, spaces, buf_str);
|
||||||
|
add_to_clob(buf, buf_str, llcheck(']'));
|
||||||
|
flush_clob(buf, buf_str);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure pretty_print_any(json_part pljson_element, spaces boolean default true, buf in out nocopy clob, line_length number default 0, erase_clob boolean default true) as
|
||||||
|
buf_str varchar2(32767) := '';
|
||||||
|
numbuf varchar2(4000);
|
||||||
|
amount number := dbms_lob.getlength(buf);
|
||||||
|
begin
|
||||||
|
if (erase_clob and amount > 0) then
|
||||||
|
dbms_lob.trim(buf, 0);
|
||||||
|
-- dbms_lob.erase(buf, amount);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
case json_part.typeval
|
||||||
|
/* number */
|
||||||
|
when 4 then
|
||||||
|
numbuf := treat(json_part as pljson_number).number_toString();
|
||||||
|
add_to_clob(buf, buf_str, numbuf);
|
||||||
|
/* string */
|
||||||
|
when 3 then
|
||||||
|
ppString(treat(json_part as pljson_string), buf, buf_str);
|
||||||
|
/* bool */
|
||||||
|
when 5 then
|
||||||
|
if (json_part.get_bool()) then
|
||||||
|
add_to_clob(buf, buf_str, 'true');
|
||||||
|
else
|
||||||
|
add_to_clob(buf, buf_str, 'false');
|
||||||
|
end if;
|
||||||
|
/* null */
|
||||||
|
when 6 then
|
||||||
|
add_to_clob(buf, buf_str, 'null');
|
||||||
|
/* array */
|
||||||
|
when 2 then
|
||||||
|
pretty_print_list(pljson_list(json_part), spaces, buf, line_length);
|
||||||
|
return;
|
||||||
|
/* object */
|
||||||
|
when 1 then
|
||||||
|
pretty_print(pljson(json_part), spaces, buf, line_length);
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
add_to_clob(buf, buf_str, 'unknown type:' || json_part.get_type);
|
||||||
|
end case;
|
||||||
|
flush_clob(buf, buf_str);
|
||||||
|
end;
|
||||||
|
|
||||||
|
/* Clob method end here */
|
||||||
|
|
||||||
|
/* Varchar2 method start here */
|
||||||
|
procedure add_buf (buf in out nocopy varchar2, str in varchar2) as
|
||||||
|
begin
|
||||||
|
if (lengthb(str)>32767-lengthb(buf)) then
|
||||||
|
raise_application_error(-20001,'Length of result JSON more than 32767 bytes. Use to_clob() procedures');
|
||||||
|
end if;
|
||||||
|
buf := buf || str;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ppString(elem pljson_string, buf in out nocopy varchar2) is
|
||||||
|
offset number := 1;
|
||||||
|
/* E.I.Sarmas (github.com/dsnz) 2016-01-21 limit to 5000 chars */
|
||||||
|
v_str varchar(5000 char);
|
||||||
|
amount number := 5000; /* chunk size for use in escapeString, less than this number may be copied */
|
||||||
|
begin
|
||||||
|
if empty_string_as_null and elem.extended_str is null and elem.str is null then
|
||||||
|
add_buf(buf, 'null');
|
||||||
|
else
|
||||||
|
add_buf(buf, case when elem.num = 1 then '"' else '/**/' end);
|
||||||
|
if (elem.extended_str is not null) then --clob implementation
|
||||||
|
while (offset <= dbms_lob.getlength(elem.extended_str)) loop
|
||||||
|
dbms_lob.read(elem.extended_str, amount, offset, v_str);
|
||||||
|
if (elem.num = 1) then
|
||||||
|
add_buf(buf, escapeString(v_str));
|
||||||
|
else
|
||||||
|
add_buf(buf, v_str);
|
||||||
|
end if;
|
||||||
|
offset := offset + amount;
|
||||||
|
end loop;
|
||||||
|
else
|
||||||
|
if (elem.num = 1) then
|
||||||
|
while (offset <= length(elem.str)) loop
|
||||||
|
v_str:=substr(elem.str, offset, amount);
|
||||||
|
add_buf(buf, escapeString(v_str));
|
||||||
|
offset := offset + amount;
|
||||||
|
end loop;
|
||||||
|
else
|
||||||
|
add_buf(buf, elem.str);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
add_buf(buf, case when elem.num = 1 then '"' else '/**/' end);
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ppObj(obj pljson, indent number, buf in out nocopy varchar2, spaces boolean);
|
||||||
|
|
||||||
|
procedure ppEA(input pljson_list, indent number, buf in out varchar2, spaces boolean) as
|
||||||
|
elem pljson_element;
|
||||||
|
arr pljson_element_array := input.list_data;
|
||||||
|
str varchar2(400);
|
||||||
|
begin
|
||||||
|
for y in 1 .. arr.count loop
|
||||||
|
elem := arr(y);
|
||||||
|
if (elem is not null) then
|
||||||
|
case elem.typeval
|
||||||
|
/* number */
|
||||||
|
when 4 then
|
||||||
|
str := treat(elem as pljson_number).number_toString();
|
||||||
|
add_buf(buf, llcheck(str));
|
||||||
|
/* string */
|
||||||
|
when 3 then
|
||||||
|
ppString(treat(elem as pljson_string), buf);
|
||||||
|
/* bool */
|
||||||
|
when 5 then
|
||||||
|
if (elem.get_bool()) then
|
||||||
|
add_buf (buf, llcheck('true'));
|
||||||
|
else
|
||||||
|
add_buf (buf, llcheck('false'));
|
||||||
|
end if;
|
||||||
|
/* null */
|
||||||
|
when 6 then
|
||||||
|
add_buf (buf, llcheck('null'));
|
||||||
|
/* array */
|
||||||
|
when 2 then
|
||||||
|
add_buf( buf, llcheck('['));
|
||||||
|
ppEA(treat(elem as pljson_list), indent, buf, spaces);
|
||||||
|
add_buf( buf, llcheck(']'));
|
||||||
|
/* object */
|
||||||
|
when 1 then
|
||||||
|
ppObj(treat(elem as pljson), indent, buf, spaces);
|
||||||
|
else
|
||||||
|
add_buf (buf, llcheck(elem.get_type)); /* should never happen */
|
||||||
|
end case;
|
||||||
|
end if;
|
||||||
|
if (y != arr.count) then add_buf(buf, llcheck(getCommaSep(spaces))); end if;
|
||||||
|
end loop;
|
||||||
|
end ppEA;
|
||||||
|
|
||||||
|
procedure ppMem(mem pljson_element, indent number, buf in out nocopy varchar2, spaces boolean) as
|
||||||
|
str varchar2(400) := '';
|
||||||
|
begin
|
||||||
|
add_buf(buf, llcheck(tab(indent, spaces)) || getMemName(mem, spaces));
|
||||||
|
case mem.typeval
|
||||||
|
/* number */
|
||||||
|
when 4 then
|
||||||
|
str := treat(mem as pljson_number).number_toString();
|
||||||
|
add_buf(buf, llcheck(str));
|
||||||
|
/* string */
|
||||||
|
when 3 then
|
||||||
|
ppString(treat(mem as pljson_string), buf);
|
||||||
|
/* bool */
|
||||||
|
when 5 then
|
||||||
|
if (mem.get_bool()) then
|
||||||
|
add_buf(buf, llcheck('true'));
|
||||||
|
else
|
||||||
|
add_buf(buf, llcheck('false'));
|
||||||
|
end if;
|
||||||
|
/* null */
|
||||||
|
when 6 then
|
||||||
|
add_buf(buf, llcheck('null'));
|
||||||
|
/* array */
|
||||||
|
when 2 then
|
||||||
|
add_buf(buf, llcheck('['));
|
||||||
|
ppEA(treat(mem as pljson_list), indent, buf, spaces);
|
||||||
|
add_buf(buf, llcheck(']'));
|
||||||
|
/* object */
|
||||||
|
when 1 then
|
||||||
|
ppObj(treat(mem as pljson), indent, buf, spaces);
|
||||||
|
else
|
||||||
|
add_buf(buf, llcheck(mem.get_type)); /* should never happen */
|
||||||
|
end case;
|
||||||
|
end ppMem;
|
||||||
|
|
||||||
|
procedure ppObj(obj pljson, indent number, buf in out nocopy varchar2, spaces boolean) as
|
||||||
|
begin
|
||||||
|
add_buf (buf, llcheck('{') || newline(spaces));
|
||||||
|
for m in 1 .. obj.json_data.count loop
|
||||||
|
ppMem(obj.json_data(m), indent+1, buf, spaces);
|
||||||
|
if (m != obj.json_data.count) then
|
||||||
|
add_buf(buf, llcheck(',') || newline(spaces));
|
||||||
|
else
|
||||||
|
add_buf(buf, newline(spaces));
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
add_buf(buf, llcheck(tab(indent, spaces)) || llcheck('}')); -- || chr(13);
|
||||||
|
end ppObj;
|
||||||
|
|
||||||
|
function pretty_print(obj pljson, spaces boolean default true, line_length number default 0) return varchar2 as
|
||||||
|
buf varchar2(32767 byte) := '';
|
||||||
|
begin
|
||||||
|
max_line_len := line_length;
|
||||||
|
cur_line_len := 0;
|
||||||
|
ppObj(obj, 0, buf, spaces);
|
||||||
|
return buf;
|
||||||
|
end pretty_print;
|
||||||
|
|
||||||
|
function pretty_print_list(obj pljson_list, spaces boolean default true, line_length number default 0) return varchar2 as
|
||||||
|
buf varchar2(32767 byte) :='';
|
||||||
|
begin
|
||||||
|
max_line_len := line_length;
|
||||||
|
cur_line_len := 0;
|
||||||
|
add_buf(buf, llcheck('['));
|
||||||
|
ppEA(obj, 0, buf, spaces);
|
||||||
|
add_buf(buf, llcheck(']'));
|
||||||
|
return buf;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function pretty_print_any(json_part pljson_element, spaces boolean default true, line_length number default 0) return varchar2 as
|
||||||
|
buf varchar2(32767) := '';
|
||||||
|
begin
|
||||||
|
case json_part.typeval
|
||||||
|
/* number */
|
||||||
|
when 4 then
|
||||||
|
buf := treat(json_part as pljson_number).number_toString();
|
||||||
|
/* string */
|
||||||
|
when 3 then
|
||||||
|
ppString(treat(json_part as pljson_string), buf);
|
||||||
|
/* bool */
|
||||||
|
when 5 then
|
||||||
|
if (json_part.get_bool()) then buf := 'true'; else buf := 'false'; end if;
|
||||||
|
/* null */
|
||||||
|
when 6 then
|
||||||
|
buf := 'null';
|
||||||
|
/* array */
|
||||||
|
when 2 then
|
||||||
|
buf := pretty_print_list(pljson_list(json_part), spaces, line_length);
|
||||||
|
/* object */
|
||||||
|
when 1 then
|
||||||
|
buf := pretty_print(pljson(json_part), spaces, line_length);
|
||||||
|
else
|
||||||
|
buf := 'weird error: ' || json_part.get_type;
|
||||||
|
end case;
|
||||||
|
return buf;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure dbms_output_clob(my_clob clob, delim varchar2, jsonp varchar2 default null) as
|
||||||
|
prev number := 1;
|
||||||
|
indx number := 1;
|
||||||
|
size_of_nl number := length2(delim);
|
||||||
|
v_str varchar2(32767);
|
||||||
|
amount number;
|
||||||
|
max_string_chars number := 5000; /* chunk size, less than this number may be copied */
|
||||||
|
begin
|
||||||
|
if (jsonp is not null) then dbms_output.put_line(jsonp||'('); end if;
|
||||||
|
while (indx != 0) loop
|
||||||
|
--read every line
|
||||||
|
indx := dbms_lob.instr(my_clob, delim, prev+1);
|
||||||
|
--dbms_output.put_line(prev || ' to ' || indx);
|
||||||
|
|
||||||
|
if (indx = 0) then
|
||||||
|
--emit from prev to end;
|
||||||
|
amount := max_string_chars;
|
||||||
|
--dbms_output.put_line(' mycloblen ' || dbms_lob.getlength(my_clob));
|
||||||
|
loop
|
||||||
|
dbms_lob.read(my_clob, amount, prev, v_str);
|
||||||
|
dbms_output.put_line(v_str);
|
||||||
|
prev := prev+amount;
|
||||||
|
exit when prev >= dbms_lob.getlength(my_clob);
|
||||||
|
end loop;
|
||||||
|
else
|
||||||
|
amount := indx - prev;
|
||||||
|
if (amount > max_string_chars) then
|
||||||
|
amount := max_string_chars;
|
||||||
|
--dbms_output.put_line(' mycloblen ' || dbms_lob.getlength(my_clob));
|
||||||
|
loop
|
||||||
|
dbms_lob.read(my_clob, amount, prev, v_str);
|
||||||
|
dbms_output.put_line(v_str);
|
||||||
|
prev := prev+amount;
|
||||||
|
amount := indx - prev;
|
||||||
|
exit when prev >= indx - 1;
|
||||||
|
if (amount > max_string_chars) then
|
||||||
|
amount := max_string_chars;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
prev := indx + size_of_nl;
|
||||||
|
else
|
||||||
|
dbms_lob.read(my_clob, amount, prev, v_str);
|
||||||
|
dbms_output.put_line(v_str);
|
||||||
|
prev := indx + size_of_nl;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
if (jsonp is not null) then dbms_output.put_line(')'); end if;
|
||||||
|
|
||||||
|
/* while (amount != 0) loop
|
||||||
|
indx := dbms_lob.instr(my_clob, delim, prev+1);
|
||||||
|
|
||||||
|
-- dbms_output.put_line(prev || ' to ' || indx);
|
||||||
|
if (indx = 0) then
|
||||||
|
indx := dbms_lob.getlength(my_clob)+1;
|
||||||
|
end if;
|
||||||
|
if (indx-prev > 32767) then
|
||||||
|
indx := prev+32767;
|
||||||
|
end if;
|
||||||
|
-- dbms_output.put_line(prev || ' to ' || indx);
|
||||||
|
--substr doesnt work properly on all platforms! (come on oracle - error on Oracle VM for virtualbox)
|
||||||
|
-- dbms_output.put_line(dbms_lob.substr(my_clob, indx-prev, prev));
|
||||||
|
amount := indx-prev;
|
||||||
|
-- dbms_output.put_line('amount'||amount);
|
||||||
|
dbms_lob.read(my_clob, amount, prev, v_str);
|
||||||
|
dbms_output.put_line(v_str);
|
||||||
|
prev := indx+size_of_nl;
|
||||||
|
if (amount = 32767) then prev := prev-size_of_nl-1; end if;
|
||||||
|
end loop;
|
||||||
|
if (jsonp is not null) then dbms_output.put_line(')'); end if;*/
|
||||||
|
end;
|
||||||
|
|
||||||
|
/* procedure dbms_output_clob(my_clob clob, delim varchar2, jsonp varchar2 default null) as
|
||||||
|
prev number := 1;
|
||||||
|
indx number := 1;
|
||||||
|
size_of_nl number := length2(delim);
|
||||||
|
v_str varchar2(32767);
|
||||||
|
amount number;
|
||||||
|
begin
|
||||||
|
if (jsonp is not null) then dbms_output.put_line(jsonp||'('); end if;
|
||||||
|
while (indx != 0) loop
|
||||||
|
indx := dbms_lob.instr(my_clob, delim, prev+1);
|
||||||
|
|
||||||
|
--dbms_output.put_line(prev || ' to ' || indx);
|
||||||
|
if (indx-prev > 32767) then
|
||||||
|
indx := prev+32767;
|
||||||
|
end if;
|
||||||
|
--dbms_output.put_line(prev || ' to ' || indx);
|
||||||
|
--substr doesnt work properly on all platforms! (come on oracle - error on Oracle VM for virtualbox)
|
||||||
|
if (indx = 0) then
|
||||||
|
--dbms_output.put_line(dbms_lob.substr(my_clob, dbms_lob.getlength(my_clob)-prev+size_of_nl, prev));
|
||||||
|
amount := dbms_lob.getlength(my_clob)-prev+size_of_nl;
|
||||||
|
dbms_lob.read(my_clob, amount, prev, v_str);
|
||||||
|
else
|
||||||
|
--dbms_output.put_line(dbms_lob.substr(my_clob, indx-prev, prev));
|
||||||
|
amount := indx-prev;
|
||||||
|
--dbms_output.put_line('amount'||amount);
|
||||||
|
dbms_lob.read(my_clob, amount, prev, v_str);
|
||||||
|
end if;
|
||||||
|
dbms_output.put_line(v_str);
|
||||||
|
prev := indx+size_of_nl;
|
||||||
|
if (amount = 32767) then prev := prev-size_of_nl-1; end if;
|
||||||
|
end loop;
|
||||||
|
if (jsonp is not null) then dbms_output.put_line(')'); end if;
|
||||||
|
end;
|
||||||
|
*/
|
||||||
|
|
||||||
|
procedure htp_output_clob(my_clob clob, jsonp varchar2 default null) as
|
||||||
|
/*amount number := 4096;
|
||||||
|
pos number := 1;
|
||||||
|
len number;
|
||||||
|
*/
|
||||||
|
l_amt number default 4096;
|
||||||
|
l_off number default 1;
|
||||||
|
l_str varchar2(32000);
|
||||||
|
begin
|
||||||
|
if (jsonp is not null) then htp.prn(jsonp||'('); end if;
|
||||||
|
|
||||||
|
begin
|
||||||
|
loop
|
||||||
|
dbms_lob.read( my_clob, l_amt, l_off, l_str );
|
||||||
|
|
||||||
|
-- it is vital to use htp.PRN to avoid
|
||||||
|
-- spurious line feeds getting added to your
|
||||||
|
-- document
|
||||||
|
htp.prn( l_str );
|
||||||
|
l_off := l_off+l_amt;
|
||||||
|
end loop;
|
||||||
|
exception
|
||||||
|
when no_data_found then NULL;
|
||||||
|
end;
|
||||||
|
|
||||||
|
/*
|
||||||
|
len := dbms_lob.getlength(my_clob);
|
||||||
|
|
||||||
|
while (pos < len) loop
|
||||||
|
htp.prn(dbms_lob.substr(my_clob, amount, pos)); -- should I replace substr with dbms_lob.read?
|
||||||
|
--dbms_output.put_line(dbms_lob.substr(my_clob, amount, pos));
|
||||||
|
pos := pos + amount;
|
||||||
|
end loop;
|
||||||
|
*/
|
||||||
|
if (jsonp is not null) then htp.prn(')'); end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end pljson_printer;```
|
||||||
204
docs/packages/PLJSON_UT.md
Normal file
204
docs/packages/PLJSON_UT.md
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
# PLJSON_UT
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package pljson_ut as
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* E.I.Sarmas (github.com/dsnz) 2017-07-22
|
||||||
|
*
|
||||||
|
* Simple unit test framework for pljson
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
suite_id number;
|
||||||
|
suite_name varchar2(100);
|
||||||
|
file_name varchar2(100);
|
||||||
|
pass_count number;
|
||||||
|
fail_count number;
|
||||||
|
total_count number;
|
||||||
|
|
||||||
|
case_name varchar2(100);
|
||||||
|
case_pass number;
|
||||||
|
case_fail number;
|
||||||
|
case_total number;
|
||||||
|
|
||||||
|
INDENT_1 varchar2(10) := ' ';
|
||||||
|
INDENT_2 varchar2(10) := ' ';
|
||||||
|
|
||||||
|
procedure testsuite(suite_name_ varchar2, file_name_ varchar2);
|
||||||
|
procedure testcase(case_name_ varchar2);
|
||||||
|
|
||||||
|
procedure pass(test_name varchar2 := null);
|
||||||
|
procedure fail(test_name varchar2 := null);
|
||||||
|
|
||||||
|
procedure assertTrue(b boolean, test_name varchar2 := null);
|
||||||
|
procedure assertFalse(b boolean, test_name varchar2 := null);
|
||||||
|
|
||||||
|
procedure testsuite_report;
|
||||||
|
|
||||||
|
procedure startup;
|
||||||
|
procedure shutdown;
|
||||||
|
|
||||||
|
end pljson_ut;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package body pljson_ut as
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* E.I.Sarmas (github.com/dsnz) 2017-07-22
|
||||||
|
*
|
||||||
|
* Simple unit test framework for pljson
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
procedure testsuite(suite_name_ varchar2, file_name_ varchar2) is
|
||||||
|
begin
|
||||||
|
suite_id := suite_id + 1;
|
||||||
|
suite_name := suite_name_;
|
||||||
|
file_name := file_name_;
|
||||||
|
pass_count := 0;
|
||||||
|
fail_count := 0;
|
||||||
|
total_count := 0;
|
||||||
|
dbms_output.put_line(suite_name_);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure testcase(case_name_ varchar2) is
|
||||||
|
begin
|
||||||
|
case_name := case_name_;
|
||||||
|
case_pass := 0;
|
||||||
|
case_fail := 0;
|
||||||
|
case_total := 0;
|
||||||
|
dbms_output.put_line(INDENT_1 || case_name_);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure pass(test_name varchar2 := null) is
|
||||||
|
begin
|
||||||
|
if (case_total = 0) then
|
||||||
|
pass_count := pass_count + 1;
|
||||||
|
total_count := total_count + 1;
|
||||||
|
end if;
|
||||||
|
case_pass := case_pass + 1;
|
||||||
|
case_total := case_total + 1;
|
||||||
|
if (test_name is not null) then
|
||||||
|
dbms_output.put_line(INDENT_2 || 'OK: '|| test_name);
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure fail(test_name varchar2 := null) is
|
||||||
|
begin
|
||||||
|
if (case_fail = 0) then
|
||||||
|
fail_count := fail_count + 1;
|
||||||
|
if (case_total = 0) then
|
||||||
|
total_count := total_count + 1;
|
||||||
|
else
|
||||||
|
pass_count := pass_count - 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
case_fail := case_fail + 1;
|
||||||
|
case_total := case_total + 1;
|
||||||
|
if (test_name is not null) then
|
||||||
|
dbms_output.put_line(INDENT_2 || 'FAILED: '|| test_name);
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure assertTrue(b boolean, test_name varchar2 := null) is
|
||||||
|
begin
|
||||||
|
if (b) then
|
||||||
|
pass(test_name);
|
||||||
|
else
|
||||||
|
fail(test_name);
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure assertFalse(b boolean, test_name varchar2 := null) is
|
||||||
|
begin
|
||||||
|
if (not b) then
|
||||||
|
pass(test_name);
|
||||||
|
else
|
||||||
|
fail(test_name);
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure testsuite_report is
|
||||||
|
begin
|
||||||
|
dbms_output.put_line('');
|
||||||
|
dbms_output.put_line(
|
||||||
|
total_count || ' tests, '
|
||||||
|
|| pass_count || ' passed, '
|
||||||
|
|| fail_count || ' failed'
|
||||||
|
);
|
||||||
|
|
||||||
|
execute immediate 'insert into pljson_testsuite values (:1, :2, :3, :4, :5, :6)'
|
||||||
|
using suite_id, suite_name, file_name, pass_count, fail_count, total_count;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure startup is
|
||||||
|
begin
|
||||||
|
suite_id := 0;
|
||||||
|
execute immediate 'truncate table pljson_testsuite';
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure shutdown is
|
||||||
|
begin
|
||||||
|
commit;
|
||||||
|
|
||||||
|
dbms_output.put_line('');
|
||||||
|
for rec in (
|
||||||
|
select suite_id, suite_name, passed, failed, total, file_name
|
||||||
|
from (
|
||||||
|
select 3 s, suite_id,
|
||||||
|
lpad(suite_name, 30) suite_name,
|
||||||
|
to_char(passed, '999999') passed,
|
||||||
|
to_char(failed, '999999') failed,
|
||||||
|
to_char(total, '999999') total,
|
||||||
|
lpad(file_name, 30) file_name
|
||||||
|
from pljson_testsuite
|
||||||
|
union
|
||||||
|
select 1 s, 0 suite_id,
|
||||||
|
lpad('SUITE_NAME', 30) suite_name,
|
||||||
|
lpad('PASSED', 7) passed,
|
||||||
|
lpad('FAILED', 7) failed,
|
||||||
|
lpad('TOTAL', 7) total,
|
||||||
|
lpad('FILE_NAME', 30) file_name
|
||||||
|
from dual
|
||||||
|
union
|
||||||
|
select 5 s, 0,
|
||||||
|
lpad('ALL TESTS', 30) suite_name,
|
||||||
|
to_char(sum(passed), '999999') passed,
|
||||||
|
to_char(sum(failed), '999999') failed,
|
||||||
|
to_char(sum(total), '999999') total,
|
||||||
|
lpad(' ', 30) file_name
|
||||||
|
from pljson_testsuite
|
||||||
|
union
|
||||||
|
select 2 s, 0 suite_id,
|
||||||
|
lpad('-', 30, '-') suite_name,
|
||||||
|
lpad('-', 7, '-') passed,
|
||||||
|
lpad('-', 7, '-') failed,
|
||||||
|
lpad('-', 7, '-') total,
|
||||||
|
lpad('-', 30, '-') file_name
|
||||||
|
from dual
|
||||||
|
union
|
||||||
|
select 4 s, 0 suite_id,
|
||||||
|
lpad('-', 30, '-') suite_name,
|
||||||
|
lpad('-', 7, '-') passed,
|
||||||
|
lpad('-', 7, '-') failed,
|
||||||
|
lpad('-', 7, '-') total,
|
||||||
|
lpad('-', 30, '-') file_name
|
||||||
|
from dual
|
||||||
|
order by s, suite_id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
loop
|
||||||
|
dbms_output.put_line(
|
||||||
|
rec.suite_name||' '||rec.passed||' '||rec.failed||' '||rec.total||' '||rec.file_name
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end pljson_ut;```
|
||||||
370
docs/packages/PLJSON_UTIL_PKG.md
Normal file
370
docs/packages/PLJSON_UTIL_PKG.md
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
# PLJSON_UTIL_PKG
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package pljson_util_pkg authid current_user as
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Purpose: JSON utilities for PL/SQL
|
||||||
|
see http://ora-00001.blogspot.com/
|
||||||
|
|
||||||
|
Remarks:
|
||||||
|
|
||||||
|
Who Date Description
|
||||||
|
------ ---------- -------------------------------------
|
||||||
|
MBR 30.01.2010 Created
|
||||||
|
JKR 01.05.2010 Edited to fit in PL/JSON
|
||||||
|
JKR 19.01.2011 Newest stylesheet + bugfix handling
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- generate JSON from REF Cursor
|
||||||
|
function ref_cursor_to_json (p_ref_cursor in sys_refcursor,
|
||||||
|
p_max_rows in number := null,
|
||||||
|
p_skip_rows in number := null) return pljson_list;
|
||||||
|
|
||||||
|
-- generate JSON from SQL statement
|
||||||
|
function sql_to_json (p_sql in varchar2,
|
||||||
|
p_max_rows in number := null,
|
||||||
|
p_skip_rows in number := null) return pljson_list;
|
||||||
|
|
||||||
|
|
||||||
|
end pljson_util_pkg;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package body pljson_util_pkg as
|
||||||
|
scanner_exception exception;
|
||||||
|
pragma exception_init(scanner_exception, -20100);
|
||||||
|
parser_exception exception;
|
||||||
|
pragma exception_init(parser_exception, -20101);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Purpose: JSON utilities for PL/SQL
|
||||||
|
|
||||||
|
Remarks:
|
||||||
|
|
||||||
|
Who Date Description
|
||||||
|
------ ---------- -------------------------------------
|
||||||
|
MBR 30.01.2010 Created
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
function get_xml_to_json_stylesheet return varchar2 as
|
||||||
|
stylesheet varchar2(32767);
|
||||||
|
nls_numeric_characters varchar2(2);
|
||||||
|
begin
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Purpose: return XSLT stylesheet for XML to JSON transformation
|
||||||
|
|
||||||
|
Remarks: see http://code.google.com/p/xml2json-xslt/
|
||||||
|
|
||||||
|
Who Date Description
|
||||||
|
------ ---------- -------------------------------------
|
||||||
|
MBR 30.01.2010 Created
|
||||||
|
MBR 30.01.2010 Added fix for nulls
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
stylesheet := q'^<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||||
|
<!--
|
||||||
|
Copyright (c) 2006,2008 Doeke Zanstra
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. Redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<xsl:output indent="no" omit-xml-declaration="yes" method="text" encoding="UTF-8" media-type="text/x-json"/>
|
||||||
|
<xsl:strip-space elements="*"/>
|
||||||
|
<!--contant-->
|
||||||
|
<xsl:variable name="d">0123456789</xsl:variable>
|
||||||
|
|
||||||
|
<!-- ignore document text -->
|
||||||
|
<xsl:template match="text()[preceding-sibling::node() or following-sibling::node()]"/>
|
||||||
|
|
||||||
|
<!-- string -->
|
||||||
|
<xsl:template match="text()">
|
||||||
|
<xsl:call-template name="escape-string">
|
||||||
|
<xsl:with-param name="s" select="."/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- Main template for escaping strings; used by above template and for object-properties
|
||||||
|
Responsibilities: placed quotes around string, and chain up to next filter, escape-bs-string -->
|
||||||
|
<xsl:template name="escape-string">
|
||||||
|
<xsl:param name="s"/>
|
||||||
|
<xsl:text>"</xsl:text>
|
||||||
|
<xsl:call-template name="escape-bs-string">
|
||||||
|
<xsl:with-param name="s" select="$s"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
<xsl:text>"</xsl:text>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- Escape the backslash (\) before everything else. -->
|
||||||
|
<xsl:template name="escape-bs-string">
|
||||||
|
<xsl:param name="s"/>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="contains($s,'\')">
|
||||||
|
<xsl:call-template name="escape-quot-string">
|
||||||
|
<xsl:with-param name="s" select="concat(substring-before($s,'\'),'\\')"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
<xsl:call-template name="escape-bs-string">
|
||||||
|
<xsl:with-param name="s" select="substring-after($s,'\')"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:call-template name="escape-quot-string">
|
||||||
|
<xsl:with-param name="s" select="$s"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- Escape the double quote ("). -->
|
||||||
|
<xsl:template name="escape-quot-string">
|
||||||
|
<xsl:param name="s"/>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="contains($s,'"')">
|
||||||
|
<xsl:call-template name="encode-string">
|
||||||
|
<xsl:with-param name="s" select="concat(substring-before($s,'"'),'\"')"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
<xsl:call-template name="escape-quot-string">
|
||||||
|
<xsl:with-param name="s" select="substring-after($s,'"')"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:call-template name="encode-string">
|
||||||
|
<xsl:with-param name="s" select="$s"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- Replace tab, line feed and/or carriage return by its matching escape code. Can't escape backslash
|
||||||
|
or double quote here, because they don't replace characters (� becomes \t), but they prefix
|
||||||
|
characters (\ becomes \\). Besides, backslash should be seperate anyway, because it should be
|
||||||
|
processed first. This function can't do that. -->
|
||||||
|
<xsl:template name="encode-string">
|
||||||
|
<xsl:param name="s"/>
|
||||||
|
<xsl:choose>
|
||||||
|
<!-- tab -->
|
||||||
|
<xsl:when test="contains($s,'	')">
|
||||||
|
<xsl:call-template name="encode-string">
|
||||||
|
<xsl:with-param name="s" select="concat(substring-before($s,'	'),'\t',substring-after($s,'	'))"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
<!-- line feed -->
|
||||||
|
<xsl:when test="contains($s,'
')">
|
||||||
|
<xsl:call-template name="encode-string">
|
||||||
|
<xsl:with-param name="s" select="concat(substring-before($s,'
'),'\n',substring-after($s,'
'))"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
<!-- carriage return -->
|
||||||
|
<xsl:when test="contains($s,'
')">
|
||||||
|
<xsl:call-template name="encode-string">
|
||||||
|
<xsl:with-param name="s" select="concat(substring-before($s,'
'),'\r',substring-after($s,'
'))"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise><xsl:value-of select="$s"/></xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- number (no support for javascript mantissa) -->
|
||||||
|
<xsl:template match="text()[not(
|
||||||
|
(starts-with(., '0' ) and . != '0' and not(starts-with(., '0.' ))) or
|
||||||
|
(starts-with(.,'-0' ) and . != '-0' and not(starts-with(.,'-0.' ))) or
|
||||||
|
string(number(translate(., '{{nls_numeric_characters}}', '.,')))='NaN'
|
||||||
|
)]">
|
||||||
|
|
||||||
|
<xsl:variable name="num_string" select="translate(., '{{nls_numeric_characters}}', '.,')"/>
|
||||||
|
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="starts-with($num_string, '.')">
|
||||||
|
<xsl:value-of select="concat('0', $num_string)"/>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:value-of select="$num_string"/>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- boolean, case-insensitive -->
|
||||||
|
<xsl:template match="text()[translate(.,'TRUE','true')='true']">true</xsl:template>
|
||||||
|
<xsl:template match="text()[translate(.,'FALSE','false')='false']">false</xsl:template>
|
||||||
|
|
||||||
|
<!-- object -->
|
||||||
|
<xsl:template match="*" name="base">
|
||||||
|
<xsl:if test="not(preceding-sibling::*)">{</xsl:if>
|
||||||
|
<xsl:call-template name="escape-string">
|
||||||
|
<xsl:with-param name="s" select="name()"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
<xsl:text>:</xsl:text>
|
||||||
|
<!-- check type of node -->
|
||||||
|
<xsl:choose>
|
||||||
|
<!-- null nodes -->
|
||||||
|
<xsl:when test="count(child::node())=0">null</xsl:when>
|
||||||
|
<!-- other nodes -->
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:apply-templates select="child::node()"/>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
<!-- end of type check -->
|
||||||
|
<xsl:if test="following-sibling::*">,</xsl:if>
|
||||||
|
<xsl:if test="not(following-sibling::*)">}</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- array -->
|
||||||
|
<xsl:template match="*[count(../*[name(../*)=name(.)])=count(../*) and count(../*)>1]">
|
||||||
|
<xsl:if test="not(preceding-sibling::*)">[</xsl:if>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="not(child::node())">
|
||||||
|
<xsl:text>null</xsl:text>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:apply-templates select="child::node()"/>
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
<xsl:if test="following-sibling::*">,</xsl:if>
|
||||||
|
<xsl:if test="not(following-sibling::*)">]</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!-- convert root element to an anonymous container -->
|
||||||
|
<xsl:template match="/">
|
||||||
|
<xsl:apply-templates select="node()"/>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>^';
|
||||||
|
|
||||||
|
select value
|
||||||
|
into nls_numeric_characters
|
||||||
|
from nls_session_parameters
|
||||||
|
where parameter = 'NLS_NUMERIC_CHARACTERS';
|
||||||
|
|
||||||
|
return replace(stylesheet, '{{nls_numeric_characters}}', nls_numeric_characters);
|
||||||
|
|
||||||
|
end get_xml_to_json_stylesheet;
|
||||||
|
|
||||||
|
|
||||||
|
function ref_cursor_to_json (p_ref_cursor in sys_refcursor,
|
||||||
|
p_max_rows in number := null,
|
||||||
|
p_skip_rows in number := null) return pljson_list
|
||||||
|
as
|
||||||
|
l_ctx dbms_xmlgen.ctxhandle;
|
||||||
|
l_num_rows pls_integer;
|
||||||
|
l_xml xmltype;
|
||||||
|
l_xsl xmltype := xmltype(get_xml_to_json_stylesheet);
|
||||||
|
l_returnvalue clob;
|
||||||
|
begin
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Purpose: generate JSON from REF Cursor
|
||||||
|
|
||||||
|
Remarks:
|
||||||
|
|
||||||
|
Who Date Description
|
||||||
|
------ ---------- -------------------------------------
|
||||||
|
MBR 30.01.2010 Created
|
||||||
|
JKR 01.05.2010 Edited to fit in PL/JSON
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
l_ctx := dbms_xmlgen.newcontext (p_ref_cursor);
|
||||||
|
|
||||||
|
dbms_xmlgen.setnullhandling (l_ctx, dbms_xmlgen.empty_tag);
|
||||||
|
|
||||||
|
-- for pagination
|
||||||
|
|
||||||
|
if p_max_rows is not null then
|
||||||
|
dbms_xmlgen.setmaxrows (l_ctx, p_max_rows);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if p_skip_rows is not null then
|
||||||
|
dbms_xmlgen.setskiprows (l_ctx, p_skip_rows);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- get the XML content
|
||||||
|
l_xml := dbms_xmlgen.getxmltype (l_ctx, dbms_xmlgen.none);
|
||||||
|
|
||||||
|
l_num_rows := dbms_xmlgen.getnumrowsprocessed (l_ctx);
|
||||||
|
|
||||||
|
dbms_xmlgen.closecontext (l_ctx);
|
||||||
|
|
||||||
|
close p_ref_cursor;
|
||||||
|
|
||||||
|
if(l_num_rows = 0) then
|
||||||
|
return pljson_list();
|
||||||
|
end if;
|
||||||
|
|
||||||
|
--dbms_output.put_line(l_xml.getstringval);
|
||||||
|
-- perform the XSL transformation
|
||||||
|
SELECT l_xml.transform(l_xsl).getclobval()
|
||||||
|
INTO l_returnvalue
|
||||||
|
FROM DUAL;
|
||||||
|
|
||||||
|
--dbms_output.put_line(l_returnvalue);
|
||||||
|
|
||||||
|
if(l_num_rows > 1) then
|
||||||
|
return pljson_list(pljson(l_returnvalue).get('ROWSET'));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
declare ret pljson_list := pljson_list();
|
||||||
|
begin
|
||||||
|
ret.append(
|
||||||
|
pljson(
|
||||||
|
pljson(l_returnvalue).get('ROWSET')
|
||||||
|
).get('ROW')
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
end;
|
||||||
|
|
||||||
|
exception
|
||||||
|
when scanner_exception then
|
||||||
|
dbms_output.put('Scanner problem with the following input: ');
|
||||||
|
dbms_output.put_line(l_returnvalue);
|
||||||
|
raise;
|
||||||
|
when parser_exception then
|
||||||
|
dbms_output.put('Parser problem with the following input: ');
|
||||||
|
dbms_output.put_line(l_returnvalue);
|
||||||
|
raise;
|
||||||
|
when others then raise;
|
||||||
|
end ref_cursor_to_json;
|
||||||
|
|
||||||
|
function sql_to_json (p_sql in varchar2,
|
||||||
|
p_max_rows in number := null,
|
||||||
|
p_skip_rows in number := null) return pljson_list
|
||||||
|
as
|
||||||
|
v_cur sys_refcursor;
|
||||||
|
begin
|
||||||
|
open v_cur for p_sql;
|
||||||
|
return ref_cursor_to_json(v_cur, p_max_rows, p_skip_rows);
|
||||||
|
|
||||||
|
end sql_to_json;
|
||||||
|
|
||||||
|
end pljson_util_pkg;```
|
||||||
162
docs/packages/PLJSON_XML.md
Normal file
162
docs/packages/PLJSON_XML.md
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
# PLJSON_XML
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package pljson_xml as
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010 Jonas Krogsboell
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
declare
|
||||||
|
obj json := json('{a:1, b:[2, 3, 4], c:true}');
|
||||||
|
x xmltype;
|
||||||
|
begin
|
||||||
|
obj.print;
|
||||||
|
x := json_xml.json_to_xml(obj);
|
||||||
|
dbms_output.put_line(x.getclobval());
|
||||||
|
end;
|
||||||
|
*/
|
||||||
|
|
||||||
|
function json_to_xml(obj pljson, tagname varchar2 default 'root') return xmltype;
|
||||||
|
|
||||||
|
end pljson_xml;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package body pljson_xml as
|
||||||
|
|
||||||
|
function escapeStr(str varchar2) return varchar2 as
|
||||||
|
buf varchar2(32767) := '';
|
||||||
|
ch varchar2(4);
|
||||||
|
begin
|
||||||
|
for i in 1 .. length(str) loop
|
||||||
|
ch := substr(str, i, 1);
|
||||||
|
case ch
|
||||||
|
when '&' then buf := buf || '&';
|
||||||
|
when '<' then buf := buf || '<';
|
||||||
|
when '>' then buf := buf || '>';
|
||||||
|
when '"' then buf := buf || '"';
|
||||||
|
else buf := buf || ch;
|
||||||
|
end case;
|
||||||
|
end loop;
|
||||||
|
return buf;
|
||||||
|
end escapeStr;
|
||||||
|
|
||||||
|
/* Clob methods from printer */
|
||||||
|
procedure add_to_clob(buf_lob in out nocopy clob, buf_str in out nocopy varchar2, str varchar2) as
|
||||||
|
begin
|
||||||
|
-- if (length(str) > 5000 - length(buf_str)) then
|
||||||
|
if (lengthb(str) > 32767 - lengthb(buf_str)) then
|
||||||
|
dbms_lob.append(buf_lob, buf_str);
|
||||||
|
buf_str := str;
|
||||||
|
else
|
||||||
|
buf_str := buf_str || str;
|
||||||
|
end if;
|
||||||
|
end add_to_clob;
|
||||||
|
|
||||||
|
procedure flush_clob(buf_lob in out nocopy clob, buf_str in out nocopy varchar2) as
|
||||||
|
begin
|
||||||
|
dbms_lob.append(buf_lob, buf_str);
|
||||||
|
end flush_clob;
|
||||||
|
|
||||||
|
procedure toString(obj pljson_element, tagname in varchar2, xmlstr in out nocopy clob, xmlbuf in out nocopy varchar2) as
|
||||||
|
v_obj pljson;
|
||||||
|
v_list pljson_list;
|
||||||
|
|
||||||
|
v_keys pljson_list;
|
||||||
|
v_value pljson_element;
|
||||||
|
key_str varchar2(4000);
|
||||||
|
begin
|
||||||
|
if (obj.is_object()) then
|
||||||
|
add_to_clob(xmlstr, xmlbuf, '<' || tagname || '>');
|
||||||
|
v_obj := pljson(obj);
|
||||||
|
|
||||||
|
v_keys := v_obj.get_keys();
|
||||||
|
for i in 1 .. v_keys.count loop
|
||||||
|
v_value := v_obj.get(i);
|
||||||
|
key_str := v_keys.get(i).get_string();
|
||||||
|
|
||||||
|
if (key_str = 'content') then
|
||||||
|
if (v_value.is_array()) then
|
||||||
|
declare
|
||||||
|
v_l pljson_list := pljson_list(v_value);
|
||||||
|
begin
|
||||||
|
for j in 1 .. v_l.count loop
|
||||||
|
if (j > 1) then add_to_clob(xmlstr, xmlbuf, chr(13)||chr(10)); end if;
|
||||||
|
add_to_clob(xmlstr, xmlbuf, escapeStr(v_l.get(j).to_char()));
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
add_to_clob(xmlstr, xmlbuf, escapeStr(v_value.to_char()));
|
||||||
|
end if;
|
||||||
|
elsif (v_value.is_array()) then
|
||||||
|
declare
|
||||||
|
v_l pljson_list := pljson_list(v_value);
|
||||||
|
begin
|
||||||
|
for j in 1 .. v_l.count loop
|
||||||
|
v_value := v_l.get(j);
|
||||||
|
if (v_value.is_array()) then
|
||||||
|
add_to_clob(xmlstr, xmlbuf, '<' || key_str || '>');
|
||||||
|
add_to_clob(xmlstr, xmlbuf, escapeStr(v_value.to_char()));
|
||||||
|
add_to_clob(xmlstr, xmlbuf, '</' || key_str || '>');
|
||||||
|
else
|
||||||
|
toString(v_value, key_str, xmlstr, xmlbuf);
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
elsif (v_value.is_null() or (v_value.is_string() and v_value.get_string() = '')) then
|
||||||
|
add_to_clob(xmlstr, xmlbuf, '<' || key_str || '/>');
|
||||||
|
else
|
||||||
|
toString(v_value, key_str, xmlstr, xmlbuf);
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
add_to_clob(xmlstr, xmlbuf, '</' || tagname || '>');
|
||||||
|
elsif (obj.is_array()) then
|
||||||
|
v_list := pljson_list(obj);
|
||||||
|
for i in 1 .. v_list.count loop
|
||||||
|
v_value := v_list.get(i);
|
||||||
|
toString(v_value, nvl(tagname, 'array'), xmlstr, xmlbuf);
|
||||||
|
end loop;
|
||||||
|
else
|
||||||
|
add_to_clob(xmlstr, xmlbuf, '<' || tagname || '>'||case when obj.value_of() is not null then escapeStr(obj.value_of()) end ||'</' || tagname || '>');
|
||||||
|
end if;
|
||||||
|
end toString;
|
||||||
|
|
||||||
|
function json_to_xml(obj pljson, tagname varchar2 default 'root') return xmltype as
|
||||||
|
xmlstr clob := empty_clob();
|
||||||
|
xmlbuf varchar2(32767) := '';
|
||||||
|
returnValue xmltype;
|
||||||
|
begin
|
||||||
|
dbms_lob.createtemporary(xmlstr, true);
|
||||||
|
|
||||||
|
toString(obj, tagname, xmlstr, xmlbuf);
|
||||||
|
|
||||||
|
flush_clob(xmlstr, xmlbuf);
|
||||||
|
returnValue := xmltype('<?xml version="1.0"?>'||xmlstr);
|
||||||
|
dbms_lob.freetemporary(xmlstr);
|
||||||
|
return returnValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end pljson_xml;```
|
||||||
102
docs/packages/README.md
Normal file
102
docs/packages/README.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Packages Database
|
||||||
|
|
||||||
|
Questa cartella contiene la documentazione di tutti i 17 packages del database.
|
||||||
|
|
||||||
|
## Packages Business
|
||||||
|
|
||||||
|
| Package | Descrizione |
|
||||||
|
|---------|-------------|
|
||||||
|
| [MAIL_PKG](MAIL_PKG.md) | Gestione invio email automatiche (solleciti, reminder) |
|
||||||
|
|
||||||
|
## Packages Utility
|
||||||
|
|
||||||
|
| Package | Descrizione |
|
||||||
|
|---------|-------------|
|
||||||
|
| [UTL_BASE64](UTL_BASE64.md) | Encoding/decoding Base64 |
|
||||||
|
|
||||||
|
## Packages JasperReports (XLIB)
|
||||||
|
|
||||||
|
| Package | Descrizione |
|
||||||
|
|---------|-------------|
|
||||||
|
| [XLIB_JASPERREPORTS](XLIB_JASPERREPORTS.md) | Integrazione con JasperReports server |
|
||||||
|
| [XLIB_JASPERREPORTS_IMG](XLIB_JASPERREPORTS_IMG.md) | Gestione immagini nei report |
|
||||||
|
| [XLIB_HTTP](XLIB_HTTP.md) | Chiamate HTTP/REST |
|
||||||
|
| [XLIB_COMPONENT](XLIB_COMPONENT.md) | Gestione componenti |
|
||||||
|
| [XLIB_LOG](XLIB_LOG.md) | Sistema di logging |
|
||||||
|
|
||||||
|
## Packages JSON (PLJSON Library)
|
||||||
|
|
||||||
|
Libreria esterna per parsing e generazione JSON. In .NET può essere sostituita con `System.Text.Json` o `Newtonsoft.Json`.
|
||||||
|
|
||||||
|
| Package | Descrizione |
|
||||||
|
|---------|-------------|
|
||||||
|
| [PLJSON_DYN](PLJSON_DYN.md) | Query dinamiche JSON |
|
||||||
|
| [PLJSON_EXT](PLJSON_EXT.md) | Estensioni JSON |
|
||||||
|
| [PLJSON_HELPER](PLJSON_HELPER.md) | Helper functions |
|
||||||
|
| [PLJSON_ML](PLJSON_ML.md) | Multi-line JSON |
|
||||||
|
| [PLJSON_OBJECT_CACHE](PLJSON_OBJECT_CACHE.md) | Cache oggetti JSON |
|
||||||
|
| [PLJSON_PARSER](PLJSON_PARSER.md) | Parser JSON |
|
||||||
|
| [PLJSON_PRINTER](PLJSON_PRINTER.md) | Output JSON formattato |
|
||||||
|
| [PLJSON_UT](PLJSON_UT.md) | Unit test JSON |
|
||||||
|
| [PLJSON_UTIL_PKG](PLJSON_UTIL_PKG.md) | Utility JSON |
|
||||||
|
| [PLJSON_XML](PLJSON_XML.md) | Conversione JSON ↔ XML |
|
||||||
|
|
||||||
|
## Dettaglio Package MAIL_PKG
|
||||||
|
|
||||||
|
### Procedures Disponibili
|
||||||
|
|
||||||
|
| Procedura | Descrizione |
|
||||||
|
|-----------|-------------|
|
||||||
|
| `send_custom_mail` | Invio email generica |
|
||||||
|
| `send_richiesta_riscontro_preventivo` | Sollecito per preventivi in stato 100/200 |
|
||||||
|
| `send_richiesta_riscontro_preventivo_job` | Job: 10 giorni dopo DATA_DOC |
|
||||||
|
| `send_richiesta_riscontro_post_degustazione` | Sollecito post-degustazione |
|
||||||
|
| `send_richiesta_riscontro_post_degustazione_job` | Job: 15 giorni dopo prima degustazione |
|
||||||
|
| `send_reminder_seconda_caparra` | Reminder pagamento seconda caparra |
|
||||||
|
| `send_reminder_seconda_caparra_job` | Job: ogni 5 giorni da 65gg prima evento |
|
||||||
|
|
||||||
|
### Configurazione Email
|
||||||
|
|
||||||
|
- **From**: `noreply@apollinarecatering.it`
|
||||||
|
- **BCC**: `monia@apollinarecatering.it, matrimonio@apollinarecatering.it`
|
||||||
|
- Usa `APEX_MAIL` per invio
|
||||||
|
- Richiede `CMN_MAIL_HTMLUTILS` per costruzione body HTML
|
||||||
|
|
||||||
|
### Migrazione .NET
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// Esempio implementazione con SendGrid o SMTP
|
||||||
|
public interface IMailService
|
||||||
|
{
|
||||||
|
Task SendCustomMailAsync(string recipients, string subject, string body);
|
||||||
|
Task SendRichiestaRiscontroPreventivo(int eventoId);
|
||||||
|
Task SendReminderSecondaCaparra(int eventoId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jobs con Hangfire
|
||||||
|
[RecurringJob("0 9 * * *")]
|
||||||
|
public async Task SendReminderSecondaCaparraJob()
|
||||||
|
{
|
||||||
|
var eventi = await GetEventiDaPagareEntro65gg();
|
||||||
|
foreach (var evento in eventi.Where(e => ShouldSendReminder(e)))
|
||||||
|
{
|
||||||
|
await _mailService.SendReminderSecondaCaparra(evento.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Note per Migrazione
|
||||||
|
|
||||||
|
1. **MAIL_PKG**: Sostituire con servizio email .NET (SendGrid, SMTP, Azure Communication Services)
|
||||||
|
|
||||||
|
2. **PLJSON_***: Non necessari in .NET, usare `System.Text.Json`
|
||||||
|
|
||||||
|
3. **XLIB_JASPERREPORTS**: Valutare alternative:
|
||||||
|
- SSRS (SQL Server Reporting Services)
|
||||||
|
- DevExpress Reports
|
||||||
|
- Telerik Reporting
|
||||||
|
- QuestPDF / iTextSharp per PDF
|
||||||
|
|
||||||
|
4. **XLIB_HTTP**: Sostituire con `HttpClient`
|
||||||
|
|
||||||
|
5. **UTL_BASE64**: Usare `Convert.ToBase64String` / `Convert.FromBase64String`
|
||||||
168
docs/packages/UTL_BASE64.md
Normal file
168
docs/packages/UTL_BASE64.md
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
# UTL_BASE64
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE "UTL_BASE64" is
|
||||||
|
function decode_base64(p_clob_in in clob) return blob;
|
||||||
|
|
||||||
|
function encode_base64(p_blob_in in blob) return clob;
|
||||||
|
|
||||||
|
FUNCTION encodeBlob2Base64(pBlobIn IN BLOB) RETURN BLOB;
|
||||||
|
|
||||||
|
FUNCTION decodeBase642Blob(pBlobIn IN BLOB) RETURN BLOB;
|
||||||
|
|
||||||
|
function base64encode(p_blob in blob) return clob;
|
||||||
|
end;
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE BODY "UTL_BASE64" is
|
||||||
|
function decode_base64(p_clob_in in clob) return blob is
|
||||||
|
v_blob blob;
|
||||||
|
v_result blob;
|
||||||
|
v_offset integer;
|
||||||
|
v_buffer_size binary_integer := 48;
|
||||||
|
v_buffer_varchar varchar2(48);
|
||||||
|
v_buffer_raw raw(48);
|
||||||
|
begin
|
||||||
|
if p_clob_in is null then
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
dbms_lob.createtemporary(v_blob, true);
|
||||||
|
v_offset := 1;
|
||||||
|
for i in 1 .. ceil(dbms_lob.getlength(p_clob_in) / v_buffer_size) loop
|
||||||
|
dbms_lob.read(p_clob_in, v_buffer_size, v_offset, v_buffer_varchar);
|
||||||
|
v_buffer_raw := utl_raw.cast_to_raw(v_buffer_varchar);
|
||||||
|
v_buffer_raw := utl_encode.base64_decode(v_buffer_raw);
|
||||||
|
dbms_lob.writeappend(v_blob, utl_raw.length(v_buffer_raw), v_buffer_raw);
|
||||||
|
v_offset := v_offset + v_buffer_size;
|
||||||
|
end loop;
|
||||||
|
v_result := v_blob;
|
||||||
|
dbms_lob.freetemporary(v_blob);
|
||||||
|
return v_result;
|
||||||
|
end decode_base64;
|
||||||
|
|
||||||
|
function encode_base64(p_blob_in in blob) return clob is
|
||||||
|
v_clob clob;
|
||||||
|
v_result clob;
|
||||||
|
v_offset integer;
|
||||||
|
v_chunk_size binary_integer := (48 / 4) * 3;
|
||||||
|
v_buffer_varchar varchar2(48);
|
||||||
|
v_buffer_raw raw(48);
|
||||||
|
begin
|
||||||
|
if p_blob_in is null then
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
dbms_lob.createtemporary(v_clob, true);
|
||||||
|
v_offset := 1;
|
||||||
|
for i in 1 .. ceil(dbms_lob.getlength(p_blob_in) / v_chunk_size) loop
|
||||||
|
dbms_lob.read(p_blob_in, v_chunk_size, v_offset, v_buffer_raw);
|
||||||
|
v_buffer_raw := utl_encode.base64_encode(v_buffer_raw);
|
||||||
|
v_buffer_varchar := utl_raw.cast_to_varchar2(v_buffer_raw);
|
||||||
|
dbms_lob.writeappend(v_clob, length(v_buffer_varchar), v_buffer_varchar);
|
||||||
|
v_offset := v_offset + v_chunk_size;
|
||||||
|
end loop;
|
||||||
|
v_result := v_clob;
|
||||||
|
dbms_lob.freetemporary(v_clob);
|
||||||
|
return v_result;
|
||||||
|
end encode_base64;
|
||||||
|
|
||||||
|
FUNCTION encodeBlob2Base64(pBlobIn IN BLOB) RETURN BLOB IS
|
||||||
|
vAmount NUMBER := 45;
|
||||||
|
vBlobEnc BLOB := empty_blob();
|
||||||
|
vBlobEncLen NUMBER := 0;
|
||||||
|
vBlobInLen NUMBER := 0;
|
||||||
|
vBuffer RAW(45);
|
||||||
|
vOffset NUMBER := 1;
|
||||||
|
BEGIN
|
||||||
|
-- dbms_output.put_line('Start base64 encoding.');
|
||||||
|
vBlobInLen := dbms_lob.getlength(pBlobIn);
|
||||||
|
-- dbms_output.put_line('<BlobInLength>' || vBlobInLen);
|
||||||
|
dbms_lob.createtemporary(vBlobEnc, TRUE);
|
||||||
|
LOOP
|
||||||
|
IF vOffset >= vBlobInLen THEN
|
||||||
|
EXIT;
|
||||||
|
END IF;
|
||||||
|
dbms_lob.read(pBlobIn, vAmount, vOffset, vBuffer);
|
||||||
|
BEGIN
|
||||||
|
dbms_lob.append(vBlobEnc, utl_encode.base64_encode(vBuffer));
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
dbms_output.put_line('<vAmount>' || vAmount || '<vOffset>' || vOffset || '<vBuffer>' || vBuffer);
|
||||||
|
dbms_output.put_line('ERROR IN append: ' || SQLERRM);
|
||||||
|
RAISE;
|
||||||
|
END;
|
||||||
|
vOffset := vOffset + vAmount;
|
||||||
|
END LOOP;
|
||||||
|
vBlobEncLen := dbms_lob.getlength(vBlobEnc);
|
||||||
|
-- dbms_output.put_line('<BlobEncLength>' || vBlobEncLen);
|
||||||
|
-- dbms_output.put_line('Finshed base64 encoding.');
|
||||||
|
RETURN vBlobEnc;
|
||||||
|
END encodeBlob2Base64;
|
||||||
|
|
||||||
|
FUNCTION decodeBase642Blob(pBlobIn IN BLOB) RETURN BLOB IS
|
||||||
|
vAmount NUMBER := 256;--32;
|
||||||
|
vBlobDec BLOB := empty_blob();
|
||||||
|
vBlobDecLen NUMBER := 0;
|
||||||
|
vBlobInLen NUMBER := 0;
|
||||||
|
vBuffer RAW(256);--32);
|
||||||
|
vOffset NUMBER := 1;
|
||||||
|
BEGIN
|
||||||
|
-- dbms_output.put_line('Start base64 decoding.');
|
||||||
|
vBlobInLen := dbms_lob.getlength(pBlobIn);
|
||||||
|
-- dbms_output.put_line('<BlobInLength>' || vBlobInLen);
|
||||||
|
dbms_lob.createtemporary(vBlobDec, TRUE);
|
||||||
|
LOOP
|
||||||
|
IF vOffset >= vBlobInLen THEN
|
||||||
|
EXIT;
|
||||||
|
END IF;
|
||||||
|
dbms_lob.read(pBlobIn, vAmount, vOffset, vBuffer);
|
||||||
|
BEGIN
|
||||||
|
dbms_lob.append(vBlobDec, utl_encode.base64_decode(vBuffer));
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
dbms_output.put_line('<vAmount>' || vAmount || '<vOffset>' || vOffset || '<vBuffer>' || vBuffer);
|
||||||
|
dbms_output.put_line('ERROR IN append: ' || SQLERRM);
|
||||||
|
RAISE;
|
||||||
|
END;
|
||||||
|
vOffset := vOffset + vAmount;
|
||||||
|
END LOOP;
|
||||||
|
vBlobDecLen := dbms_lob.getlength(vBlobDec);
|
||||||
|
-- dbms_output.put_line('<BlobDecLength>' || vBlobDecLen);
|
||||||
|
-- dbms_output.put_line('Finshed base64 decoding.');
|
||||||
|
RETURN vBlobDec;
|
||||||
|
END decodeBase642Blob;
|
||||||
|
|
||||||
|
function base64encode(p_blob in blob)
|
||||||
|
return clob
|
||||||
|
is
|
||||||
|
CRLF constant varchar2(2) := chr(13)||chr(10);
|
||||||
|
l_clob clob;
|
||||||
|
l_amount integer := 23826;
|
||||||
|
l_offset integer := 1;
|
||||||
|
l_raw raw(32767);
|
||||||
|
l_buf varchar2(32767);
|
||||||
|
l_len integer := dbms_lob.getlength(p_blob);
|
||||||
|
begin
|
||||||
|
|
||||||
|
dbms_lob.createtemporary(l_clob, true, dbms_lob.call);
|
||||||
|
|
||||||
|
while l_offset <= l_len loop
|
||||||
|
dbms_lob.read(p_blob, l_amount, l_offset, l_raw);
|
||||||
|
l_offset := l_offset + l_amount;
|
||||||
|
l_buf := utl_raw.cast_to_varchar2(utl_encode.base64_encode(l_raw));
|
||||||
|
l_buf := replace(l_buf, CRLF);
|
||||||
|
dbms_lob.writeappend(l_clob, length(l_buf), l_buf);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return l_clob;
|
||||||
|
|
||||||
|
end base64encode;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
```
|
||||||
265
docs/packages/XLIB_COMPONENT.md
Normal file
265
docs/packages/XLIB_COMPONENT.md
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
# XLIB_COMPONENT
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE "XLIB_COMPONENT"
|
||||||
|
AS
|
||||||
|
/*=========================================================================
|
||||||
|
$Id: xlib_component.pks 57 2013-05-13 07:09:51Z dietmar.aust $
|
||||||
|
|
||||||
|
Purpose :
|
||||||
|
|
||||||
|
License : Copyright (c) 2010 Dietmar Aust (opal-consulting.de)
|
||||||
|
Licensed under a BSD style license (license.txt)
|
||||||
|
http://www.opal-consulting.de/pls/apex/f?p=20090928:14
|
||||||
|
|
||||||
|
$LastChangedDate: 2013-05-13 09:09:51 +0200 (Mon, 13 May 2013) $
|
||||||
|
$LastChangedBy: dietmar.aust $
|
||||||
|
|
||||||
|
Date Author Comment
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
06.01.2010 D. Aust Initial creation
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
|
||||||
|
-- how many digits does the version key have?
|
||||||
|
-- 3 => e.g. 1.0.0
|
||||||
|
-- 4 => e.g. 1.0.0.0
|
||||||
|
c_num_version_components CONSTANT NUMBER := 6;
|
||||||
|
|
||||||
|
PROCEDURE create_component (
|
||||||
|
p_name xlib_components.comp_name%TYPE,
|
||||||
|
p_version xlib_components.comp_version%TYPE,
|
||||||
|
p_version_label xlib_components.comp_version_label%TYPE DEFAULT NULL,
|
||||||
|
p_depends_on xlib_components.comp_depends_on%TYPE DEFAULT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
PROCEDURE set_component (
|
||||||
|
p_name xlib_components.comp_name%TYPE,
|
||||||
|
p_version xlib_components.comp_version%TYPE,
|
||||||
|
p_version_label xlib_components.comp_version_label%TYPE DEFAULT NULL,
|
||||||
|
p_depends_on xlib_components.comp_depends_on%TYPE DEFAULT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
PROCEDURE delete_component (p_name IN xlib_components.comp_name%TYPE);
|
||||||
|
|
||||||
|
/*****
|
||||||
|
utility functions
|
||||||
|
****/
|
||||||
|
FUNCTION get_version (p_name IN xlib_components.comp_name%TYPE)
|
||||||
|
RETURN xlib_components.comp_version%TYPE;
|
||||||
|
|
||||||
|
FUNCTION make_version_string (p_version IN VARCHAR2)
|
||||||
|
RETURN VARCHAR2;
|
||||||
|
|
||||||
|
PROCEDURE verify_required_component (
|
||||||
|
p_comp_name IN VARCHAR2,
|
||||||
|
p_comp_version_min IN VARCHAR2
|
||||||
|
);
|
||||||
|
END xlib_component;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE BODY "XLIB_COMPONENT"
|
||||||
|
AS
|
||||||
|
/*=========================================================================
|
||||||
|
FILE : $Id: xlib_component.pkb 57 2013-05-13 07:09:51Z dietmar.aust $
|
||||||
|
=========================================================================*/
|
||||||
|
TYPE vc2_arr_t IS TABLE OF VARCHAR2 (32767 CHAR)
|
||||||
|
INDEX BY BINARY_INTEGER;
|
||||||
|
|
||||||
|
PROCEDURE create_component (
|
||||||
|
p_name xlib_components.comp_name%TYPE,
|
||||||
|
p_version xlib_components.comp_version%TYPE,
|
||||||
|
p_version_label xlib_components.comp_version_label%TYPE DEFAULT NULL,
|
||||||
|
p_depends_on xlib_components.comp_depends_on%TYPE DEFAULT NULL
|
||||||
|
|
||||||
|
)
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO xlib_components
|
||||||
|
(comp_id, comp_name, comp_version, comp_version_label, comp_depends_on
|
||||||
|
)
|
||||||
|
VALUES (xlib_seq.NEXTVAL, p_name, p_version, p_version_label, p_depends_on
|
||||||
|
);
|
||||||
|
END;
|
||||||
|
|
||||||
|
PROCEDURE set_component (
|
||||||
|
p_name xlib_components.comp_name%TYPE,
|
||||||
|
p_version xlib_components.comp_version%TYPE,
|
||||||
|
p_version_label xlib_components.comp_version_label%TYPE DEFAULT NULL,
|
||||||
|
p_depends_on xlib_components.comp_depends_on%TYPE DEFAULT NULL
|
||||||
|
)
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO xlib_components
|
||||||
|
(comp_id, comp_name, comp_version, comp_version_label, comp_depends_on
|
||||||
|
)
|
||||||
|
VALUES (xlib_seq.NEXTVAL, p_name, p_version, p_version_label, p_depends_on
|
||||||
|
);
|
||||||
|
EXCEPTION
|
||||||
|
WHEN DUP_VAL_ON_INDEX
|
||||||
|
THEN
|
||||||
|
UPDATE xlib_components
|
||||||
|
SET comp_version = p_version,
|
||||||
|
comp_version_label = p_version_label,
|
||||||
|
comp_depends_on = p_depends_on
|
||||||
|
WHERE comp_name = p_name;
|
||||||
|
|
||||||
|
IF SQL%ROWCOUNT = 0
|
||||||
|
THEN
|
||||||
|
raise_application_error (-20006,
|
||||||
|
'component ' || p_name || ' not found'
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
|
||||||
|
PROCEDURE delete_component (p_name IN xlib_components.comp_name%TYPE)
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
-- delete component
|
||||||
|
DELETE FROM xlib_components
|
||||||
|
WHERE comp_name = p_name;
|
||||||
|
|
||||||
|
IF SQL%ROWCOUNT = 0
|
||||||
|
THEN
|
||||||
|
raise_application_error (-20001,
|
||||||
|
'Component ' || p_name || ' not found'
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
|
||||||
|
FUNCTION split_string (p_str IN VARCHAR2, p_sep IN VARCHAR2 DEFAULT ',')
|
||||||
|
RETURN vc2_arr_t
|
||||||
|
AS
|
||||||
|
l_string VARCHAR2 (32767) := p_str || p_sep;
|
||||||
|
l_sep_index PLS_INTEGER;
|
||||||
|
l_index PLS_INTEGER := 1;
|
||||||
|
l_tab vc2_arr_t;
|
||||||
|
BEGIN
|
||||||
|
-- assertions
|
||||||
|
IF LENGTH (p_sep) != 1
|
||||||
|
THEN
|
||||||
|
raise_application_error
|
||||||
|
(-20004,
|
||||||
|
'wrong separator format, must be only one character'
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
LOOP
|
||||||
|
l_sep_index := INSTR (l_string, p_sep, l_index);
|
||||||
|
EXIT WHEN l_sep_index = 0;
|
||||||
|
l_tab (l_tab.COUNT) :=
|
||||||
|
SUBSTR (l_string, l_index, l_sep_index - l_index);
|
||||||
|
l_index := l_sep_index + 1;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
RETURN l_tab;
|
||||||
|
END;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FUNCTION get_version (p_name IN xlib_components.comp_name%TYPE)
|
||||||
|
RETURN xlib_components.comp_version%TYPE
|
||||||
|
IS
|
||||||
|
l_version xlib_components.comp_version%TYPE;
|
||||||
|
BEGIN
|
||||||
|
SELECT comp_version
|
||||||
|
INTO l_version
|
||||||
|
FROM xlib_components
|
||||||
|
WHERE comp_name = p_name;
|
||||||
|
|
||||||
|
RETURN l_version;
|
||||||
|
END;
|
||||||
|
|
||||||
|
PROCEDURE assert_version_format (p_version IN VARCHAR2)
|
||||||
|
IS
|
||||||
|
l_tab vc2_arr_t;
|
||||||
|
l_num NUMBER;
|
||||||
|
BEGIN
|
||||||
|
-- '.' at the beginning or end of the version?
|
||||||
|
IF SUBSTR (p_version, 1, 1) = '.'
|
||||||
|
OR SUBSTR (p_version, LENGTH (p_version), 1) = '.'
|
||||||
|
OR INSTR (p_version, ' ') > 0
|
||||||
|
THEN
|
||||||
|
raise_application_error (-20002, 'wrong version format');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
l_tab := split_string (p_version, '.');
|
||||||
|
|
||||||
|
FOR i IN 0 .. l_tab.COUNT - 1
|
||||||
|
LOOP
|
||||||
|
l_num := TO_NUMBER (l_tab (i));
|
||||||
|
END LOOP;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS
|
||||||
|
THEN
|
||||||
|
IF SQLCODE = -6502 /* numeric or value error */
|
||||||
|
THEN
|
||||||
|
raise_application_error (-20005,
|
||||||
|
'wrong version format, no numbers.'
|
||||||
|
);
|
||||||
|
ELSE
|
||||||
|
RAISE;
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
|
||||||
|
FUNCTION make_version_string (p_version IN VARCHAR2)
|
||||||
|
RETURN VARCHAR2
|
||||||
|
IS
|
||||||
|
l_num_dots NUMBER;
|
||||||
|
l_tab vc2_arr_t;
|
||||||
|
l_str VARCHAR2 (32767 CHAR);
|
||||||
|
l_comp VARCHAR2 (50 CHAR);
|
||||||
|
BEGIN
|
||||||
|
-- assertions
|
||||||
|
assert_version_format (p_version => p_version);
|
||||||
|
l_tab := split_string (p_version, '.');
|
||||||
|
|
||||||
|
FOR i IN 1 .. c_num_version_components
|
||||||
|
LOOP
|
||||||
|
IF l_tab.EXISTS (i - 1)
|
||||||
|
THEN
|
||||||
|
l_comp :=
|
||||||
|
TO_CHAR (TO_NUMBER (NVL (l_tab (i - 1), '0')), 'FM0000');
|
||||||
|
ELSE
|
||||||
|
l_comp := '0000';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF l_str IS NULL
|
||||||
|
THEN
|
||||||
|
l_str := l_comp;
|
||||||
|
ELSE
|
||||||
|
l_str := l_str || '.' || l_comp;
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
RETURN l_str;
|
||||||
|
END;
|
||||||
|
|
||||||
|
PROCEDURE verify_required_component (
|
||||||
|
p_comp_name IN VARCHAR2,
|
||||||
|
p_comp_version_min IN VARCHAR2
|
||||||
|
)
|
||||||
|
IS
|
||||||
|
l_current_version VARCHAR2 (50);
|
||||||
|
BEGIN
|
||||||
|
l_current_version := xlib_component.get_version (p_name => p_comp_name);
|
||||||
|
|
||||||
|
IF make_version_string (l_current_version)
|
||||||
|
>= make_version_string (p_comp_version_min)
|
||||||
|
THEN
|
||||||
|
NULL; -- ok
|
||||||
|
ELSE
|
||||||
|
raise_application_error
|
||||||
|
(-20020,
|
||||||
|
'this upgrade requires '||p_comp_name||' in version '
|
||||||
|
|| p_comp_version_min
|
||||||
|
|| ' or higher, not version '
|
||||||
|
|| l_current_version
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
END xlib_component;```
|
||||||
477
docs/packages/XLIB_HTTP.md
Normal file
477
docs/packages/XLIB_HTTP.md
Normal file
@@ -0,0 +1,477 @@
|
|||||||
|
# XLIB_HTTP
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE "XLIB_HTTP"
|
||||||
|
AS
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Purpose : Make http callouts
|
||||||
|
|
||||||
|
License : Copyright (c) 2010 Dietmar Aust (opal-consulting.de)
|
||||||
|
Licensed under a BSD style license (license.txt)
|
||||||
|
http://www.opal-consulting.de/pls/apex/f?p=20090928:14
|
||||||
|
|
||||||
|
Version Date Author Comment
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
19.02.2007 D. Aust initial creation
|
||||||
|
07.08.2008 D. Aust - added check_get_request
|
||||||
|
- display_url_raw: pass all request headers
|
||||||
|
to the client
|
||||||
|
05.08.2012 D. Aust suppress mime header TRANSFER-ENCODING,
|
||||||
|
causes lots of problems with XMLDB listener
|
||||||
|
and others choking.
|
||||||
|
2.3.0.0 19.05.2014 D. Aust - #294 - Fix chunked encoding problem in
|
||||||
|
xlib_http.get_report
|
||||||
|
- added version information to this package
|
||||||
|
2.3.0.0 09.05.2015 D. Aust pass JSESSIONID from backend J2EE server to client
|
||||||
|
for image rendering in html reports
|
||||||
|
2.6.1 28.09.2020 D. Aust - #40 - APEX 20.1 security bundle (PSE 30990551) rejects response header "Cache-Control: private"
|
||||||
|
2.6.2 13.10.2020 D. Aust - added function check_acl()
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
|
||||||
|
c_success CONSTANT CHAR (1) := '1';
|
||||||
|
c_fail CONSTANT CHAR (1) := '0';
|
||||||
|
|
||||||
|
-- version of this package
|
||||||
|
version_c constant varchar2(20 char) := '2.6.2';
|
||||||
|
|
||||||
|
TYPE vc_arr_t IS TABLE OF VARCHAR2 (32767) INDEX BY BINARY_INTEGER;
|
||||||
|
g_empty_vc_arr vc_arr_t;
|
||||||
|
|
||||||
|
/* Function: MyFunction
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
*
|
||||||
|
* x - Description of x.
|
||||||
|
* y - Description of y.
|
||||||
|
* z - Description of z.
|
||||||
|
*/
|
||||||
|
PROCEDURE display_url_raw (
|
||||||
|
p_url VARCHAR2,
|
||||||
|
p_mime_type_override IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_charset IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_header_name_arr IN vc_arr_t default g_empty_vc_arr,
|
||||||
|
p_header_value_arr IN vc_arr_t default g_empty_vc_arr
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Procedure: retrieve_blob_from_url
|
||||||
|
|
||||||
|
Multiplies two integers.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
p_url - url to be called
|
||||||
|
|
||||||
|
o_blob - output: the resulting out blob
|
||||||
|
o_mime_type - output: the resulting out mime type from the call
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
The two integers multiplied together.
|
||||||
|
o_blob - the resulting out blob
|
||||||
|
|
||||||
|
See Also:
|
||||||
|
|
||||||
|
<escape_form_data>
|
||||||
|
*/
|
||||||
|
PROCEDURE retrieve_blob_from_url (
|
||||||
|
p_url VARCHAR2,
|
||||||
|
o_blob OUT BLOB,
|
||||||
|
o_mime_type OUT VARCHAR2
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: escape_form_data
|
||||||
|
Here is some describing text ...
|
||||||
|
|
||||||
|
--- SQL
|
||||||
|
declare
|
||||||
|
l_i number;
|
||||||
|
begin
|
||||||
|
null;
|
||||||
|
|
||||||
|
Select count(*)
|
||||||
|
into l_count
|
||||||
|
from dual;
|
||||||
|
end;
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
s - string to be escaped
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
the escaped data
|
||||||
|
*/
|
||||||
|
FUNCTION escape_form_data (s VARCHAR2)
|
||||||
|
RETURN VARCHAR2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: check_get_request
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
p_url the url to be called
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Returns c_fail or c_success
|
||||||
|
|
||||||
|
*/
|
||||||
|
FUNCTION check_get_request (p_url VARCHAR2)
|
||||||
|
RETURN CHAR;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: check_acl
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
p_url the url to be called
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Returns c_fail or c_success
|
||||||
|
*/
|
||||||
|
FUNCTION check_acl (p_url VARCHAR2)
|
||||||
|
RETURN CHAR;
|
||||||
|
END;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE BODY "XLIB_HTTP"
|
||||||
|
AS
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Purpose : Make http callouts
|
||||||
|
|
||||||
|
License : Copyright (c) 2010 Dietmar Aust (opal-consulting.de)
|
||||||
|
Licensed under a BSD style license (license.txt)
|
||||||
|
https://github.com/daust/JasperReportsIntegration
|
||||||
|
|
||||||
|
Version Date Author Comment
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
19.02.2007 D. Aust initial creation
|
||||||
|
07.08.2008 D. Aust - added check_get_request
|
||||||
|
- display_url_raw: pass all request headers
|
||||||
|
to the client
|
||||||
|
05.08.2012 D. Aust suppress mime header TRANSFER-ENCODING,
|
||||||
|
causes lots of problems with XMLDB listener
|
||||||
|
and others choking.
|
||||||
|
2.3.0.0 19.05.2014 D. Aust - #294 - Fix chunked encoding problem in
|
||||||
|
xlib_http.get_report
|
||||||
|
- added version information to this package
|
||||||
|
2.3.0.0 09.05.2015 D. Aust pass JSESSIONID from backend J2EE server to client
|
||||||
|
for image rendering in html reports
|
||||||
|
2.6.1 28.09.2020 D. Aust - #40 - APEX 20.1 security bundle (PSE 30990551) rejects response header "Cache-Control: private"
|
||||||
|
2.6.2 13.10.2020 D. Aust - added function check_acl()
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
|
||||||
|
m_module VARCHAR2 (50) := 'XLIB_HTTP';
|
||||||
|
|
||||||
|
PROCEDURE display_url_raw (
|
||||||
|
p_url VARCHAR2,
|
||||||
|
p_mime_type_override IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_charset IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_header_name_arr IN vc_arr_t default g_empty_vc_arr,
|
||||||
|
p_header_value_arr IN vc_arr_t default g_empty_vc_arr
|
||||||
|
)
|
||||||
|
IS
|
||||||
|
l_http_request UTL_HTTP.req;
|
||||||
|
l_http_response UTL_HTTP.resp;
|
||||||
|
l_blob BLOB;
|
||||||
|
l_raw RAW (32767);
|
||||||
|
l_buffer_size NUMBER := 32767;
|
||||||
|
--
|
||||||
|
l_proc VARCHAR2 (100) := m_module || '.DISPLAY_URL_RAW';
|
||||||
|
--
|
||||||
|
l_mime_type VARCHAR2 (100);
|
||||||
|
l_header_name VARCHAR2 (256);
|
||||||
|
l_header_value VARCHAR2 (1024);
|
||||||
|
l_jsession VARCHAR2 (256);
|
||||||
|
l_path VARCHAR2 (1024);
|
||||||
|
--
|
||||||
|
l_header_name_arr vc_arr_t;
|
||||||
|
l_header_value_arr vc_arr_t;
|
||||||
|
--
|
||||||
|
l_msg varchar2(32767);
|
||||||
|
BEGIN
|
||||||
|
xlog (l_proc, 'show url: ' || p_url);
|
||||||
|
--htp.flush();
|
||||||
|
--htp.init();
|
||||||
|
|
||||||
|
-- Initialize the BLOB.
|
||||||
|
DBMS_LOB.createtemporary (l_blob, FALSE);
|
||||||
|
|
||||||
|
l_http_request := UTL_HTTP.begin_request (url => p_url,
|
||||||
|
method => 'GET',
|
||||||
|
http_version => utl_http.http_version_1_0);
|
||||||
|
|
||||||
|
utl_http.set_header (l_http_request, 'Connection', 'Keep-Alive');
|
||||||
|
|
||||||
|
-- pass additional headers to the target service
|
||||||
|
for i in 1..p_header_name_arr.count loop
|
||||||
|
xlog(l_proc, 'pass additional headers to target service: '|| p_header_name_arr(i) ||': '||p_header_value_arr(i));
|
||||||
|
utl_http.set_header(l_http_request, p_header_name_arr(i), p_header_value_arr(i));
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
-- get response from target service
|
||||||
|
l_http_response := UTL_HTTP.get_response (l_http_request);
|
||||||
|
|
||||||
|
FOR i IN 1 .. UTL_HTTP.get_header_count (l_http_response)
|
||||||
|
LOOP
|
||||||
|
UTL_HTTP.get_header (l_http_response,
|
||||||
|
i,
|
||||||
|
l_header_name,
|
||||||
|
l_header_value
|
||||||
|
);
|
||||||
|
-- store header value in arr
|
||||||
|
l_header_name_arr (i) := l_header_name;
|
||||||
|
l_header_value_arr (i) := l_header_value;
|
||||||
|
|
||||||
|
IF LOWER (l_header_name) = 'content-type'
|
||||||
|
THEN
|
||||||
|
l_mime_type := l_header_value;
|
||||||
|
xlog(l_proc, 'content-type from server: ' || l_mime_type);
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
-- override mime type
|
||||||
|
IF p_mime_type_override IS NOT NULL
|
||||||
|
THEN
|
||||||
|
l_mime_type := p_mime_type_override;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Copy the response into the BLOB.
|
||||||
|
BEGIN
|
||||||
|
LOOP
|
||||||
|
UTL_HTTP.read_raw (l_http_response, l_raw, l_buffer_size);
|
||||||
|
DBMS_LOB.writeappend (l_blob, UTL_RAW.LENGTH (l_raw), l_raw);
|
||||||
|
END LOOP;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN UTL_HTTP.end_of_body
|
||||||
|
THEN
|
||||||
|
UTL_HTTP.end_response (l_http_response);
|
||||||
|
END;
|
||||||
|
|
||||||
|
xlog(l_proc, 'set content-type: ' || l_mime_type);
|
||||||
|
OWA_UTIL.mime_header (ccontent_type => l_mime_type,
|
||||||
|
bclose_header => FALSE,
|
||||||
|
ccharset => p_charset
|
||||||
|
);
|
||||||
|
|
||||||
|
FOR i IN 1 .. l_header_name_arr.COUNT
|
||||||
|
LOOP
|
||||||
|
IF UPPER (l_header_name_arr (i)) IN
|
||||||
|
('CONTENT-LENGTH', 'CONTENT-TYPE', 'MIME-TYPE', 'TRANSFER-ENCODING',
|
||||||
|
'STRICT-TRANSPORT-SECURITY', 'CACHE-CONTROL', 'PRAGMA', 'EXPIRES')
|
||||||
|
THEN
|
||||||
|
--xlog (l_proc, 'skip header ' || l_header_name_arr (i));
|
||||||
|
null;
|
||||||
|
ELSE
|
||||||
|
if upper(l_header_name_arr(i)) = 'SET-COOKIE' and l_header_value_arr (i) like 'JSESSIONID%' then
|
||||||
|
xlog(l_proc , 'JSESSION_ID found !!!:'||l_header_value_arr (i));
|
||||||
|
--extract path
|
||||||
|
l_jsession := regexp_substr(l_header_value_arr (i), 'JSESSIONID=(.*);[ ]*Path',1, 1,'i',1);
|
||||||
|
l_path := regexp_substr(l_header_value_arr (i), ';[ ]*Path=(.*)',1, 1,'i',1);
|
||||||
|
|
||||||
|
xlog(l_proc, 'xx:full:'||l_header_value_arr (i)|| '; xx:session:'||l_jsession || '; xx:path:'||l_path);
|
||||||
|
else
|
||||||
|
l_header_value := l_header_value_arr (i);
|
||||||
|
end if;
|
||||||
|
xlog (l_proc,
|
||||||
|
'set header:'
|
||||||
|
|| l_header_name_arr (i)
|
||||||
|
|| ': '
|
||||||
|
|| l_header_value
|
||||||
|
);
|
||||||
|
HTP.p (l_header_name_arr (i) || ': ' || l_header_value);
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
-- JSESSION Cookies ausgeben
|
||||||
|
-- if using tunnel, then the cookie is JRI_JSESSIONID
|
||||||
|
-- if not using tunnel, then cookie is JSESSIONID directly
|
||||||
|
--
|
||||||
|
if xlib_jasperreports.get_use_images_no_tunnel=false then
|
||||||
|
l_msg := 'Set-Cookie: ' || xlib_jasperreports.m_jri_cookie_name_c || '=' || l_jsession;
|
||||||
|
xlog (l_proc, 'set header:' || l_msg );
|
||||||
|
HTP.p (l_msg);
|
||||||
|
l_msg := 'Set-Cookie: ' || xlib_jasperreports.m_jri_path_cookie_name_c || '=' || l_path;
|
||||||
|
xlog (l_proc, 'set header:' || l_msg );
|
||||||
|
HTP.p (l_msg);
|
||||||
|
else
|
||||||
|
l_msg := 'Set-Cookie: JSESSIONID=' || l_jsession;
|
||||||
|
if xlib_jasperreports.get_cookie_path_no_tunnel is not null then
|
||||||
|
l_msg := l_msg || '; Path=' || xlib_jasperreports.get_cookie_path_no_tunnel;
|
||||||
|
end if;
|
||||||
|
xlog (l_proc, 'set header:' || l_msg );
|
||||||
|
HTP.p (l_msg);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- set content length
|
||||||
|
HTP.p ('Content-length: ' || DBMS_LOB.getlength (l_blob));
|
||||||
|
OWA_UTIL.http_header_close;
|
||||||
|
WPG_DOCLOAD.download_file (l_blob);
|
||||||
|
-- Relase the resources associated with the temporary LOB.
|
||||||
|
DBMS_LOB.freetemporary (l_blob);
|
||||||
|
EXCEPTION
|
||||||
|
WHEN UTL_HTTP.end_of_body
|
||||||
|
THEN
|
||||||
|
UTL_HTTP.end_response (l_http_response);
|
||||||
|
DBMS_LOB.freetemporary (l_blob);
|
||||||
|
RAISE;
|
||||||
|
WHEN OTHERS
|
||||||
|
THEN
|
||||||
|
xlog (l_proc, 'Error: ' || SQLERRM, 'ERROR');
|
||||||
|
RAISE;
|
||||||
|
END;
|
||||||
|
|
||||||
|
PROCEDURE retrieve_blob_from_url (
|
||||||
|
p_url VARCHAR2,
|
||||||
|
o_blob OUT BLOB,
|
||||||
|
o_mime_type OUT VARCHAR2
|
||||||
|
)
|
||||||
|
IS
|
||||||
|
l_http_request UTL_HTTP.req;
|
||||||
|
l_http_response UTL_HTTP.resp;
|
||||||
|
l_raw RAW (32767);
|
||||||
|
--
|
||||||
|
l_proc VARCHAR2 (100)
|
||||||
|
:= m_module || '.RETRIEVE_BLOB_FROM_URL';
|
||||||
|
--
|
||||||
|
l_header_name VARCHAR2 (256);
|
||||||
|
l_header_value VARCHAR2 (1024);
|
||||||
|
BEGIN
|
||||||
|
-- Initialize the BLOB.
|
||||||
|
dbms_lob.createtemporary (o_blob, false);
|
||||||
|
l_http_request := utl_http.begin_request (url => p_url,
|
||||||
|
method => 'GET',
|
||||||
|
http_version => utl_http.http_version_1_0);
|
||||||
|
|
||||||
|
l_http_response := UTL_HTTP.get_response (l_http_request);
|
||||||
|
|
||||||
|
FOR i IN 1 .. UTL_HTTP.get_header_count (l_http_response)
|
||||||
|
LOOP
|
||||||
|
UTL_HTTP.get_header (l_http_response,
|
||||||
|
i,
|
||||||
|
l_header_name,
|
||||||
|
l_header_value
|
||||||
|
);
|
||||||
|
|
||||||
|
IF LOWER (l_header_name) = 'content-type'
|
||||||
|
THEN
|
||||||
|
o_mime_type := l_header_value;
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
-- Copy the response into the BLOB.
|
||||||
|
BEGIN
|
||||||
|
LOOP
|
||||||
|
UTL_HTTP.read_raw (l_http_response, l_raw, 32767);
|
||||||
|
DBMS_LOB.writeappend (o_blob, UTL_RAW.LENGTH (l_raw), l_raw);
|
||||||
|
END LOOP;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN UTL_HTTP.end_of_body
|
||||||
|
THEN
|
||||||
|
UTL_HTTP.end_response (l_http_response);
|
||||||
|
END;
|
||||||
|
-- Relase the resources associated with the temporary LOB.
|
||||||
|
--DBMS_LOB.freetemporary (l_blob);
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS
|
||||||
|
THEN
|
||||||
|
UTL_HTTP.end_response (l_http_response);
|
||||||
|
DBMS_LOB.freetemporary (o_blob);
|
||||||
|
xlog (l_proc, 'Error: ' || SQLERRM, 'ERROR');
|
||||||
|
RAISE;
|
||||||
|
END;
|
||||||
|
|
||||||
|
FUNCTION escape_form_data (s VARCHAR2)
|
||||||
|
RETURN VARCHAR2
|
||||||
|
IS
|
||||||
|
l_s VARCHAR2 (500 CHAR);
|
||||||
|
|
||||||
|
FUNCTION r (s VARCHAR2, c VARCHAR2)
|
||||||
|
RETURN VARCHAR2
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
RETURN REPLACE (s, c, '%' || TRIM (TO_CHAR (ASCII (c), 'XX')));
|
||||||
|
END;
|
||||||
|
BEGIN
|
||||||
|
l_s := s;
|
||||||
|
l_s := REPLACE (l_s, ' ', '+');
|
||||||
|
l_s := r (l_s, chr(37)); -- %
|
||||||
|
l_s := r (l_s, chr(37)); -- /
|
||||||
|
l_s := r (l_s, chr(63)); -- ?
|
||||||
|
l_s := r (l_s, chr(38)); -- &
|
||||||
|
l_s := r (l_s, chr(228)); -- <20><><EFBFBD>
|
||||||
|
l_s := r (l_s, chr(196)); -- <20><>
|
||||||
|
l_s := r (l_s, chr(246)); -- <20><>
|
||||||
|
l_s := r (l_s, chr(214)); -- <20><>
|
||||||
|
l_s := r (l_s, chr(252)); -- <20><>
|
||||||
|
l_s := r (l_s, chr(220)); -- <20><><EFBFBD>
|
||||||
|
l_s := r (l_s, chr(223)); -- <20><><EFBFBD>
|
||||||
|
RETURN l_s;
|
||||||
|
END;
|
||||||
|
|
||||||
|
FUNCTION check_get_request (p_url VARCHAR2)
|
||||||
|
RETURN CHAR
|
||||||
|
IS
|
||||||
|
l_clob CLOB;
|
||||||
|
BEGIN
|
||||||
|
IF p_url IS NULL
|
||||||
|
THEN
|
||||||
|
RETURN c_fail;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT HTTPURITYPE (p_url).getclob ()
|
||||||
|
INTO l_clob
|
||||||
|
FROM DUAL;
|
||||||
|
|
||||||
|
/*SELECT c_success
|
||||||
|
INTO l_ret
|
||||||
|
FROM DUAL
|
||||||
|
WHERE EXISTS (SELECT HTTPURITYPE (p_url).getclob ()
|
||||||
|
FROM DUAL);
|
||||||
|
*/
|
||||||
|
RETURN c_success;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS
|
||||||
|
THEN
|
||||||
|
RETURN c_fail;
|
||||||
|
END;
|
||||||
|
|
||||||
|
FUNCTION check_acl (p_url VARCHAR2)
|
||||||
|
RETURN CHAR
|
||||||
|
IS
|
||||||
|
l_clob CLOB;
|
||||||
|
BEGIN
|
||||||
|
IF p_url IS NULL
|
||||||
|
THEN
|
||||||
|
RETURN c_fail;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT HTTPURITYPE (p_url).getclob ()
|
||||||
|
INTO l_clob
|
||||||
|
FROM DUAL;
|
||||||
|
|
||||||
|
/*SELECT c_success
|
||||||
|
INTO l_ret
|
||||||
|
FROM DUAL
|
||||||
|
WHERE EXISTS (SELECT HTTPURITYPE (p_url).getclob ()
|
||||||
|
FROM DUAL);
|
||||||
|
*/
|
||||||
|
RETURN c_success;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS
|
||||||
|
THEN
|
||||||
|
-- acl problem
|
||||||
|
if sqlcode=24247 then
|
||||||
|
RETURN c_fail;
|
||||||
|
else
|
||||||
|
-- no acl problem
|
||||||
|
return c_success;
|
||||||
|
end if;
|
||||||
|
END;
|
||||||
|
END;```
|
||||||
721
docs/packages/XLIB_JASPERREPORTS.md
Normal file
721
docs/packages/XLIB_JASPERREPORTS.md
Normal file
@@ -0,0 +1,721 @@
|
|||||||
|
# XLIB_JASPERREPORTS
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE "XLIB_JASPERREPORTS"
|
||||||
|
AS
|
||||||
|
/*=========================================================================
|
||||||
|
Purpose :
|
||||||
|
|
||||||
|
License : Copyright (c) 2010 Dietmar Aust (opal-consulting.de)
|
||||||
|
Licensed under a BSD style license (license.txt)
|
||||||
|
http://www.opal-consulting.de/pls/apex/f?p=20090928:14
|
||||||
|
|
||||||
|
$LastChangedDate: 2018-09-30 09:00:44 +0200 (So, 30 Sep 2018) $
|
||||||
|
$LastChangedBy: dietmar.aust $
|
||||||
|
|
||||||
|
Version Date Author Comment
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
06.01.2010 D. Aust Initial creation
|
||||||
|
06.05.2011 D. Aust added constants for xlsx and docx
|
||||||
|
05.08.2012 D. Aust added version 2.0.0 features:
|
||||||
|
- direct printing
|
||||||
|
- save file on server
|
||||||
|
11.05.2013 D. Aust added support for tunneling images for html
|
||||||
|
exports only
|
||||||
|
2.3.0.0 19.05.2014 D. Aust - #294 - Fix chunked encoding problem in
|
||||||
|
xlib_http.get_report
|
||||||
|
- added version information to this package
|
||||||
|
2.4.0.0 15.10.2017 D. Aust FEATURE: #3941 - Support for timeZones
|
||||||
|
(report parameter REPORT_TIME_ZONE)
|
||||||
|
2.5.0.0 29.09.2018 D. Aust FEATURE: #9 - Ability to set Printjob name (programmatically)
|
||||||
|
2.5.0.1 30.09.2018 D. Aust fix bool2string issue
|
||||||
|
2.6.1 01.10.2020 D. Aust add get_default_configuration() and set_default_configuration()
|
||||||
|
2.6.2 13.10.2020 D. Aust #54 - Timeout value from default table not working
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
|
||||||
|
-- version of this package
|
||||||
|
version_c constant varchar2(20 char) := '2.6.2';
|
||||||
|
|
||||||
|
-- constants
|
||||||
|
-- supported formats
|
||||||
|
c_rep_format_pdf CONSTANT VARCHAR2 (20) := 'pdf';
|
||||||
|
c_rep_format_rtf CONSTANT VARCHAR2 (20) := 'rtf';
|
||||||
|
c_rep_format_xls CONSTANT VARCHAR2 (20) := 'xls';
|
||||||
|
c_rep_format_html constant varchar2 (20) := 'html';
|
||||||
|
c_rep_format_html2 CONSTANT VARCHAR2 (20) := 'html2';
|
||||||
|
c_rep_format_csv CONSTANT VARCHAR2 (20) := 'csv';
|
||||||
|
c_rep_format_docx CONSTANT VARCHAR2 (20) := 'docx';
|
||||||
|
c_rep_format_pptx CONSTANT VARCHAR2 (20) := 'pptx';
|
||||||
|
c_rep_format_xlsx CONSTANT VARCHAR2 (20) := 'xlsx';
|
||||||
|
|
||||||
|
-- images uri
|
||||||
|
--c_images_uri_tunnel constant varchar2(100 char)
|
||||||
|
-- := 'xlib_jasperreports_img.get_image?p_url=#REPORT_URL#&p_image=';
|
||||||
|
-- #IMAGE_NAME# and #J2EE_CONTEXT# will be substituted on the J2EE server side
|
||||||
|
m_jri_cookie_name_c CONSTANT VARCHAR2 (50) := 'JRI_SESSIONID';
|
||||||
|
m_jri_path_cookie_name_c CONSTANT VARCHAR2 (50) := 'JRI_PATH';
|
||||||
|
c_images_uri_tunnel constant varchar2(500 char) := 'wwv_flow.show?p_request=APPLICATION_PROCESS%3DJRI_SHOW_IMAGE&p_flow_id=#APP_ID#&p_flow_step_id=0&p_instance=#APP_SESSION#&x01=#IMAGE_NAME#';
|
||||||
|
c_images_uri_no_tunnel constant varchar2(500 char) := '#J2EE_CONTEXT_PATH#/report_image?image=#IMAGE_NAME#';
|
||||||
|
|
||||||
|
-- exceptions
|
||||||
|
report_url_not_defined EXCEPTION;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- sets the url for the report server for all requests in the
|
||||||
|
-- current session
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
PROCEDURE set_report_url (p_report_url IN VARCHAR2);
|
||||||
|
|
||||||
|
FUNCTION get_report_url
|
||||||
|
RETURN VARCHAR2;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- set the image uri for html reports only!
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
PROCEDURE set_images_uri (p_images_uri IN VARCHAR2 default null);
|
||||||
|
procedure use_images_no_tunnel (p_server_uri in varchar2 default null, p_cookie_path varchar2 default null);
|
||||||
|
function get_use_images_no_tunnel return boolean;
|
||||||
|
|
||||||
|
FUNCTION get_images_uri
|
||||||
|
return varchar2;
|
||||||
|
FUNCTION get_cookie_path_no_tunnel
|
||||||
|
RETURN VARCHAR2;
|
||||||
|
|
||||||
|
|
||||||
|
/** make a callout with utl_http to the j2ee container running the
|
||||||
|
* JasperReportsIntegration web application
|
||||||
|
* => return the results
|
||||||
|
*
|
||||||
|
* @param p_rep_name name of the report (needs a name.jasper file deployed on the server)
|
||||||
|
* @param p_rep_format report format, e.g. pdf, rtf, etc, see constants
|
||||||
|
* @param p_data_source data source name, needs to be configured in J2EE application
|
||||||
|
* @param p_out_filename filename if the file should be downloaded
|
||||||
|
* @param p_rep_locale report locale setting, e.g. de_DE or en_US
|
||||||
|
* @param p_rep_encoding encoding, e.g. UTF-8
|
||||||
|
* @param p_additional_params additional parameters, e.g.: p1=1&p2=2
|
||||||
|
* @param p_print_is_enabled shall the report be sent to the printer directly?
|
||||||
|
* @param p_print_printer_name name or substring of printer name
|
||||||
|
* @param p_print_media media used, either the paper size or the tray
|
||||||
|
* @param p_print_copies number of copies to be printed
|
||||||
|
* @param p_print_duplex duplex printing?
|
||||||
|
* @param p_print_collate sorting the print output?
|
||||||
|
* @param p_save_is_enabled shall the generated file be saved on the server?
|
||||||
|
* @param p_rep_time_zone "time zone" parameter for the execution of the report,
|
||||||
|
a list of valid entries can be found here:
|
||||||
|
https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||||
|
E.g.: Europe/Berlin, UCT, US/Central, US/Pacific,
|
||||||
|
Etc/Greenwich, Europe/London
|
||||||
|
* @param p_save_filename filename for the file to be saved on the server
|
||||||
|
* @param p_print_job_name name of the print job name, by default it uses: JasperReports - <report name>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
PROCEDURE show_report (
|
||||||
|
p_rep_name IN VARCHAR2 DEFAULT 'test',
|
||||||
|
p_rep_format IN VARCHAR2 DEFAULT c_rep_format_pdf,
|
||||||
|
p_data_source IN VARCHAR2 DEFAULT 'default',
|
||||||
|
p_out_filename IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_rep_locale in varchar2 default 'de_DE',
|
||||||
|
p_rep_encoding in varchar2 default 'UTF-8',
|
||||||
|
p_additional_params in varchar2 default null,
|
||||||
|
p_print_is_enabled in boolean default false,
|
||||||
|
p_print_printer_name in varchar2 default null,
|
||||||
|
p_print_media in varchar2 default null,
|
||||||
|
p_print_copies in number default 1,
|
||||||
|
p_print_duplex in boolean default false,
|
||||||
|
p_print_collate in boolean default false,
|
||||||
|
p_save_is_enabled in boolean default false,
|
||||||
|
p_save_filename in varchar2 default null,
|
||||||
|
p_rep_time_zone in varchar2 default null,
|
||||||
|
p_print_job_name in varchar2 default null
|
||||||
|
);
|
||||||
|
|
||||||
|
/* tunnels images for html reports */
|
||||||
|
procedure show_image(p_image_name IN VARCHAR2);
|
||||||
|
|
||||||
|
|
||||||
|
/** run the report and return the result as a blob
|
||||||
|
*
|
||||||
|
* @param p_rep_name name of the report (needs a name.jasper file deployed on the server)
|
||||||
|
* @param p_rep_format report format, e.g. pdf, rtf, etc, see constants
|
||||||
|
* @param p_data_source data source name, needs to be configured in J2EE application
|
||||||
|
* @param p_out_filename filename if the file should be downloaded
|
||||||
|
* @param p_rep_locale report locale setting, e.g. de_DE or en_US
|
||||||
|
* @param p_rep_encoding encoding, e.g. UTF-8
|
||||||
|
* @param p_additional_params additional parameters, e.g.: p1=1&p2=2
|
||||||
|
* @param p_print_is_enabled shall the report be sent to the printer directly?
|
||||||
|
* @param p_print_printer_name name or substring of printer name
|
||||||
|
* @param p_print_media media used, either the paper size or the tray
|
||||||
|
* @param p_print_copies number of copies to be printed
|
||||||
|
* @param p_print_duplex duplex printing?
|
||||||
|
* @param p_print_collate sorting the print output?
|
||||||
|
* @param p_save_is_enabled shall the generated file be saved on the server?
|
||||||
|
* @param p_save_filename filename for the file to be saved on the server
|
||||||
|
* @param p_rep_time_zone "time zone" parameter for the execution of the report,
|
||||||
|
a list of valid entries can be found here:
|
||||||
|
https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||||
|
E.g.: Europe/Berlin, UCT, US/Central, US/Pacific,
|
||||||
|
Etc/Greenwich, Europe/London
|
||||||
|
* @param p_out_blob the blob will be returned here
|
||||||
|
* @param p_out_mime_type the proper mime type of the generated file
|
||||||
|
* @param p_print_job_name name of the print job name, by default it uses: JasperReports - <report name>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
PROCEDURE get_report (
|
||||||
|
p_rep_name IN VARCHAR2 DEFAULT 'test',
|
||||||
|
p_rep_format in varchar2 default c_rep_format_pdf,
|
||||||
|
p_data_source IN VARCHAR2 DEFAULT 'default',
|
||||||
|
p_rep_locale in varchar2 default 'de_DE',
|
||||||
|
p_rep_encoding IN VARCHAR2 DEFAULT 'UTF-8',
|
||||||
|
p_additional_params in varchar2 default null,
|
||||||
|
p_print_is_enabled in boolean default false,
|
||||||
|
p_print_printer_name in varchar2 default null,
|
||||||
|
p_print_media in varchar2 default null,
|
||||||
|
p_print_copies in number default 1,
|
||||||
|
p_print_duplex in boolean default false,
|
||||||
|
p_print_collate in boolean default false,
|
||||||
|
p_save_is_enabled in boolean default false,
|
||||||
|
p_save_filename in varchar2 default null,
|
||||||
|
p_rep_time_zone in varchar2 default null,
|
||||||
|
p_out_blob IN OUT BLOB,
|
||||||
|
p_out_mime_type IN OUT VARCHAR2,
|
||||||
|
p_print_job_name in varchar2 default null
|
||||||
|
);
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- get default configuration
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
FUNCTION get_default_configuration
|
||||||
|
return xlib_jasperreports_conf%rowtype;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- set default configuration
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
PROCEDURE set_default_configuration(p_conf in out xlib_jasperreports_conf%rowtype);
|
||||||
|
|
||||||
|
PROCEDURE set_default_configuration (
|
||||||
|
p_protocol IN xlib_jasperreports_conf.conf_protocol%TYPE default 'http',
|
||||||
|
p_server IN xlib_jasperreports_conf.conf_server%TYPE default 'localhost',
|
||||||
|
p_port IN xlib_jasperreports_conf.conf_port%TYPE default '80',
|
||||||
|
p_context_path IN xlib_jasperreports_conf.conf_context_path%TYPE default 'jri',
|
||||||
|
p_wallet_path IN xlib_jasperreports_conf.conf_wallet_path%TYPE default null,
|
||||||
|
p_wallet_pwd IN xlib_jasperreports_conf.conf_wallet_pwd%TYPE default null,
|
||||||
|
p_http_transfer_timeout IN xlib_jasperreports_conf.conf_http_transfer_timeout%TYPE default 60);
|
||||||
|
|
||||||
|
|
||||||
|
END;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE BODY "XLIB_JASPERREPORTS"
|
||||||
|
AS
|
||||||
|
/*=========================================================================
|
||||||
|
Purpose :
|
||||||
|
|
||||||
|
License : Copyright (c) 2010 Dietmar Aust (opal-consulting.de)
|
||||||
|
Licensed under a BSD style license (license.txt)
|
||||||
|
http://www.opal-consulting.de/pls/apex/f?p=20090928:14
|
||||||
|
|
||||||
|
$LastChangedDate: 2018-09-30 09:00:44 +0200 (So, 30 Sep 2018) $
|
||||||
|
$LastChangedBy: dietmar.aust $
|
||||||
|
|
||||||
|
Version Date Author Comment
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
06.01.2010 D. Aust Initial creation
|
||||||
|
06.05.2011 D. Aust added constants for xlsx and docx
|
||||||
|
05.08.2012 D. Aust added version 2.0.0 features:
|
||||||
|
- direct printing
|
||||||
|
- save file on server
|
||||||
|
11.05.2013 D. Aust added support for tunneling images for html
|
||||||
|
exports only
|
||||||
|
2.3.0.0 19.05.2014 D. Aust - #294 - Fix chunked encoding problem in
|
||||||
|
xlib_http.get_report
|
||||||
|
- added version information to this package
|
||||||
|
2.4.0.0 15.10.2017 D. Aust FEATURE: #3941 - Support for timeZones
|
||||||
|
(report parameter REPORT_TIME_ZONE)
|
||||||
|
2.5.0.0 29.09.2018 D. Aust FEATURE: #9 - Ability to set Printjob name (programmatically)
|
||||||
|
2.5.0.1 30.09.2018 D. Aust fix bool2string issue
|
||||||
|
2.6.1 01.10.2020 D. Aust add get_default_configuration() and set_default_configuration()
|
||||||
|
2.6.2 13.10.2020 D. Aust #54 - Timeout value from default table not working
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
m_module constant varchar2 (100) := $$plsql_unit;
|
||||||
|
m_report_url VARCHAR2 (32767) := NULL;
|
||||||
|
m_images_uri VARCHAR2 (32767) := NULL;
|
||||||
|
m_use_images_no_tunnel boolean := false;
|
||||||
|
m_cookie_path_no_tunnel varchar2(200 char) := null;
|
||||||
|
|
||||||
|
-- convert boolean to 'true' or 'false'
|
||||||
|
FUNCTION bool2string (b IN BOOLEAN)
|
||||||
|
RETURN VARCHAR2
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
IF b
|
||||||
|
THEN
|
||||||
|
RETURN 'true';
|
||||||
|
ELSE
|
||||||
|
RETURN 'false';
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
|
||||||
|
procedure setup_configuration_defaults
|
||||||
|
is
|
||||||
|
l_conf xlib_jasperreports_conf%rowtype;
|
||||||
|
l_timeout PLS_INTEGER;
|
||||||
|
begin
|
||||||
|
l_conf := get_default_configuration();
|
||||||
|
|
||||||
|
-- override report url if not defined
|
||||||
|
if m_report_url is null then
|
||||||
|
m_report_url := l_conf.conf_protocol || '://'||l_conf.conf_server||':'||l_conf.conf_port||'/'||l_conf.conf_context_path||'/report';
|
||||||
|
xlog(p_module => m_module, p_msg => 'Override report url from defaults: '|| m_report_url, p_type=> 'DEBUG');
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- set wallet path and pwd
|
||||||
|
-- will ALWAYS override the settings, will ignore previous calls to set_wallet
|
||||||
|
-- at least we check whether the config table has an entry for the wallet or not.
|
||||||
|
-- thus it could work relying on the wallet set by APEX through the internal workspace! :)
|
||||||
|
if lower(m_report_url) like 'https%' and l_conf.conf_wallet_path is not null then
|
||||||
|
utl_http.set_wallet(l_conf.conf_wallet_path, l_conf.conf_wallet_pwd);
|
||||||
|
xlog(p_module => m_module, p_msg => 'Override wallet location/pwd from defaults', p_type=> 'DEBUG');
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- override http transfer timeout it not defined
|
||||||
|
utl_http.get_transfer_timeout( timeout => l_timeout );
|
||||||
|
--xlog(p_module => m_module, p_msg => 'Current setting of transfer_timeout: '||l_timeout, p_type=> 'DEBUG');
|
||||||
|
if (l_timeout is null or l_timeout=60 /*60 is the default*/) then
|
||||||
|
utl_http.set_transfer_timeout(l_conf.conf_http_transfer_timeout);
|
||||||
|
xlog(p_module => m_module, p_msg => 'Override http transfer timeout ('||l_timeout||'s) from defaults: '|| l_conf.conf_http_transfer_timeout ||'s', p_type=> 'DEBUG');
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
PROCEDURE dump_all_cookies
|
||||||
|
IS
|
||||||
|
l_proc VARCHAR2 (100) := m_module || '.dump_all_cookies';
|
||||||
|
l_name_arr OWA_COOKIE.vc_arr;
|
||||||
|
l_vals_arr OWA_COOKIE.vc_arr;
|
||||||
|
l_vals_ret INTEGER;
|
||||||
|
BEGIN
|
||||||
|
xlog (l_proc, 'start');
|
||||||
|
OWA_COOKIE.get_all (names => l_name_arr, vals => l_vals_arr, num_vals => l_vals_ret);
|
||||||
|
|
||||||
|
xlog (l_proc, '#num of cookies: ' || l_vals_ret);
|
||||||
|
|
||||||
|
FOR i IN 1 .. l_name_arr.COUNT
|
||||||
|
LOOP
|
||||||
|
xlog (l_proc, i || ':' || l_name_arr (i) || '=' || l_vals_arr (i));
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
xlog (l_proc, 'end');
|
||||||
|
END;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- sets the url for the report server for all requests in the
|
||||||
|
-- current session
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
PROCEDURE set_report_url (p_report_url IN VARCHAR2)
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
xlog ('set_report_url:', p_report_url);
|
||||||
|
m_report_url := p_report_url;
|
||||||
|
END;
|
||||||
|
|
||||||
|
FUNCTION get_report_url
|
||||||
|
RETURN VARCHAR2
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
RETURN m_report_url;
|
||||||
|
END;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- sets the images_uri only for http reports!
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
PROCEDURE set_images_uri (p_images_uri IN VARCHAR2)
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
m_images_uri := p_images_uri;
|
||||||
|
END;
|
||||||
|
|
||||||
|
/* use the images from the application server when both /ords and /jri are
|
||||||
|
installed on the same application server
|
||||||
|
|
||||||
|
the p_server_uri parameter is rarely used, only when they are not run on the same application server
|
||||||
|
and the uri differs. But that comes with a lot of CORS and other cookie issues.
|
||||||
|
*/
|
||||||
|
procedure use_images_no_tunnel (p_server_uri in varchar2 default null, p_cookie_path varchar2 default null)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
m_use_images_no_tunnel := true;
|
||||||
|
m_cookie_path_no_tunnel := p_cookie_path;
|
||||||
|
|
||||||
|
-- the placeholders #J2EE_CONTEXT_PATH# and #IMAGE_NAME# will be replaced
|
||||||
|
-- inside the J2EE application with the current values of the deployment
|
||||||
|
set_images_uri( p_images_uri => p_server_uri || '#J2EE_CONTEXT_PATH#/report_image?image=#IMAGE_NAME#');
|
||||||
|
end;
|
||||||
|
|
||||||
|
function get_use_images_no_tunnel return boolean
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return m_use_images_no_tunnel;
|
||||||
|
end;
|
||||||
|
|
||||||
|
FUNCTION get_cookie_path_no_tunnel
|
||||||
|
RETURN VARCHAR2
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
RETURN m_cookie_path_no_tunnel;
|
||||||
|
END;
|
||||||
|
|
||||||
|
|
||||||
|
FUNCTION get_images_uri
|
||||||
|
RETURN VARCHAR2
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
RETURN m_images_uri;
|
||||||
|
END;
|
||||||
|
|
||||||
|
FUNCTION compute_images_uri_tunnel
|
||||||
|
RETURN VARCHAR2
|
||||||
|
IS
|
||||||
|
l_uri VARCHAR2 (32767 CHAR);
|
||||||
|
BEGIN
|
||||||
|
--l_uri := sys_context( 'userenv', 'current_schema' )
|
||||||
|
-- || '.' || c_images_uri_tunnel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
c_images_uri_tunnel
|
||||||
|
:='xlib_jasperreports_img.get_image?p_url=#REPORT_URL#&p_image=';
|
||||||
|
*/
|
||||||
|
|
||||||
|
--l_uri := replace(l_uri, '#REPORT_URL#', APEX_UTIL.URL_ENCODE(m_report_url));
|
||||||
|
--l_uri := replace(l_uri, '#REPORT_URL#', m_report_url);
|
||||||
|
|
||||||
|
-- c_images_uri_tunnel constant varchar2(100 char) := 'wwv_flow.show?p_request=APPLICATION_PROCESS%3DJRI_SHOW_IMAGE&p_flow_id=#APP_ID#&p_flow_step_id=0&p_instance=#APP_SESSION#&x01=#IMG_NAME#';
|
||||||
|
l_uri := c_images_uri_tunnel;
|
||||||
|
l_uri := REPLACE (l_uri, '#APP_ID#', v ('APP_ID'));
|
||||||
|
l_uri := REPLACE (l_uri, '#APP_SESSION#', v ('APP_SESSION'));
|
||||||
|
|
||||||
|
xlog ('compute tunnel', l_uri);
|
||||||
|
|
||||||
|
RETURN l_uri;
|
||||||
|
END;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- displays an image for html reports
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
PROCEDURE show_image (p_image_name IN VARCHAR2)
|
||||||
|
IS
|
||||||
|
l_proc VARCHAR2 (100) := m_module || '.show_image';
|
||||||
|
l_url VARCHAR2 (32767);
|
||||||
|
|
||||||
|
l_header_name_arr xlib_http.vc_arr_t;
|
||||||
|
l_header_value_arr xlib_http.vc_arr_t;
|
||||||
|
|
||||||
|
PROCEDURE get_headers_to_pass2j2ee (p_header_name_arr OUT xlib_http.vc_arr_t,
|
||||||
|
p_header_value_arr OUT xlib_http.vc_arr_t)
|
||||||
|
IS
|
||||||
|
l_proc VARCHAR2 (100) := m_module || '.get_headers_to_pass2j2ee';
|
||||||
|
jsession_cookie OWA_COOKIE.cookie;
|
||||||
|
jsession_path_cookie OWA_COOKIE.cookie;
|
||||||
|
BEGIN
|
||||||
|
jsession_cookie := OWA_COOKIE.get (name => m_jri_cookie_name_c);
|
||||||
|
jsession_path_cookie := OWA_COOKIE.get (name => m_jri_path_cookie_name_c);
|
||||||
|
|
||||||
|
xlog (l_proc, 'show jsession_id and path: ');
|
||||||
|
xlog (l_proc, jsession_cookie.vals (1));
|
||||||
|
xlog (l_proc, jsession_path_cookie.vals (1));
|
||||||
|
|
||||||
|
|
||||||
|
p_header_name_arr (p_header_name_arr.COUNT + 1) := 'Cookie';
|
||||||
|
p_header_value_arr (p_header_value_arr.COUNT + 1) :=
|
||||||
|
'JSESSIONID=' || jsession_cookie.vals (1) || ';Path=' || jsession_path_cookie.vals (1);
|
||||||
|
--xlog(l_proc, 'end');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS
|
||||||
|
THEN
|
||||||
|
xlog (l_proc, DBMS_UTILITY.format_error_backtrace, 'ERROR');
|
||||||
|
END;
|
||||||
|
BEGIN
|
||||||
|
xlog (l_proc, 'start: ### SHOW IMAGE: ' || p_image_name);
|
||||||
|
dump_all_cookies;
|
||||||
|
|
||||||
|
-- pick up defaults from table xlib_jasperreports_conf
|
||||||
|
setup_configuration_defaults();
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- assert valid values for the input variables
|
||||||
|
-------------------------------------------------------
|
||||||
|
IF m_report_url IS NULL
|
||||||
|
THEN
|
||||||
|
RAISE report_url_not_defined;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- construct URL
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- _image?image=img_0_0_15&uuid=b41eb881-7ca5-4919-bd8f-5afa8d10b398
|
||||||
|
l_url := m_report_url || '_image';
|
||||||
|
l_url := l_url || '?image=' || p_image_name;
|
||||||
|
l_url := l_url || '&JSESSIONID=' || OWA_COOKIE.get (name => m_jri_cookie_name_c).vals (1);
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- determine cookies for calling the j2ee server
|
||||||
|
-- JSESSIONID needs to be passed, the path needs to
|
||||||
|
-- be modified for the j2ee server context
|
||||||
|
-------------------------------------------------------
|
||||||
|
get_headers_to_pass2j2ee (p_header_name_arr => l_header_name_arr, p_header_value_arr => l_header_value_arr);
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- call J2EE server
|
||||||
|
-------------------------------------------------------
|
||||||
|
xlib_http.
|
||||||
|
display_url_raw (p_url => l_url, p_header_name_arr => l_header_name_arr, p_header_value_arr => l_header_value_arr);
|
||||||
|
END;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- make a callout with utl_http to the j2ee container running the
|
||||||
|
-- JasperReportsIntegration webapp
|
||||||
|
-- => return the results
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
PROCEDURE show_report (p_rep_name IN VARCHAR2 DEFAULT 'test',
|
||||||
|
p_rep_format IN VARCHAR2 DEFAULT c_rep_format_pdf,
|
||||||
|
p_data_source IN VARCHAR2 DEFAULT 'default',
|
||||||
|
p_out_filename IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_rep_locale IN VARCHAR2 DEFAULT 'de_DE',
|
||||||
|
p_rep_encoding IN VARCHAR2 DEFAULT 'UTF-8',
|
||||||
|
p_additional_params IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_print_is_enabled IN BOOLEAN DEFAULT FALSE,
|
||||||
|
p_print_printer_name IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_print_media IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_print_copies IN NUMBER DEFAULT 1,
|
||||||
|
p_print_duplex IN BOOLEAN DEFAULT FALSE,
|
||||||
|
p_print_collate IN BOOLEAN DEFAULT FALSE,
|
||||||
|
p_save_is_enabled IN BOOLEAN DEFAULT FALSE,
|
||||||
|
p_save_filename IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_rep_time_zone IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_print_job_name IN VARCHAR2 DEFAULT NULL)
|
||||||
|
IS
|
||||||
|
l_proc VARCHAR2 (100) := m_module || '.SHOW_REPORT';
|
||||||
|
l_url VARCHAR2 (32767);
|
||||||
|
BEGIN
|
||||||
|
-- pick up defaults from table xlib_jasperreports_conf
|
||||||
|
setup_configuration_defaults();
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- assert valid values for the input variables
|
||||||
|
-------------------------------------------------------
|
||||||
|
IF m_report_url IS NULL
|
||||||
|
THEN
|
||||||
|
xlog(p_module => m_module, p_msg => 'The report url is empty', p_type=> 'ERROR');
|
||||||
|
|
||||||
|
RAISE report_url_not_defined;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- construct URL
|
||||||
|
-------------------------------------------------------
|
||||||
|
l_url := m_report_url;
|
||||||
|
l_url := l_url || '?_repName=' || p_rep_name;
|
||||||
|
l_url := l_url || '&_repFormat=' || p_rep_format;
|
||||||
|
l_url := l_url || '&_dataSource=' || p_data_source;
|
||||||
|
l_url := l_url || '&_outFilename=' || p_out_filename;
|
||||||
|
l_url := l_url || '&_repLocale=' || p_rep_locale;
|
||||||
|
l_url := l_url || '&_repEncoding=' || p_rep_encoding;
|
||||||
|
l_url := l_url || '&_repTimeZone=' || APEX_UTIL.URL_ENCODE (p_rep_time_zone);
|
||||||
|
|
||||||
|
-- per default use the tunnel through the database
|
||||||
|
IF m_images_uri IS NULL OR m_images_uri = c_images_uri_tunnel
|
||||||
|
THEN
|
||||||
|
-- tunnel through database
|
||||||
|
l_url := l_url || '&_imagesURI=' || APEX_UTIL.URL_ENCODE (compute_images_uri_tunnel);
|
||||||
|
ELSE
|
||||||
|
-- use parameter, mostly for direct access to servlet
|
||||||
|
l_url := l_url || '&_imagesURI=' || APEX_UTIL.URL_ENCODE (m_images_uri);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- direct printing
|
||||||
|
l_url := l_url || '&_printIsEnabled=' || bool2string (p_print_is_enabled);
|
||||||
|
l_url := l_url || '&_printPrinterName=' || p_print_printer_name;
|
||||||
|
l_url := l_url || '&_printPrinterTray=' || p_print_media;
|
||||||
|
l_url := l_url || '&_printCopies=' || p_print_copies;
|
||||||
|
l_url := l_url || '&_printDuplex=' || bool2string (p_print_duplex);
|
||||||
|
l_url := l_url || '&_printCollate=' || bool2string (p_print_collate);
|
||||||
|
l_url := l_url || '&_printJobName=' || p_print_job_name;
|
||||||
|
|
||||||
|
-- save file on server
|
||||||
|
l_url := l_url || '&_saveIsEnabled=' || bool2string (p_save_is_enabled);
|
||||||
|
l_url := l_url || '&_saveFileName=' || p_save_filename;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Each additional parameter needs to be escaped using utl_url.escape()
|
||||||
|
utl_url.escape(
|
||||||
|
url => p_additional_params,
|
||||||
|
escape_reserved_chars => true,
|
||||||
|
url_charset => 'UTF-8'
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- additional report parameter passed?
|
||||||
|
IF (p_additional_params IS NOT NULL)
|
||||||
|
THEN
|
||||||
|
-- l_url := l_url || '&' || p_additional_params;
|
||||||
|
l_url := l_url || '&' || utl_url.escape(
|
||||||
|
url => p_additional_params,
|
||||||
|
escape_reserved_chars => false,
|
||||||
|
url_charset => 'UTF-8'
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- call J2EE server
|
||||||
|
-------------------------------------------------------
|
||||||
|
xlib_http.display_url_raw (p_url => l_url);
|
||||||
|
END;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- run the report and return the result as a blob
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
PROCEDURE get_report (p_rep_name IN VARCHAR2 DEFAULT 'test',
|
||||||
|
p_rep_format IN VARCHAR2 DEFAULT c_rep_format_pdf,
|
||||||
|
p_data_source IN VARCHAR2 DEFAULT 'default',
|
||||||
|
p_rep_locale IN VARCHAR2 DEFAULT 'de_DE',
|
||||||
|
p_rep_encoding IN VARCHAR2 DEFAULT 'UTF-8',
|
||||||
|
p_additional_params IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_print_is_enabled IN BOOLEAN DEFAULT FALSE,
|
||||||
|
p_print_printer_name IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_print_media IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_print_copies IN NUMBER DEFAULT 1,
|
||||||
|
p_print_duplex IN BOOLEAN DEFAULT FALSE,
|
||||||
|
p_print_collate IN BOOLEAN DEFAULT FALSE,
|
||||||
|
p_save_is_enabled IN BOOLEAN DEFAULT FALSE,
|
||||||
|
p_save_filename IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_rep_time_zone IN VARCHAR2 DEFAULT NULL,
|
||||||
|
p_out_blob IN OUT BLOB,
|
||||||
|
p_out_mime_type IN OUT VARCHAR2,
|
||||||
|
p_print_job_name IN VARCHAR2 DEFAULT NULL)
|
||||||
|
IS
|
||||||
|
l_proc VARCHAR2 (100) := m_module || '.GET_REPORT';
|
||||||
|
l_url VARCHAR2 (32767);
|
||||||
|
BEGIN
|
||||||
|
-- pick up defaults from table xlib_jasperreports_conf
|
||||||
|
setup_configuration_defaults();
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- assert valid values for the input variables
|
||||||
|
-------------------------------------------------------
|
||||||
|
IF m_report_url IS NULL
|
||||||
|
THEN
|
||||||
|
RAISE report_url_not_defined;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- construct URL
|
||||||
|
-------------------------------------------------------
|
||||||
|
l_url := m_report_url;
|
||||||
|
l_url := l_url || '?_repName=' || p_rep_name;
|
||||||
|
l_url := l_url || '&_repFormat=' || p_rep_format;
|
||||||
|
l_url := l_url || '&_dataSource=' || p_data_source;
|
||||||
|
l_url := l_url || '&_repLocale=' || p_rep_locale;
|
||||||
|
l_url := l_url || '&_repEncoding=' || p_rep_encoding;
|
||||||
|
l_url := l_url || '&_repTimeZone=' || APEX_UTIL.URL_ENCODE (p_rep_time_zone);
|
||||||
|
|
||||||
|
-- per default use the tunnel through the database
|
||||||
|
IF m_images_uri IS NULL OR m_images_uri = c_images_uri_tunnel
|
||||||
|
THEN
|
||||||
|
-- tunnel through database
|
||||||
|
l_url := l_url || '&_imagesURI=' || APEX_UTIL.URL_ENCODE (compute_images_uri_tunnel);
|
||||||
|
ELSE
|
||||||
|
-- use parameter, mostly for direct access to servlet
|
||||||
|
l_url := l_url || '&_imagesURI=' || APEX_UTIL.URL_ENCODE (m_images_uri);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- direct printing
|
||||||
|
l_url := l_url || '&_printIsEnabled=' || bool2string (p_print_is_enabled);
|
||||||
|
l_url := l_url || '&_printPrinterName=' || p_print_printer_name;
|
||||||
|
l_url := l_url || '&_printPrinterTray=' || p_print_media;
|
||||||
|
l_url := l_url || '&_printCopies=' || p_print_copies;
|
||||||
|
l_url := l_url || '&_printDuplex=' || bool2string (p_print_duplex);
|
||||||
|
l_url := l_url || '&_printCollate=' || bool2string (p_print_collate);
|
||||||
|
l_url := l_url || '&_printJobName=' || p_print_job_name;
|
||||||
|
|
||||||
|
-- save file on server
|
||||||
|
l_url := l_url || '&_saveIsEnabled=' || bool2string (p_save_is_enabled);
|
||||||
|
l_url := l_url || '&_saveFileName=' || p_save_filename;
|
||||||
|
|
||||||
|
-- additional report parameter passed?
|
||||||
|
IF (p_additional_params IS NOT NULL)
|
||||||
|
THEN
|
||||||
|
-- l_url := l_url || '&' || p_additional_params;
|
||||||
|
l_url := l_url || '&' || utl_url.escape(
|
||||||
|
url => p_additional_params,
|
||||||
|
escape_reserved_chars => false,
|
||||||
|
url_charset => 'UTF-8'
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- call Tomcat
|
||||||
|
-------------------------------------------------------
|
||||||
|
xlib_http.retrieve_blob_from_url (p_url => l_url, o_blob => p_out_blob, o_mime_type => p_out_mime_type);
|
||||||
|
END;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- get default configuration
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
FUNCTION get_default_configuration
|
||||||
|
RETURN xlib_jasperreports_conf%ROWTYPE
|
||||||
|
IS
|
||||||
|
l_conf xlib_jasperreports_conf%ROWTYPE;
|
||||||
|
BEGIN
|
||||||
|
SELECT *
|
||||||
|
INTO l_conf
|
||||||
|
FROM xlib_jasperreports_conf
|
||||||
|
WHERE conf_id = 'MAIN';
|
||||||
|
|
||||||
|
RETURN l_conf;
|
||||||
|
END;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- set default configuration
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
PROCEDURE set_default_configuration (p_conf IN OUT xlib_jasperreports_conf%ROWTYPE)
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
p_conf.conf_id := 'MAIN';
|
||||||
|
|
||||||
|
UPDATE xlib_jasperreports_conf
|
||||||
|
SET row = p_conf
|
||||||
|
WHERE conf_id = p_conf.conf_id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
|
||||||
|
PROCEDURE set_default_configuration (
|
||||||
|
p_protocol IN xlib_jasperreports_conf.conf_protocol%TYPE default 'http',
|
||||||
|
p_server IN xlib_jasperreports_conf.conf_server%TYPE default 'localhost',
|
||||||
|
p_port IN xlib_jasperreports_conf.conf_port%TYPE default '80',
|
||||||
|
p_context_path IN xlib_jasperreports_conf.conf_context_path%TYPE default 'jri',
|
||||||
|
p_wallet_path IN xlib_jasperreports_conf.conf_wallet_path%TYPE default null,
|
||||||
|
p_wallet_pwd IN xlib_jasperreports_conf.conf_wallet_pwd%TYPE default null,
|
||||||
|
p_http_transfer_timeout IN xlib_jasperreports_conf.conf_http_transfer_timeout%TYPE default 60)
|
||||||
|
IS
|
||||||
|
BEGIN
|
||||||
|
UPDATE xlib_jasperreports_conf
|
||||||
|
SET conf_protocol = p_protocol,
|
||||||
|
conf_server = p_server,
|
||||||
|
conf_port = p_port,
|
||||||
|
conf_context_path = p_context_path,
|
||||||
|
conf_wallet_path = p_wallet_path,
|
||||||
|
conf_wallet_pwd = p_wallet_pwd,
|
||||||
|
conf_http_transfer_timeout = p_http_transfer_timeout
|
||||||
|
WHERE conf_id = 'MAIN';
|
||||||
|
END;
|
||||||
|
END;```
|
||||||
63
docs/packages/XLIB_JASPERREPORTS_IMG.md
Normal file
63
docs/packages/XLIB_JASPERREPORTS_IMG.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# XLIB_JASPERREPORTS_IMG
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE XLIB_JASPERREPORTS_IMG AS
|
||||||
|
/*
|
||||||
|
$Id: xlib_jasperreports_img.pks 71 2017-10-15 16:25:51Z dietmar.aust $
|
||||||
|
*/
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- get_image: retrieves a report image from the server
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
PROCEDURE get_image (p_url in varchar2, p_image IN VARCHAR2);
|
||||||
|
|
||||||
|
procedure test;
|
||||||
|
|
||||||
|
|
||||||
|
END XLIB_JASPERREPORTS_IMG;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
package body xlib_jasperreports_img as
|
||||||
|
/*
|
||||||
|
$Id: xlib_jasperreports_img.pkb 71 2017-10-15 16:25:51Z dietmar.aust $
|
||||||
|
*/
|
||||||
|
m_module constant varchar2 (100) := $$plsql_unit;
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- get_image: retrieves a report image from the server
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
procedure get_image (p_url in varchar2, p_image in varchar2)
|
||||||
|
is
|
||||||
|
l_url varchar2 (32767);
|
||||||
|
l_proc VARCHAR2 (100) := m_module || '.GET_IMAGE';
|
||||||
|
begin
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- construct URL
|
||||||
|
-------------------------------------------------------
|
||||||
|
l_url := p_url;
|
||||||
|
-- use image servlet
|
||||||
|
l_url := l_url || '_image?image=' || p_image;
|
||||||
|
-- use images directory /report_tmp/
|
||||||
|
--l_url := l_url || '_tmp/' || p_image;
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
-- call J2EE server
|
||||||
|
-------------------------------------------------------
|
||||||
|
xlog(l_proc, l_url);
|
||||||
|
xlib_http.display_url_raw (p_url => l_url);
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure test
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
htp.p('test');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
END XLIB_JASPERREPORTS_IMG;```
|
||||||
58
docs/packages/XLIB_LOG.md
Normal file
58
docs/packages/XLIB_LOG.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# XLIB_LOG
|
||||||
|
|
||||||
|
## Package Specification
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE "XLIB_LOG"
|
||||||
|
IS
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Purpose : Application Logging
|
||||||
|
|
||||||
|
License : Copyright (c) 2010 Dietmar Aust (opal-consulting.de)
|
||||||
|
Licensed under a BSD style license (license.txt)
|
||||||
|
https://github.com/daust/JasperReportsIntegration
|
||||||
|
|
||||||
|
Date Author Comment
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
06.01.2010 D. Aust Initial creation
|
||||||
|
13.05.2012 D. Aust insert fails when created_by user value too large
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
|
||||||
|
PROCEDURE m (
|
||||||
|
p_module IN VARCHAR2,
|
||||||
|
p_msg IN VARCHAR2,
|
||||||
|
p_type IN VARCHAR2 DEFAULT 'DEBUG',
|
||||||
|
p_level PLS_INTEGER DEFAULT 15
|
||||||
|
);
|
||||||
|
END;```
|
||||||
|
|
||||||
|
## Package Body
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PACKAGE BODY "XLIB_LOG"
|
||||||
|
IS
|
||||||
|
|
||||||
|
PROCEDURE m (
|
||||||
|
p_module IN VARCHAR2,
|
||||||
|
p_msg IN VARCHAR2,
|
||||||
|
p_type IN VARCHAR2 DEFAULT 'DEBUG',
|
||||||
|
p_level IN PLS_INTEGER DEFAULT 15
|
||||||
|
)
|
||||||
|
IS
|
||||||
|
PRAGMA AUTONOMOUS_TRANSACTION;
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO xlib_logs
|
||||||
|
(log_module, log_msg, log_type, log_level, log_created_on, log_created_by
|
||||||
|
)
|
||||||
|
values ( substr(p_module,1,100)
|
||||||
|
, substr(p_msg,1,4000)
|
||||||
|
, substr(p_type,1,20)
|
||||||
|
, p_level
|
||||||
|
, sysdate
|
||||||
|
, substr(nvl(v('APP_USER'), user),1,100)
|
||||||
|
);
|
||||||
|
COMMIT;
|
||||||
|
END;
|
||||||
|
END;```
|
||||||
419
docs/procedures/EVENTI_AGGIORNA_QTA_LISTA.md
Normal file
419
docs/procedures/EVENTI_AGGIORNA_QTA_LISTA.md
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
# EVENTI_AGGIORNA_QTA_LISTA
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PROCEDURE "EVENTI_AGGIORNA_QTA_LISTA" (
|
||||||
|
p_id_evento NUMBER
|
||||||
|
) AS
|
||||||
|
-- ricalcola tutte le qta della lista
|
||||||
|
|
||||||
|
v_cod_art VARCHAR2(10);
|
||||||
|
v_coeff_a NUMBER;
|
||||||
|
v_coeff_s NUMBER;
|
||||||
|
v_coeff_b NUMBER;
|
||||||
|
v_ospiti NUMBER;
|
||||||
|
v_qta_a NUMBER;
|
||||||
|
v_qta_s NUMBER;
|
||||||
|
v_qta_b NUMBER;
|
||||||
|
v_qta_std_a NUMBER;
|
||||||
|
v_qta_std_s NUMBER;
|
||||||
|
v_qta_std_b NUMBER;
|
||||||
|
v_count_tov NUMBER;
|
||||||
|
v_count_tov_buf NUMBER;
|
||||||
|
v_qta_giac NUMBER;
|
||||||
|
v_qta_imp NUMBER;
|
||||||
|
v_data_evt DATE;
|
||||||
|
v_qta_man VARCHAR2(100);
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
-- Daniele Viti
|
||||||
|
-- Scorre tutti gli articoli dell'evento
|
||||||
|
---------
|
||||||
|
FOR c IN (
|
||||||
|
SELECT DISTINCT
|
||||||
|
cod_articolo
|
||||||
|
FROM
|
||||||
|
eventi_det_prel
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
) LOOP
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
--default su qta:
|
||||||
|
|
||||||
|
--verifica qta standard
|
||||||
|
SELECT
|
||||||
|
nvl(qta_std_a, 0),
|
||||||
|
nvl(qta_std_s, 0),
|
||||||
|
nvl(qta_std_b, 0)
|
||||||
|
INTO
|
||||||
|
v_qta_std_a,
|
||||||
|
v_qta_std_s,
|
||||||
|
v_qta_std_b
|
||||||
|
FROM
|
||||||
|
articoli
|
||||||
|
WHERE
|
||||||
|
cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
IF v_qta_std_a > 0 OR v_qta_std_s > 0 OR v_qta_std_b > 0 THEN
|
||||||
|
UPDATE eventi_det_prel
|
||||||
|
SET
|
||||||
|
qta_ape = v_qta_std_a,
|
||||||
|
qta_sedu = v_qta_std_s,
|
||||||
|
qta_bufdol = v_qta_std_b,
|
||||||
|
qta = qta_ape + qta_sedu + qta_bufdol + qta_man_ape + qta_man_sedu + qta_man_bufdol
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
AND cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
CONTINUE; -- se esistono le qta standard aggiorna e passa il giro successivo!
|
||||||
|
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
cod_relativo
|
||||||
|
INTO v_cod_art
|
||||||
|
FROM
|
||||||
|
articoli
|
||||||
|
WHERE
|
||||||
|
cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
IF v_cod_art IS NULL THEN
|
||||||
|
--Articolo Relativo assente
|
||||||
|
|
||||||
|
--verifica se cod_articolo è di tipo TOVAGLE O CARAFFE etc...
|
||||||
|
SELECT
|
||||||
|
COUNT(*)
|
||||||
|
INTO v_count_tov
|
||||||
|
FROM
|
||||||
|
articoli a
|
||||||
|
JOIN tb_codici_categ c ON a.cod_categ = c.cod_categ
|
||||||
|
JOIN tb_tipi_mat t ON c.cod_tipo = t.cod_tipo
|
||||||
|
WHERE
|
||||||
|
( c.cod_tipo IN ( 'CA-CARAFFE' )
|
||||||
|
-- or c.COD_CATEG in ('TOV-BUFF','TOV-SED')
|
||||||
|
OR c.cod_categ IN ( 'TOV-SED' ) )
|
||||||
|
AND a.cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
--verifica se cod_articolo è di tipo TOVAGLE BUFFET
|
||||||
|
SELECT
|
||||||
|
COUNT(*)
|
||||||
|
INTO v_count_tov_buf
|
||||||
|
FROM
|
||||||
|
articoli a
|
||||||
|
JOIN tb_codici_categ c ON a.cod_categ = c.cod_categ
|
||||||
|
JOIN tb_tipi_mat t ON c.cod_tipo = t.cod_tipo
|
||||||
|
WHERE
|
||||||
|
c.cod_categ IN ( 'TOV-BUFF' )
|
||||||
|
AND a.cod_articolo = c.cod_articolo; -- 'CM-DANI'
|
||||||
|
|
||||||
|
IF v_count_tov > 0 THEN
|
||||||
|
--c.COD_ARTICOLO è di tipo TOVAGLE O CARAFFE etc...
|
||||||
|
|
||||||
|
-- reperisco le qta tot inserita per i tavoli
|
||||||
|
SELECT
|
||||||
|
nvl(SUM(qta_ape),
|
||||||
|
0),
|
||||||
|
nvl(SUM(qta_sedu),
|
||||||
|
0),
|
||||||
|
nvl(SUM(qta_bufdol),
|
||||||
|
0)
|
||||||
|
INTO
|
||||||
|
v_qta_a,
|
||||||
|
v_qta_s,
|
||||||
|
v_qta_b
|
||||||
|
FROM
|
||||||
|
eventi_det_prel e
|
||||||
|
JOIN articoli a ON e.cod_articolo = a.cod_articolo
|
||||||
|
JOIN tb_codici_categ c ON a.cod_categ = c.cod_categ
|
||||||
|
JOIN tb_tipi_mat t ON c.cod_tipo = t.cod_tipo
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
AND c.cod_tipo IN ( 'TA' );
|
||||||
|
|
||||||
|
--recupero il coefficente dell'atricolo (tovagliato o caraffe) e lo moltiplico x la qta tavoli
|
||||||
|
SELECT
|
||||||
|
nvl(coeff_a, 0),
|
||||||
|
nvl(coeff_s, 0),
|
||||||
|
nvl(coeff_b, 0)
|
||||||
|
INTO
|
||||||
|
v_coeff_a,
|
||||||
|
v_coeff_s,
|
||||||
|
v_coeff_b
|
||||||
|
FROM
|
||||||
|
articoli
|
||||||
|
WHERE
|
||||||
|
cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
UPDATE eventi_det_prel
|
||||||
|
SET
|
||||||
|
qta_ape = v_qta_a * v_coeff_a,
|
||||||
|
qta_sedu = v_qta_s * v_coeff_s,
|
||||||
|
qta_bufdol = v_qta_b * v_coeff_b,
|
||||||
|
qta = qta_ape + qta_sedu + qta_bufdol + qta_man_ape + qta_man_sedu + qta_man_bufdol
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
AND cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
ELSIF v_count_tov_buf > 0 THEN
|
||||||
|
--c.COD_ARTICOLO è di tipo TOVAGLE BUFFET
|
||||||
|
|
||||||
|
-- reperisco le qta tot inserita per gli angoli buffet
|
||||||
|
SELECT
|
||||||
|
nvl(SUM(qta_ape),
|
||||||
|
0),
|
||||||
|
nvl(SUM(qta_sedu),
|
||||||
|
0),
|
||||||
|
nvl(SUM(qta_bufdol),
|
||||||
|
0)
|
||||||
|
INTO
|
||||||
|
v_qta_a,
|
||||||
|
v_qta_s,
|
||||||
|
v_qta_b
|
||||||
|
FROM
|
||||||
|
eventi_det_prel e
|
||||||
|
JOIN articoli a ON e.cod_articolo = a.cod_articolo
|
||||||
|
JOIN tb_codici_categ c ON a.cod_categ = c.cod_categ
|
||||||
|
JOIN tb_tipi_mat t ON c.cod_tipo = t.cod_tipo
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
AND c.cod_tipo IN ( 'AN' );
|
||||||
|
|
||||||
|
--recupero il coefficente dell'atricolo (tovagliato buffet) e lo moltiplico x la qta angoli
|
||||||
|
SELECT
|
||||||
|
nvl(coeff_a, 0),
|
||||||
|
nvl(coeff_s, 0),
|
||||||
|
nvl(coeff_b, 0)
|
||||||
|
INTO
|
||||||
|
v_coeff_a,
|
||||||
|
v_coeff_s,
|
||||||
|
v_coeff_b
|
||||||
|
FROM
|
||||||
|
articoli
|
||||||
|
WHERE
|
||||||
|
cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
UPDATE eventi_det_prel
|
||||||
|
SET
|
||||||
|
qta_ape = v_qta_a * v_coeff_a,
|
||||||
|
qta_sedu = v_qta_s * v_coeff_s,
|
||||||
|
qta_bufdol = v_qta_b * v_coeff_b,
|
||||||
|
qta = qta_ape + qta_sedu + qta_bufdol + qta_man_ape + qta_man_sedu + qta_man_bufdol
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
AND cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
ELSE
|
||||||
|
BEGIN
|
||||||
|
v_cod_art := c.cod_articolo;
|
||||||
|
SELECT
|
||||||
|
nvl(coeff_a, 0),
|
||||||
|
nvl(coeff_s, 0),
|
||||||
|
nvl(coeff_b, 0)
|
||||||
|
INTO
|
||||||
|
v_coeff_a,
|
||||||
|
v_coeff_s,
|
||||||
|
v_coeff_b
|
||||||
|
FROM
|
||||||
|
articoli
|
||||||
|
WHERE
|
||||||
|
cod_articolo = v_cod_art;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
nvl(tot_ospiti, 0)
|
||||||
|
INTO v_ospiti
|
||||||
|
FROM
|
||||||
|
eventi
|
||||||
|
WHERE
|
||||||
|
id = p_id_evento;
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN no_data_found THEN
|
||||||
|
raise_application_error(-20001, 'Errore: Coefficenti/Num Ospiti NON TROVATI - '
|
||||||
|
|| sqlcode
|
||||||
|
|| ' - '
|
||||||
|
|| substr(sqlerrm, 1, 64));
|
||||||
|
END;
|
||||||
|
|
||||||
|
UPDATE eventi_det_prel
|
||||||
|
SET
|
||||||
|
qta_ape = trunc(v_coeff_a * v_ospiti),
|
||||||
|
qta_sedu = trunc(v_coeff_s * v_ospiti),
|
||||||
|
qta_bufdol = trunc(v_coeff_b * v_ospiti),
|
||||||
|
qta = qta_ape + qta_sedu + qta_bufdol + qta_man_ape + qta_man_sedu + qta_man_bufdol
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
AND cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
ELSE
|
||||||
|
-- cod relativo valorizzato
|
||||||
|
BEGIN
|
||||||
|
-- reperisco le qta inserite per il cod_relativo nella lista
|
||||||
|
SELECT
|
||||||
|
nvl(qta_ape, 0),
|
||||||
|
nvl(qta_sedu, 0),
|
||||||
|
nvl(qta_bufdol, 0)
|
||||||
|
INTO
|
||||||
|
v_qta_a,
|
||||||
|
v_qta_s,
|
||||||
|
v_qta_b
|
||||||
|
FROM
|
||||||
|
eventi_det_prel
|
||||||
|
WHERE
|
||||||
|
cod_articolo = v_cod_art
|
||||||
|
AND id_evento = p_id_evento;
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN no_data_found THEN
|
||||||
|
CONTINUE;
|
||||||
|
-- Disattivato temporaneamente per evitare spam
|
||||||
|
--RAISE_APPLICATION_ERROR(-20000, 'Errore: Qta NON TROVATA !!! - v_cod_art: ' || v_cod_art || ' - ' || SQLCODE || ' - ' || SUBSTR(SQLERRM, 1 , 64));
|
||||||
|
END;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
-- reperisco i coefficenti
|
||||||
|
SELECT
|
||||||
|
nvl(coeff_a, 0),
|
||||||
|
nvl(coeff_s, 0),
|
||||||
|
nvl(coeff_b, 0)
|
||||||
|
INTO
|
||||||
|
v_coeff_a,
|
||||||
|
v_coeff_s,
|
||||||
|
v_coeff_b
|
||||||
|
FROM
|
||||||
|
articoli
|
||||||
|
WHERE
|
||||||
|
cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN no_data_found THEN
|
||||||
|
raise_application_error(-20001, 'Errore: Qta/Coefficenti del codice relativo NON TROVATI - '
|
||||||
|
|| sqlcode
|
||||||
|
|| ' - '
|
||||||
|
|| substr(sqlerrm, 1, 64));
|
||||||
|
END;
|
||||||
|
|
||||||
|
UPDATE eventi_det_prel
|
||||||
|
SET
|
||||||
|
qta_ape = trunc(v_coeff_a * v_qta_a),
|
||||||
|
qta_sedu = trunc(v_coeff_s * v_qta_s),
|
||||||
|
qta_bufdol = trunc(v_coeff_b * v_qta_b),
|
||||||
|
qta = qta_ape + qta_sedu + qta_bufdol + qta_man_ape + qta_man_sedu + qta_man_bufdol
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
AND cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- NOTE SE SUPERO LA QTA DISPONBILE !!!
|
||||||
|
BEGIN
|
||||||
|
SELECT
|
||||||
|
data
|
||||||
|
INTO v_data_evt
|
||||||
|
FROM
|
||||||
|
eventi
|
||||||
|
WHERE
|
||||||
|
id = p_id_evento;
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN no_data_found THEN
|
||||||
|
raise_application_error(-20001, 'v_data_evento - '
|
||||||
|
|| v_data_evt
|
||||||
|
|| ' - '
|
||||||
|
|| sqlcode
|
||||||
|
|| ' - '
|
||||||
|
|| substr(sqlerrm, 1, 64));
|
||||||
|
END;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
SELECT
|
||||||
|
qta_giac
|
||||||
|
INTO v_qta_giac
|
||||||
|
FROM
|
||||||
|
articoli
|
||||||
|
WHERE
|
||||||
|
cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN no_data_found THEN
|
||||||
|
raise_application_error(-20001, 'v_qta_giac - '
|
||||||
|
|| v_qta_giac
|
||||||
|
|| ' - '
|
||||||
|
|| sqlcode
|
||||||
|
|| ' - '
|
||||||
|
|| substr(sqlerrm, 1, 64));
|
||||||
|
END;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
SELECT
|
||||||
|
nvl(f_get_qta_impegnata(c.cod_articolo, v_data_evt),
|
||||||
|
0)
|
||||||
|
INTO v_qta_imp
|
||||||
|
FROM
|
||||||
|
dual;
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN no_data_found THEN
|
||||||
|
raise_application_error(-20001, 'v_qta_imp - '
|
||||||
|
|| v_qta_imp
|
||||||
|
|| ' - '
|
||||||
|
|| v_cod_art
|
||||||
|
|| ', '
|
||||||
|
|| v_data_evt
|
||||||
|
|| ' - '
|
||||||
|
|| sqlcode
|
||||||
|
|| ' - '
|
||||||
|
|| substr(sqlerrm, 1, 64));
|
||||||
|
END;
|
||||||
|
|
||||||
|
--RAISE_APPLICATION_ERROR(-20000, 'v_qta_giac - ' || v_qta_giac || ' - ' || SQLCODE || ' - ' || SUBSTR(SQLERRM, 1 , 64));
|
||||||
|
dbms_output.put_line('CodArt: '
|
||||||
|
|| c.cod_articolo
|
||||||
|
|| '; Qta Imp: '
|
||||||
|
|| v_qta_imp
|
||||||
|
|| '; Qta Giac: '
|
||||||
|
|| v_qta_giac);
|
||||||
|
--NOTA: a differenza del trigger "BEFORE INSERT ON EVENTI_DET_PREL",
|
||||||
|
-- in questo caso la qta_imp è già comprensiva della qta ricalcolata
|
||||||
|
IF v_qta_imp > v_qta_giac THEN
|
||||||
|
v_qta_man := v_qta_imp - v_qta_giac;
|
||||||
|
--:NEW.NOTE := 'QTA TOT NON Disponibile, mancano: ' || to_char(v_qta_man);
|
||||||
|
UPDATE eventi_det_prel
|
||||||
|
SET
|
||||||
|
note = 'QTA TOT NON Disponibile, mancano: ' || to_char(v_qta_man)
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
AND cod_articolo = c.cod_articolo;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
ELSE
|
||||||
|
UPDATE eventi_det_prel
|
||||||
|
SET
|
||||||
|
note = NULL
|
||||||
|
WHERE
|
||||||
|
id_evento = p_id_evento
|
||||||
|
AND cod_articolo = c.cod_articolo
|
||||||
|
AND note LIKE '%QTA TOT NON Disponibile%';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
raise_application_error(-20001, 'Errore: '
|
||||||
|
|| sqlcode
|
||||||
|
|| ' - '
|
||||||
|
|| substr(sqlerrm, 1, 64));
|
||||||
|
END;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
END eventi_aggiorna_qta_lista;```
|
||||||
45
docs/procedures/EVENTI_AGGIORNA_TOT_OSPITI.md
Normal file
45
docs/procedures/EVENTI_AGGIORNA_TOT_OSPITI.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# EVENTI_AGGIORNA_TOT_OSPITI
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PROCEDURE "EVENTI_AGGIORNA_TOT_OSPITI" (
|
||||||
|
p_id_evento IN NUMBER DEFAULT 0
|
||||||
|
) AS
|
||||||
|
--aggiorna la qta toto ospiti
|
||||||
|
--job aggiorna_tot_ospiti
|
||||||
|
|
||||||
|
CURSOR c_eventi IS
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
eventi
|
||||||
|
WHERE
|
||||||
|
id = p_id_evento;
|
||||||
|
|
||||||
|
v_tot_ospiti NUMBER;
|
||||||
|
BEGIN
|
||||||
|
/*
|
||||||
|
for c in c_eventi
|
||||||
|
loop
|
||||||
|
*/
|
||||||
|
BEGIN
|
||||||
|
v_tot_ospiti := f_get_tot_ospiti(p_id_evento);
|
||||||
|
UPDATE eventi
|
||||||
|
SET
|
||||||
|
tot_ospiti = v_tot_ospiti
|
||||||
|
WHERE
|
||||||
|
id = p_id_evento;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
raise_application_error(-20000, 'Errore nel calcolo del totale ospiti: '
|
||||||
|
|| sqlcode
|
||||||
|
|| ' - '
|
||||||
|
|| sqlerrm);
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- end loop;
|
||||||
|
|
||||||
|
END eventi_aggiorna_tot_ospiti;```
|
||||||
214
docs/procedures/EVENTI_COPIA.md
Normal file
214
docs/procedures/EVENTI_COPIA.md
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
# EVENTI_COPIA
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PROCEDURE eventi_copia (
|
||||||
|
id_evento_old IN NUMBER,
|
||||||
|
nuova_versione IN NUMBER DEFAULT 0,
|
||||||
|
id_evento_new OUT NUMBER
|
||||||
|
) AS
|
||||||
|
r_evento eventi%rowtype;
|
||||||
|
v_new_evt_id eventi.id%TYPE;
|
||||||
|
BEGIN
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
INTO r_evento
|
||||||
|
FROM
|
||||||
|
eventi
|
||||||
|
WHERE
|
||||||
|
id = id_evento_old;
|
||||||
|
|
||||||
|
r_evento.id := NULL;
|
||||||
|
r_evento.is_template := 0;
|
||||||
|
IF nuova_versione = 1 THEN
|
||||||
|
r_evento.id_evt_padre := id_evento_old;
|
||||||
|
r_evento.vers_number := nvl(r_evento.vers_number, 0) + 1; -- aggiorno il numero versione
|
||||||
|
ELSE
|
||||||
|
r_evento.id_evt_padre := NULL;
|
||||||
|
r_evento.vers_number := 0;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Copio l'evento facendo creare il nuovo id dal trigger
|
||||||
|
INSERT INTO eventi VALUES r_evento RETURNING id INTO v_new_evt_id;
|
||||||
|
|
||||||
|
IF nuova_versione = 1 THEN
|
||||||
|
-- Aggiorno il vecchio evento col nuovo id
|
||||||
|
UPDATE eventi
|
||||||
|
SET
|
||||||
|
id_evt_figlio = v_new_evt_id
|
||||||
|
WHERE
|
||||||
|
id = id_evento_old;
|
||||||
|
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- Aggiungo i figli alla nuova versione
|
||||||
|
-- Degustazioni
|
||||||
|
INSERT INTO eventi_det_degust (
|
||||||
|
id_evento,
|
||||||
|
data,
|
||||||
|
ora,
|
||||||
|
nome,
|
||||||
|
telefono,
|
||||||
|
email,
|
||||||
|
location,
|
||||||
|
n_persone,
|
||||||
|
menu,
|
||||||
|
n_paganti,
|
||||||
|
note,
|
||||||
|
n_degustazione,
|
||||||
|
consumata,
|
||||||
|
costo_degustazione
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
v_new_evt_id,
|
||||||
|
data,
|
||||||
|
ora,
|
||||||
|
nome,
|
||||||
|
telefono,
|
||||||
|
email,
|
||||||
|
location,
|
||||||
|
n_persone,
|
||||||
|
menu,
|
||||||
|
n_paganti,
|
||||||
|
note,
|
||||||
|
n_degustazione,
|
||||||
|
consumata,
|
||||||
|
costo_degustazione
|
||||||
|
FROM
|
||||||
|
eventi_det_degust
|
||||||
|
WHERE
|
||||||
|
id_evento = id_evento_old;
|
||||||
|
|
||||||
|
-- Ospiti
|
||||||
|
-- Devo fare una update... DIO TRIGGER
|
||||||
|
FOR c IN (
|
||||||
|
SELECT
|
||||||
|
id_evento,
|
||||||
|
cod_tipo_ospite,
|
||||||
|
numero,
|
||||||
|
note
|
||||||
|
FROM
|
||||||
|
eventi_det_ospiti
|
||||||
|
WHERE
|
||||||
|
id_evento = id_evento_old
|
||||||
|
) LOOP
|
||||||
|
UPDATE eventi_det_ospiti
|
||||||
|
SET
|
||||||
|
numero = c.numero,
|
||||||
|
note = c.note
|
||||||
|
WHERE
|
||||||
|
id_evento = v_new_evt_id
|
||||||
|
AND cod_tipo_ospite = c.cod_tipo_ospite;
|
||||||
|
|
||||||
|
END LOOP;
|
||||||
|
-- insert into eventi_det_ospiti (ID_EVENTO, COD_TIPO_OSPITE, NUMERO, NOTE)
|
||||||
|
-- select v_new_evt_id, COD_TIPO_OSPITE, NUMERO, NOTE
|
||||||
|
-- from eventi_det_ospiti
|
||||||
|
-- where id_evento = ID_EVENTO_OLD;
|
||||||
|
|
||||||
|
-- Prelievi
|
||||||
|
/* COME DA RICHIESTA DEL 01/2024 NON COPIO LA LISTA PRELIEVO NELLA NUOVA VERSIONE */
|
||||||
|
/* RIATTIVO NUOVAMENTE LA COPIA IL 12/02/2024 */
|
||||||
|
INSERT INTO eventi_det_prel (
|
||||||
|
id_evento,
|
||||||
|
cod_articolo,
|
||||||
|
qta,
|
||||||
|
note,
|
||||||
|
qta_ape,
|
||||||
|
qta_sedu,
|
||||||
|
qta_bufdol,
|
||||||
|
qta_man_ape,
|
||||||
|
qta_man_sedu,
|
||||||
|
qta_man_bufdol,
|
||||||
|
costo_articolo
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
v_new_evt_id,
|
||||||
|
cod_articolo,
|
||||||
|
qta,
|
||||||
|
note,
|
||||||
|
qta_ape,
|
||||||
|
qta_sedu,
|
||||||
|
qta_bufdol,
|
||||||
|
qta_man_ape,
|
||||||
|
qta_man_sedu,
|
||||||
|
qta_man_bufdol,
|
||||||
|
costo_articolo
|
||||||
|
FROM
|
||||||
|
eventi_det_prel
|
||||||
|
WHERE
|
||||||
|
id_evento = id_evento_old;
|
||||||
|
|
||||||
|
-- Risorse
|
||||||
|
INSERT INTO eventi_det_ris (
|
||||||
|
id_evento,
|
||||||
|
id_risorsa,
|
||||||
|
ore_lav,
|
||||||
|
costo,
|
||||||
|
note
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
v_new_evt_id,
|
||||||
|
id_risorsa,
|
||||||
|
ore_lav,
|
||||||
|
costo,
|
||||||
|
note
|
||||||
|
FROM
|
||||||
|
eventi_det_ris
|
||||||
|
WHERE
|
||||||
|
id_evento = id_evento_old;
|
||||||
|
|
||||||
|
-- Costi
|
||||||
|
INSERT INTO eventi_acconti (
|
||||||
|
data,
|
||||||
|
acconto,
|
||||||
|
id_evento,
|
||||||
|
a_conferma,
|
||||||
|
ordine,
|
||||||
|
descrizione
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
data,
|
||||||
|
acconto,
|
||||||
|
v_new_evt_id,
|
||||||
|
a_conferma,
|
||||||
|
ordine,
|
||||||
|
descrizione
|
||||||
|
FROM
|
||||||
|
eventi_acconti
|
||||||
|
WHERE
|
||||||
|
id_evento = id_evento_old;
|
||||||
|
|
||||||
|
-- Altri Costi
|
||||||
|
INSERT INTO eventi_altricosti (
|
||||||
|
id_evento,
|
||||||
|
descrizione,
|
||||||
|
costo,
|
||||||
|
quantity
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
v_new_evt_id,
|
||||||
|
descrizione,
|
||||||
|
costo,
|
||||||
|
quantity
|
||||||
|
FROM
|
||||||
|
eventi_altricosti
|
||||||
|
WHERE
|
||||||
|
id_evento = id_evento_old;
|
||||||
|
|
||||||
|
-- Carico il nuovo id nella pagina
|
||||||
|
id_evento_new := v_new_evt_id;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
DELETE FROM eventi
|
||||||
|
WHERE
|
||||||
|
id = v_new_evt_id;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
raise_application_error(-20001, sqlcode
|
||||||
|
|| ' - '
|
||||||
|
|| sqlerrm);
|
||||||
|
END eventi_copia;```
|
||||||
205
docs/procedures/EVENTI_RICALCOLA_ACCONTI.md
Normal file
205
docs/procedures/EVENTI_RICALCOLA_ACCONTI.md
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
# EVENTI_RICALCOLA_ACCONTI
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
procedure EVENTI_RICALCOLA_ACCONTI(p_event_id number) as
|
||||||
|
v_cnt number;
|
||||||
|
v_calc_only_saldo number := 0;
|
||||||
|
v_totale_tipi number;
|
||||||
|
v_totale_degus number;
|
||||||
|
v_totale_ris number;
|
||||||
|
v_totale_ospiti number;
|
||||||
|
v_totale_evento number;
|
||||||
|
v_totale_altricosti number;
|
||||||
|
v_primo_acconto number := 0;
|
||||||
|
v_secondo_acconto number := 0;
|
||||||
|
v_terzo_acconto number := 0;
|
||||||
|
v_prima_perc number := 0.3;
|
||||||
|
v_seconda_perc number := 0.5;
|
||||||
|
v_terza_perc number := 0.2;
|
||||||
|
begin
|
||||||
|
|
||||||
|
select count(*)
|
||||||
|
into v_cnt
|
||||||
|
from eventi_acconti
|
||||||
|
where id_evento = p_event_id
|
||||||
|
and "DATA" is not null;
|
||||||
|
/*
|
||||||
|
if v_cnt > 0 then
|
||||||
|
raise_application_error(-20001, 'Impossibile ricalcolare gli acconti per un evento già saldato o parzialmente saldato');
|
||||||
|
end if;
|
||||||
|
*/
|
||||||
|
select count(*)
|
||||||
|
into v_cnt
|
||||||
|
from eventi_acconti
|
||||||
|
where id_evento = p_event_id
|
||||||
|
and (ORDINE = 10 OR ORDINE = 20) -- primo acconto (o anche secondo) dato quindi evento confermato
|
||||||
|
and "DATA" is not null;
|
||||||
|
|
||||||
|
if v_cnt > 0 then
|
||||||
|
v_calc_only_saldo := 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select sum(costo_ivato)
|
||||||
|
into v_totale_tipi
|
||||||
|
from get_costo_tipi_evt
|
||||||
|
where id_evento = p_event_id;
|
||||||
|
|
||||||
|
select sum(costo)
|
||||||
|
into v_totale_degus
|
||||||
|
from get_costo_degus_evt
|
||||||
|
where id_evento = p_event_id;
|
||||||
|
|
||||||
|
select sum(costo)
|
||||||
|
into v_totale_ris
|
||||||
|
from get_costo_ris_evt
|
||||||
|
where id_evento = p_event_id;
|
||||||
|
|
||||||
|
select sum(costo+costo*0.10)
|
||||||
|
into v_totale_ospiti
|
||||||
|
from get_costo_ospiti_evt
|
||||||
|
where id_evento = p_event_id;
|
||||||
|
|
||||||
|
select sum((costo * quantity)+(case when costo > 0 then costo * quantity * 0.10 else 0 end))
|
||||||
|
into v_totale_altricosti
|
||||||
|
from eventi_altricosti
|
||||||
|
where id_evento = p_event_id;
|
||||||
|
|
||||||
|
v_totale_evento :=
|
||||||
|
nvl(v_totale_tipi, 0) -
|
||||||
|
nvl(v_totale_degus, 0) +
|
||||||
|
nvl(v_totale_ris, 0) +
|
||||||
|
nvl(v_totale_ospiti, 0) +
|
||||||
|
nvl(v_totale_altricosti, 0);
|
||||||
|
|
||||||
|
if v_calc_only_saldo = 0 then
|
||||||
|
-- Se nessun acconto è stato pagato allora ricalcola tutti gli acconti
|
||||||
|
delete
|
||||||
|
from eventi_acconti
|
||||||
|
where id_evento = p_event_id
|
||||||
|
and ordine in (10, 20, 30);
|
||||||
|
|
||||||
|
insert into eventi_acconti
|
||||||
|
(DESCRIZIONE, ACCONTO, ID_EVENTO, A_CONFERMA, ORDINE)
|
||||||
|
values
|
||||||
|
('PRIMA CAPARRA (art.7 punto A del contratto) a conferma evento nella cifra di euro:',
|
||||||
|
v_totale_evento * v_prima_perc, p_event_id, 1, 10);
|
||||||
|
|
||||||
|
insert into eventi_acconti
|
||||||
|
(DESCRIZIONE, ACCONTO, ID_EVENTO, A_CONFERMA, ORDINE)
|
||||||
|
values
|
||||||
|
('SECONDA CAPARRA (art. 7 punto B - circa 60 giorni prima dell''evento) nella cifra di euro:',
|
||||||
|
v_totale_evento * v_seconda_perc, p_event_id, 0, 20);
|
||||||
|
|
||||||
|
insert into eventi_acconti
|
||||||
|
(DESCRIZIONE, ACCONTO, ID_EVENTO, A_CONFERMA, ORDINE)
|
||||||
|
values
|
||||||
|
('SALDO A RICEVIMENTO CONSUNTIVO (art.7 punto c del contratto) 5 giorni prima dell''evento',
|
||||||
|
v_totale_evento * v_terza_perc, p_event_id, 0, 30);
|
||||||
|
|
||||||
|
else
|
||||||
|
-- Controllo se gli acconti sono stato pagati e in caso ricalcolo soltanto i saldi
|
||||||
|
begin
|
||||||
|
select acconto
|
||||||
|
into v_primo_acconto
|
||||||
|
from eventi_acconti
|
||||||
|
where id_evento = p_event_id
|
||||||
|
and ORDINE = 10
|
||||||
|
and data is not null; -- Il primo acconto è stato pagato
|
||||||
|
exception when no_data_found then
|
||||||
|
v_primo_acconto := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
select acconto
|
||||||
|
into v_secondo_acconto
|
||||||
|
from eventi_acconti
|
||||||
|
where id_evento = p_event_id
|
||||||
|
and ORDINE = 20
|
||||||
|
and data is not null; -- Il secondo acconto è stato pagato
|
||||||
|
exception when no_data_found then
|
||||||
|
v_secondo_acconto := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
select acconto
|
||||||
|
into v_terzo_acconto
|
||||||
|
from eventi_acconti
|
||||||
|
where id_evento = p_event_id
|
||||||
|
and ORDINE = 30
|
||||||
|
and data is not null; -- Il terzo acconto è stato pagato
|
||||||
|
exception when no_data_found then
|
||||||
|
v_terzo_acconto := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
-- Se non hanno pagato il primo acconto lo calcolo in automatico
|
||||||
|
if v_primo_acconto = 0 then
|
||||||
|
v_primo_acconto := v_totale_evento * v_prima_perc;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Ricalcolo la percentuale del secondo acconto in base al primo se non è stato pagato
|
||||||
|
if v_secondo_acconto = 0 then
|
||||||
|
v_secondo_acconto := (v_totale_evento - v_primo_acconto) * (v_seconda_perc/(v_seconda_perc + v_terza_perc));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Calcolo il terzo acconto come la rimanenza tra il totale e il primo + secondo se non è stato pagato
|
||||||
|
if v_terzo_acconto = 0 then
|
||||||
|
v_terzo_acconto := v_totale_evento - (v_primo_acconto + v_secondo_acconto);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Controllo se i totali acconti superano il totale dell'evento
|
||||||
|
if v_primo_acconto > v_totale_evento then
|
||||||
|
raise_application_error(-20001, 'Attenzione! Il primo acconto supera il costo totale del''evento');
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if v_primo_acconto + v_secondo_acconto > v_totale_evento then
|
||||||
|
raise_application_error(-20001, 'Attenzione! Il primo e il secondo acconto superano il costo totale del''evento');
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if v_primo_acconto + v_secondo_acconto + v_terzo_acconto > v_totale_evento then
|
||||||
|
raise_application_error(-20001, 'Attenzione! Gli acconti superano il costo totale del''evento');
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Se gli acconti successivi sono validi allora li aggiorno, se l'acconto precendente salda tutto li elimino
|
||||||
|
if v_secondo_acconto > 0 then
|
||||||
|
update eventi_acconti
|
||||||
|
set ACCONTO = v_secondo_acconto
|
||||||
|
where id_evento = p_event_id
|
||||||
|
and ordine = 20;
|
||||||
|
|
||||||
|
if SQL%ROWCOUNT = 0 then
|
||||||
|
insert into eventi_acconti
|
||||||
|
(DESCRIZIONE, ACCONTO, ID_EVENTO, A_CONFERMA, ORDINE)
|
||||||
|
values
|
||||||
|
('SECONDA CAPARRA (art. 7 punto B - circa 60 giorni prima dell''evento) nella cifra di euro:',
|
||||||
|
v_secondo_acconto, p_event_id, 0, 20);
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
delete
|
||||||
|
from eventi_acconti
|
||||||
|
where id_evento = p_event_id
|
||||||
|
and ordine = 20;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if v_terzo_acconto > 0 then
|
||||||
|
update eventi_acconti
|
||||||
|
set ACCONTO = v_terzo_acconto
|
||||||
|
where id_evento = p_event_id
|
||||||
|
and ordine = 30;
|
||||||
|
|
||||||
|
if SQL%ROWCOUNT = 0 then
|
||||||
|
insert into eventi_acconti
|
||||||
|
(DESCRIZIONE, ACCONTO, ID_EVENTO, A_CONFERMA, ORDINE)
|
||||||
|
values
|
||||||
|
('SALDO A RICEVIMENTO CONSUNTIVO (art.7 punto c del contratto) ', v_terzo_acconto, p_event_id, 0, 30);
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
delete
|
||||||
|
from eventi_acconti
|
||||||
|
where id_evento = p_event_id
|
||||||
|
and ordine = 30;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end if;
|
||||||
|
end;```
|
||||||
12
docs/procedures/EVENTO_ELIMINA_PRELIEVI.md
Normal file
12
docs/procedures/EVENTO_ELIMINA_PRELIEVI.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# EVENTO_ELIMINA_PRELIEVI
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PROCEDURE EVENTO_ELIMINA_PRELIEVI
|
||||||
|
(
|
||||||
|
P_ID_EVENTO IN NUMBER
|
||||||
|
) AS
|
||||||
|
BEGIN
|
||||||
|
NULL;
|
||||||
|
END EVENTO_ELIMINA_PRELIEVI;```
|
||||||
22
docs/procedures/HTPPRN.md
Normal file
22
docs/procedures/HTPPRN.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# HTPPRN
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PROCEDURE "HTPPRN" (pclob in out nocopy clob) is
|
||||||
|
v_excel varchar2(32000);
|
||||||
|
v_clob clob := pclob;
|
||||||
|
begin
|
||||||
|
while length(v_clob) > 0 loop begin
|
||||||
|
if length(v_clob) > 32000 then v_excel:= substr(v_clob,1,32000);
|
||||||
|
htp.prn(v_excel);
|
||||||
|
v_clob:= substr(v_clob,length(v_excel)+1);
|
||||||
|
else
|
||||||
|
v_excel := v_clob;
|
||||||
|
htp.prn(v_excel);
|
||||||
|
v_clob:=''; v_excel := ''; end if;
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
|
||||||
|
```
|
||||||
308
docs/procedures/LISTE_COPIA.md
Normal file
308
docs/procedures/LISTE_COPIA.md
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
# LISTE_COPIA
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PROCEDURE liste_copia (
|
||||||
|
id_evento_from IN NUMBER,
|
||||||
|
id_evento_to IN NUMBER,
|
||||||
|
copia_degustazioni IN NUMBER DEFAULT 0,
|
||||||
|
copia_prelievi IN NUMBER DEFAULT 0,
|
||||||
|
copia_risorse IN NUMBER DEFAULT 0,
|
||||||
|
copia_acconti IN NUMBER DEFAULT 0,
|
||||||
|
copia_altricosti IN NUMBER DEFAULT 0
|
||||||
|
) AS
|
||||||
|
BEGIN
|
||||||
|
-- Validate that mandatory parameters are provided
|
||||||
|
IF id_evento_from IS NULL OR id_evento_to IS NULL THEN
|
||||||
|
RAISE_APPLICATION_ERROR(-20001, 'Both id_evento_from and id_evento_to must be provided.');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- Degustazioni (Tastings)
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
IF copia_degustazioni > 0 THEN
|
||||||
|
FOR rec IN (
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
data,
|
||||||
|
ora,
|
||||||
|
nome,
|
||||||
|
telefono,
|
||||||
|
email,
|
||||||
|
location,
|
||||||
|
n_persone,
|
||||||
|
menu,
|
||||||
|
n_paganti,
|
||||||
|
note,
|
||||||
|
n_degustazione,
|
||||||
|
consumata,
|
||||||
|
costo_degustazione
|
||||||
|
FROM eventi_det_degust
|
||||||
|
WHERE id_evento = id_evento_from
|
||||||
|
) LOOP
|
||||||
|
-- Try to update using the unique key (assumed here as n_degustazione)
|
||||||
|
UPDATE eventi_det_degust
|
||||||
|
SET
|
||||||
|
data = rec.data,
|
||||||
|
ora = rec.ora,
|
||||||
|
nome = rec.nome,
|
||||||
|
telefono = rec.telefono,
|
||||||
|
email = rec.email,
|
||||||
|
location = rec.location,
|
||||||
|
n_persone = rec.n_persone,
|
||||||
|
menu = rec.menu,
|
||||||
|
n_paganti = rec.n_paganti,
|
||||||
|
note = rec.note,
|
||||||
|
consumata = rec.consumata,
|
||||||
|
costo_degustazione = rec.costo_degustazione
|
||||||
|
WHERE id_evento = id_evento_to
|
||||||
|
AND id = rec.id;
|
||||||
|
|
||||||
|
IF SQL%ROWCOUNT = 0 THEN
|
||||||
|
INSERT INTO eventi_det_degust (
|
||||||
|
id_evento,
|
||||||
|
data,
|
||||||
|
ora,
|
||||||
|
nome,
|
||||||
|
telefono,
|
||||||
|
email,
|
||||||
|
location,
|
||||||
|
n_persone,
|
||||||
|
menu,
|
||||||
|
n_paganti,
|
||||||
|
note,
|
||||||
|
n_degustazione,
|
||||||
|
consumata,
|
||||||
|
costo_degustazione
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
id_evento_to,
|
||||||
|
rec.data,
|
||||||
|
rec.ora,
|
||||||
|
rec.nome,
|
||||||
|
rec.telefono,
|
||||||
|
rec.email,
|
||||||
|
rec.location,
|
||||||
|
rec.n_persone,
|
||||||
|
rec.menu,
|
||||||
|
rec.n_paganti,
|
||||||
|
rec.note,
|
||||||
|
rec.n_degustazione,
|
||||||
|
rec.consumata,
|
||||||
|
rec.costo_degustazione
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- Ospiti (Guests)
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
FOR rec IN (
|
||||||
|
SELECT
|
||||||
|
cod_tipo_ospite,
|
||||||
|
numero,
|
||||||
|
note
|
||||||
|
FROM eventi_det_ospiti
|
||||||
|
WHERE id_evento = id_evento_from
|
||||||
|
) LOOP
|
||||||
|
UPDATE eventi_det_ospiti
|
||||||
|
SET
|
||||||
|
numero = rec.numero,
|
||||||
|
note = rec.note
|
||||||
|
WHERE id_evento = id_evento_to
|
||||||
|
AND cod_tipo_ospite = rec.cod_tipo_ospite;
|
||||||
|
|
||||||
|
IF SQL%ROWCOUNT = 0 THEN
|
||||||
|
INSERT INTO eventi_det_ospiti (
|
||||||
|
id_evento,
|
||||||
|
cod_tipo_ospite,
|
||||||
|
numero,
|
||||||
|
note
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
id_evento_to,
|
||||||
|
rec.cod_tipo_ospite,
|
||||||
|
rec.numero,
|
||||||
|
rec.note
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- Prelievi (Sampling): inserisce solo i record mancanti
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
IF copia_prelievi > 0 THEN
|
||||||
|
MERGE INTO eventi_det_prel dest
|
||||||
|
USING (
|
||||||
|
SELECT
|
||||||
|
cod_articolo,
|
||||||
|
qta,
|
||||||
|
note,
|
||||||
|
qta_ape,
|
||||||
|
qta_sedu,
|
||||||
|
qta_bufdol,
|
||||||
|
qta_man_ape,
|
||||||
|
qta_man_sedu,
|
||||||
|
qta_man_bufdol,
|
||||||
|
costo_articolo
|
||||||
|
FROM eventi_det_prel
|
||||||
|
WHERE id_evento = id_evento_from
|
||||||
|
) src
|
||||||
|
ON (
|
||||||
|
dest.id_evento = id_evento_to
|
||||||
|
AND dest.cod_articolo = src.cod_articolo
|
||||||
|
)
|
||||||
|
WHEN NOT MATCHED THEN
|
||||||
|
INSERT (
|
||||||
|
id_evento,
|
||||||
|
cod_articolo,
|
||||||
|
qta,
|
||||||
|
note,
|
||||||
|
qta_ape,
|
||||||
|
qta_sedu,
|
||||||
|
qta_bufdol,
|
||||||
|
qta_man_ape,
|
||||||
|
qta_man_sedu,
|
||||||
|
qta_man_bufdol,
|
||||||
|
costo_articolo
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
id_evento_to,
|
||||||
|
src.cod_articolo,
|
||||||
|
src.qta,
|
||||||
|
src.note,
|
||||||
|
src.qta_ape,
|
||||||
|
src.qta_sedu,
|
||||||
|
src.qta_bufdol,
|
||||||
|
src.qta_man_ape,
|
||||||
|
src.qta_man_sedu,
|
||||||
|
src.qta_man_bufdol,
|
||||||
|
src.costo_articolo
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- Risorse (Resources)
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
IF copia_risorse > 0 THEN
|
||||||
|
FOR rec IN (
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
id_risorsa,
|
||||||
|
ore_lav,
|
||||||
|
costo,
|
||||||
|
note
|
||||||
|
FROM eventi_det_ris
|
||||||
|
WHERE id_evento = id_evento_from
|
||||||
|
) LOOP
|
||||||
|
UPDATE eventi_det_ris
|
||||||
|
SET
|
||||||
|
ore_lav = rec.ore_lav,
|
||||||
|
costo = rec.costo,
|
||||||
|
note = rec.note
|
||||||
|
WHERE id_evento = id_evento_to
|
||||||
|
AND id = rec.id;
|
||||||
|
|
||||||
|
IF SQL%ROWCOUNT = 0 THEN
|
||||||
|
INSERT INTO eventi_det_ris (
|
||||||
|
id_evento,
|
||||||
|
id_risorsa,
|
||||||
|
ore_lav,
|
||||||
|
costo,
|
||||||
|
note
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
id_evento_to,
|
||||||
|
rec.id_risorsa,
|
||||||
|
rec.ore_lav,
|
||||||
|
rec.costo,
|
||||||
|
rec.note
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- Acconti (Payments)
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
IF copia_acconti > 0 THEN
|
||||||
|
FOR rec IN (
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
data,
|
||||||
|
acconto,
|
||||||
|
a_conferma,
|
||||||
|
ordine,
|
||||||
|
descrizione
|
||||||
|
FROM eventi_acconti
|
||||||
|
WHERE id_evento = id_evento_from
|
||||||
|
) LOOP
|
||||||
|
UPDATE eventi_acconti
|
||||||
|
SET
|
||||||
|
data = rec.data,
|
||||||
|
acconto = rec.acconto,
|
||||||
|
a_conferma = rec.a_conferma,
|
||||||
|
descrizione = rec.descrizione
|
||||||
|
WHERE id_evento = id_evento_to
|
||||||
|
AND id = rec.id;
|
||||||
|
|
||||||
|
IF SQL%ROWCOUNT = 0 THEN
|
||||||
|
INSERT INTO eventi_acconti (
|
||||||
|
data,
|
||||||
|
acconto,
|
||||||
|
id_evento,
|
||||||
|
a_conferma,
|
||||||
|
ordine,
|
||||||
|
descrizione
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
rec.data,
|
||||||
|
rec.acconto,
|
||||||
|
id_evento_to,
|
||||||
|
rec.a_conferma,
|
||||||
|
rec.ordine,
|
||||||
|
rec.descrizione
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- Altri Costi (Other Costs)
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
IF copia_altricosti > 0 THEN
|
||||||
|
FOR rec IN (
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
descrizione,
|
||||||
|
costo,
|
||||||
|
quantity
|
||||||
|
FROM eventi_altricosti
|
||||||
|
WHERE id_evento = id_evento_from
|
||||||
|
) LOOP
|
||||||
|
UPDATE eventi_altricosti
|
||||||
|
SET
|
||||||
|
costo = rec.costo,
|
||||||
|
quantity = rec.quantity
|
||||||
|
WHERE id_evento = id_evento_to
|
||||||
|
AND id = rec.id;
|
||||||
|
|
||||||
|
IF SQL%ROWCOUNT = 0 THEN
|
||||||
|
INSERT INTO eventi_altricosti (
|
||||||
|
id_evento,
|
||||||
|
descrizione,
|
||||||
|
costo,
|
||||||
|
quantity
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
id_evento_to,
|
||||||
|
rec.descrizione,
|
||||||
|
rec.costo,
|
||||||
|
rec.quantity
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
END IF;
|
||||||
|
END liste_copia;```
|
||||||
41
docs/procedures/P_CANCEL_SAME_LOCATION_EVENTS.md
Normal file
41
docs/procedures/P_CANCEL_SAME_LOCATION_EVENTS.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# P_CANCEL_SAME_LOCATION_EVENTS
|
||||||
|
|
||||||
|
## Codice Sorgente
|
||||||
|
|
||||||
|
```sql
|
||||||
|
PROCEDURE "P_CANCEL_SAME_LOCATION_EVENTS" (p_good_event_id number) as
|
||||||
|
-- ---------------------------
|
||||||
|
-- Autore: Daniele Viti
|
||||||
|
-- Data: 17/01/2020
|
||||||
|
-- Descrizione: Controlla che ci siano più eventi con la stessa locazione e data di quello in esame e li annulla
|
||||||
|
-- ---------------------------
|
||||||
|
v_date date;
|
||||||
|
v_idloc number;
|
||||||
|
begin
|
||||||
|
|
||||||
|
begin
|
||||||
|
-- Seleziono la data e la location per confrontarle dopo
|
||||||
|
select data, id_location
|
||||||
|
into v_date, v_idloc
|
||||||
|
from eventi
|
||||||
|
where id = p_good_event_id;
|
||||||
|
exception when no_data_found then
|
||||||
|
raise_application_error(-20001, 'Impossibile trovare l''evento da confermare');
|
||||||
|
end;
|
||||||
|
|
||||||
|
for c in (
|
||||||
|
select *
|
||||||
|
from eventi
|
||||||
|
where data = v_date
|
||||||
|
and id_location = v_idloc
|
||||||
|
and id != p_good_event_id
|
||||||
|
) loop
|
||||||
|
-- Imposta l'evento come obsoleto (annullato)
|
||||||
|
UPDATE EVENTI
|
||||||
|
SET
|
||||||
|
FLG_SUPERATO = 1,
|
||||||
|
STATO = 900
|
||||||
|
WHERE ID = c.id;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
end;```
|
||||||
90
docs/procedures/README.md
Normal file
90
docs/procedures/README.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# Stored Procedures
|
||||||
|
|
||||||
|
Questa cartella contiene la documentazione di tutte le 11 stored procedures del database.
|
||||||
|
|
||||||
|
## Procedures Business Logic
|
||||||
|
|
||||||
|
| Procedura | Descrizione |
|
||||||
|
|-----------|-------------|
|
||||||
|
| [EVENTI_AGGIORNA_QTA_LISTA](EVENTI_AGGIORNA_QTA_LISTA.md) | Ricalcola tutte le quantità della lista prelievo |
|
||||||
|
| [EVENTI_AGGIORNA_TOT_OSPITI](EVENTI_AGGIORNA_TOT_OSPITI.md) | Aggiorna il totale ospiti in testata evento |
|
||||||
|
| [EVENTI_COPIA](EVENTI_COPIA.md) | Duplica un evento con tutti i dettagli |
|
||||||
|
| [EVENTI_RICALCOLA_ACCONTI](EVENTI_RICALCOLA_ACCONTI.md) | Ricalcola gli importi degli acconti |
|
||||||
|
| [EVENTO_ELIMINA_PRELIEVI](EVENTO_ELIMINA_PRELIEVI.md) | Elimina i prelievi di un evento |
|
||||||
|
| [LISTE_COPIA](LISTE_COPIA.md) | Copia selettiva di liste tra due eventi |
|
||||||
|
| [P_CANCEL_SAME_LOCATION_EVENTS](P_CANCEL_SAME_LOCATION_EVENTS.md) | Annulla eventi nella stessa location/data |
|
||||||
|
|
||||||
|
## Procedures Utility
|
||||||
|
|
||||||
|
| Procedura | Descrizione |
|
||||||
|
|-----------|-------------|
|
||||||
|
| [ROWSORT_TIPI](ROWSORT_TIPI.md) | Riordina i tipi materiale |
|
||||||
|
| [HTPPRN](HTPPRN.md) | Output HTTP per APEX |
|
||||||
|
| [SEND_DATA_TO_DROPBOX](SEND_DATA_TO_DROPBOX.md) | Export dati verso Dropbox |
|
||||||
|
| [XLOG](XLOG.md) | Procedura di logging |
|
||||||
|
|
||||||
|
## Dettaglio Procedures Critiche
|
||||||
|
|
||||||
|
### EVENTI_AGGIORNA_QTA_LISTA
|
||||||
|
|
||||||
|
**Parametri:**
|
||||||
|
- `p_id_evento NUMBER` - ID dell'evento
|
||||||
|
|
||||||
|
**Logica:**
|
||||||
|
1. Cicla su tutti gli articoli nella lista prelievo
|
||||||
|
2. Per ogni articolo determina il metodo di calcolo:
|
||||||
|
- **Quantità Standard**: Se `QTA_STD_A/S/B` sono valorizzate
|
||||||
|
- **Tovagliato/Caraffe**: Moltiplica per quantità tavoli/angoli
|
||||||
|
- **Codice Relativo**: Moltiplica per quantità articolo di riferimento
|
||||||
|
- **Standard**: Moltiplica coefficienti per totale ospiti
|
||||||
|
3. Verifica disponibilità rispetto alla giacenza
|
||||||
|
4. Aggiorna note con warning se quantità insufficiente
|
||||||
|
|
||||||
|
### EVENTI_COPIA
|
||||||
|
|
||||||
|
**Parametri:**
|
||||||
|
- `id_evento_old NUMBER` - ID evento da copiare
|
||||||
|
- `nuova_versione NUMBER DEFAULT 0` - 1 per creare nuova versione
|
||||||
|
- `id_evento_new OUT NUMBER` - ID nuovo evento creato
|
||||||
|
|
||||||
|
**Logica:**
|
||||||
|
1. Copia testata evento
|
||||||
|
2. Se nuova versione: imposta `ID_EVT_PADRE`, incrementa `VERS_NUMBER`
|
||||||
|
3. Aggiorna evento vecchio con `ID_EVT_FIGLIO`
|
||||||
|
4. Copia tutte le tabelle dettaglio:
|
||||||
|
- `EVENTI_DET_DEGUST`
|
||||||
|
- `EVENTI_DET_OSPITI` (via UPDATE, non INSERT)
|
||||||
|
- `EVENTI_DET_PREL`
|
||||||
|
- `EVENTI_DET_RIS`
|
||||||
|
- `EVENTI_ACCONTI`
|
||||||
|
- `EVENTI_ALTRICOSTI`
|
||||||
|
5. In caso di errore: elimina evento creato e solleva eccezione
|
||||||
|
|
||||||
|
### EVENTI_RICALCOLA_ACCONTI
|
||||||
|
|
||||||
|
**Parametri:**
|
||||||
|
- `p_event_id NUMBER` - ID evento
|
||||||
|
|
||||||
|
**Logica:**
|
||||||
|
1. Calcola totale evento dalle viste costo
|
||||||
|
2. Se nessun acconto pagato:
|
||||||
|
- Elimina acconti esistenti
|
||||||
|
- Inserisce nuovi acconti con percentuali 30%-50%-20%
|
||||||
|
3. Se acconti parzialmente pagati:
|
||||||
|
- Mantiene importi pagati
|
||||||
|
- Ricalcola solo acconti non pagati
|
||||||
|
- Verifica che totale acconti ≤ totale evento
|
||||||
|
|
||||||
|
### LISTE_COPIA
|
||||||
|
|
||||||
|
**Parametri:**
|
||||||
|
- `id_evento_from NUMBER` - Evento sorgente
|
||||||
|
- `id_evento_to NUMBER` - Evento destinazione
|
||||||
|
- `copia_degustazioni NUMBER DEFAULT 0`
|
||||||
|
- `copia_prelievi NUMBER DEFAULT 0`
|
||||||
|
- `copia_risorse NUMBER DEFAULT 0`
|
||||||
|
- `copia_acconti NUMBER DEFAULT 0`
|
||||||
|
- `copia_altricosti NUMBER DEFAULT 0`
|
||||||
|
|
||||||
|
**Logica:**
|
||||||
|
Per ogni flag > 0 esegue un MERGE (UPDATE se esiste, INSERT altrimenti).
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user