Configuration Defaults
OpenBoxes uses a configuration file grails-app/conf/application.yml
(formerly, Config.groovy)
to manage application settings. The application.yml
file uses a YAML format, which is
hierarchical and structured by indentation. The configuration properties within this file include
database connections, server settings, environment-specific configurations, and more.
For more general information about how Grails configuration works, refer to the official Grails documentation.
Default Configuration File¶
To review our default configuration file, refer to the snippet below. We will document the most relevant configuration properties in the documentation in the following sections.
Note
This is the latest development version, so might contain properties that are not yet available in the latest release. If the contents did not load properly, you can access the file directly in our GitHub repository here: application.yml
# Copyright (c) 2012 Partners In Health. All rights reserved.
# The use and distribution terms for this software are covered by the
# Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
# which can be found in the file epl-v10.html at the root of this distribution.
# By using this software in any fashion, you are agreeing to be bound by
# the terms of this license.
# You must not remove this notice, or any other, from this software.
---
grails:
profile: react-webpack
codegen:
defaultPackage: org
dbconsole:
enabled: true
gorm:
reactor:
# Whether to translate GORM events into Reactor events
# Disabled by default for performance reasons
events: false
failOnError: false
config:
locations:
#
# The first config file has the lowest priority. Its contents can
# be overwritten by any file following it that sets the same config
# key. The *last* config file has the final word (highest priority).
#
- classpath:META-INF/grails.build.info
- file:${catalina.base}/.grails/openboxes-config.properties
- file:${catalina.base}/.grails/openboxes-config.groovy
- file:${catalina.base}/.grails/openboxes.yml
- ~/.grails/openboxes-config.properties
- ~/.grails/openboxes-config.groovy
- ~/.grails/openboxes.yml
plugin:
console:
enabled: true # https://github.com/sheehan/grails-console#security
# Grails Liquibase database migration support. https://grails.github.io/grails-database-migration/latest/
# Automatic migrations are disabled by default. We run them manually in BootStrap.groovy
databasemigration:
changelogFileName: changelog.groovy
info:
app:
name: '@info.app.name@'
version: '@info.app.version@'
grailsVersion: '@info.app.grailsVersion@'
spring:
main:
banner-mode: "off"
groovy:
template:
check-template-location: false
quartz:
pluginEnabled: true
jdbcStore: false
autoStartup: false
monitor:
layout: custom
showTriggerNames: true
showCountdown: true
showTickingCloud: true
# Spring Actuator Endpoints are Disabled by Default
endpoints:
enabled: true
jmx:
enabled: true
management:
info:
git:
mode: full
server:
contextPath: "/openboxes"
session:
# The time (in seconds) of inactivity before we invalidate the user's session. (7200 is two hours.)
# For future reference, this setting has been renamed to "server.servlet.session.timeout" in SpringBoot 2+
timeout: 7200
---
grails:
#
# From the asset-pipeline manual: "If you want settings to apply to
# both development runtime and build time the properties have to be
# duplicated in your application's application.yml [and build.gradle]."
#
# http://www.asset-pipeline.com/manual/index.html#configuration
# http://www.asset-pipeline.com/manual/index.html#configuration-2
#
# Every field except `bundle` should also be set in build.gradle.
#
# Because we use webpack to bundle .css and .js files, most of
# asset-pipeline's advanced features are unnecessary.
#
assets:
bundle: false
developmentRuntime: false
enableDigests: false
enableGzip: false
enableSourceMaps: false
maxThreads: 1
minifyCss: false
minifyJs: false
skipNonDigests: false
cache:
clearAtStartup: true
doc:
title: "OpenBoxes"
subtitle: ""
authors: "Justin Miranda"
license: "Eclipse Public License - Version 1.0"
copyright: ""
footer: ""
mail:
enabled: false
from: "info@openboxes.com"
prefix: "[OpenBoxes]"
host: "localhost"
port: "25"
# Authentication disabled by default
username: null
password: null
# Disable debug mode by default
debug: false
mime:
disable:
accept:
header:
userAgents:
- Gecko
- WebKit
- Presto
- Trident
types:
all: '*/*'
atom: application/atom+xml
css: text/css
csv: text/csv
form: application/x-www-form-urlencoded
html:
- text/html
- application/xhtml+xml
js: text/javascript
json:
- application/json
- text/json
multipartForm: multipart/form-data
pdf: application/pdf
rss: application/rss+xml
text: text/plain
hal:
- application/hal+json
- application/hal+xml
xml:
- text/xml
- application/xml
file:
extensions: true
use:
accept:
header: false
resources:
#
# Set Cache-Control on non-asset-pipeline-managed static assets.
# See https://gsp.grails.org/latest/guide/resources.html
#
cachePeriod: 86400
urlmapping:
cache:
maxsize: 1000
controllers:
upload:
maxFileSize: 2097152
maxRequestSize: 2097152
defaultScope: singleton
converters:
encoding: UTF-8
views:
default:
codec: 'html'
enable:
jsessionid: false
gsp:
encoding: UTF-8
htmlcodec: xml
codecs:
expression: html
scriptlets: html
taglib: none
staticparts: none
sitemesh:
preprocess: true
javascript:
library: jquery
databinding:
# The formats that Grails will attempt to use when binding input Strings to java.util.Date fields.
# We now use the java.time classes instead (ex: Instant, LocalDate). Those fields define their own
# ValueConverter classes and so don't use the formats defined here.
dateFormats:
# Old date formats, don't use going forward! Kept first in the list to maintain backwards compatability.
- 'MM/dd/yyyy HH:mm:ss XXX'
- 'MM/dd/yyyy HH:mm:ss XX'
- 'MM/dd/yyyy HH:mm:ss X'
- 'MM/dd/yyyy HH:mm XXX'
- 'MM/dd/yyyy HH:mm XX'
- 'MM/dd/yyyy HH:mm X'
# Note that if this format is given, Grails will treat it as midnight in the local server timezone, which
# is ahead of UTC, can cause the date to actually be the next day. It can also cause inconsistencies across
# hosts/environments if they're configured for different local timezones. Avoid this format going forward!
- 'MM/dd/yyyy'
# ISO-8601 formats. These are better than the old formats, but new APIs should still use Instant instead
# of Date whenever possible. Note that a format without time and timezone is NOT allowed here because that
# would be ambiguous and would lead to Date conversion weirdness. If you need a date only, use LocalDate.
- "yyyy-MM-dd'T'HH:mm:ssXXX"
- "yyyy-MM-dd'T'HH:mm:ssXX"
- "yyyy-MM-dd'T'HH:mm:ssX"
- "yyyy-MM-dd'T'HH:mmXXX"
- "yyyy-MM-dd'T'HH:mmXX"
- "yyyy-MM-dd'T'HH:mmX"
convertEmptyStringsToNull: false
endpoints:
jmx:
unique-names: true
org.eclipse.jetty.util.log.class: org.eclipse.jetty.util.log.Slf4jLog
org.jboss.logging.provider: slf4j
server.tomcat.accesslog.enabled: true
slf4j.detectLoggerNameMismatch: true
---
hibernate:
show_sql: false # Logs Hibernate queries to the console. We configure this via Logback instead.
format_sql: false
allow_update_outside_transaction: false
cache:
queries: false
provider_class: org.hibernate.cache.EhCacheProvider
region:
factory_class: org.hibernate.cache.ehcache.EhCacheRegionFactory
use_query_cache: false
use_second_level_cache: false
dataSource:
pooled: true
jmxExport: true
driverClassName: com.mysql.cj.jdbc.Driver
dbCreate: none
dialect: org.hibernate.dialect.MySQL57InnoDBDialect
factory: org.apache.tomcat.jdbc.pool.DataSourceFactory
type: org.apache.tomcat.jdbc.pool.DataSource
# Settings for database logging
logger: com.mysql.cj.jdbc.log.StandardLogger
dumpQueriesOnException: false
logSql: false # Logs SQL queries to the console. We configure this via Logback instead.
formatSql: false
logSlowQueries: false
includeInnodbStatusInDeadlockExceptions: true
properties:
# from https://docs.grails.org/3.3.16/guide/conf.html#dataSource
jmxEnabled: true
initialSize: 5
maxActive: 50
minIdle: 5
maxIdle: 25
maxWait: 10000
maxAge: 10 * 60000
timeBetweenEvictionRunsMillis: 5000
minEvictableIdleTimeMillis: 60000
validationQuery: SELECT 1
validationQueryTimeout: 3
validationInterval: 15000
testOnBorrow: false
testWhileIdle: true
testOnReturn: false
# https://tomcat.apache.org/tomcat-8.5-doc/jdbc-pool.html#JDBC_interceptors
jdbcInterceptors: "ConnectionState;StatementCache(max=200)"
defaultTransactionIsolation: java.sql.Connection.TRANSACTION_READ_COMMITTED
environments:
development:
dataSource:
dumpQueriesOnException: true
logAbandoned: true
logSlowQueries: true
username: "openboxes"
password: "openboxes"
url: jdbc:mysql://localhost:3306/openboxes?serverTimezone=UTC&useSSL=false
test:
dataSource:
dumpQueriesOnException: true
logAbandoned: true
# Our integration tests run against a containerized database: https://java.testcontainers.org/modules/databases/jdbc/.
# Note that testcontainers auto-disable SSL when connecting via jdbc: https://github.com/testcontainers/testcontainers-java/pull/561
# For more information, see /src/integration-test/README.md
url: jdbc:tc:${TEST_DATABASE:mysql:5.7.44}:///openboxes?TC_MY_CNF=testcontainers
driverClassName: org.testcontainers.jdbc.ContainerDatabaseDriver
grails:
plugin:
databasemigration:
changelogFileName: changelog-test.xml
changelogLocation: src/integration-test/resources/migrations
production:
dataSource:
username: "openboxes"
password: "openboxes"
url: jdbc:mysql://localhost:3306/openboxes?serverTimezone=UTC&useSSL=false
---
openboxes:
ajaxRequest:
timeout: 120000
dashboard:
yearTypes:
fiscalYear:
start: "07/01" # format: MM/DD, For PIH and the Govt of Dominica fiscal year start July 1
end: "06/30" # format: MM/DD
labelYearPrefix: "FY "
yearFormat: "yy"
calendarYear:
start: "01/01"
end: "12/31"
labelYearPrefix: ""
yearFormat: "yyyy"
order:
orderStatusPropertyMap:
PLACED: ["productCode", "sourceName", "supplierCode", "manufacturer", "manufacturerCode", "quantity", "unitPrice", "unitOfMeasure", "budgetCode"]
purchaseOrder:
editableProperties:
status: "PLACED"
deny: ["productCode", "sourceName", "supplierCode", "manufacturer", "manufacturerCode", "quantity", "unitOfMeasure"]
# OpenBoxes default line printer port
linePrinterTerminal:
port: "LPT1"
# OpenBoxes default uploads directory location
uploads:
location: "uploads"
# Fullstory integration
fullstory:
enabled: false
debug: false
host: "fullstory.com"
org: ""
namespace: "FS"
# Hotjar integration
hotjar:
enabled: false
hjid: 0
hjsv: 6
# Forecasting feature
forecasting:
enabled: true
demandPeriod: 365
# Bill of Materials feature
bom:
enabled: false
# User signup
signup:
enabled: true
recaptcha:
enabled: false
v2:
siteKey: ""
secretKey: ""
additionalQuestions:
enabled: false
# UserVoice widget
uservoice:
widget:
enabled: false
position: "right"
# Zopim widget
zopim:
widget:
enabled: false
url: "//v2.zopim.com/?2T7RMi7ERqr3s8N20KQ3wOBRudcwosBA"
# HelpScout beacon
helpscout:
widget:
color: "#3AB4B1"
enabled: true
key: "44ee4f01-5334-4b93-ad25-03037903eb80"
# JIRA Issue Collector
jira:
issue:
collector:
enabled: false
url: "https://openboxes.atlassian.net/s/d41d8cd98f00b204e9800998ecf8427e/en_USgc5zl3-1988229788/6318/12/1.4.10/_/download/batch/com.atlassian.jira.collector.plugin.jira-issue-collector-plugin:issuecollector/com.atlassian.jira.collector.plugin.jira-issue-collector-plugin:issuecollector.js?collectorId=fb813fdb"
# OpenBoxes Feedback
mail:
feedback:
enabled: false
recipients: ["feedback@openboxes.com"]
# OpenBoxes Error Emails (bug reports)
errors:
enabled: true
recipients: ["errors@openboxes.com"]
# Barcode scanner (disabled by default)
scannerDetection:
enabled: false
barcode:
printer:
# Print barcode labels via USB
name: "printer-thermalprinter"
# Print barcode labels via RAW
ipAddress: "127.0.0.1"
port: 9100
# Default delay and min length for typeahead components
typeahead:
delay: 300
minLength: 3
refreshAnalyticsDataOnStartup:
enabled: true
jobs:
# Send stock alerts
sendStockAlertsJob:
enabled: true
skipOnEmpty: true
daysUntilExpiry: 60
cronExpression: "0 0 0 * * ?" # every day at midnight
# Refresh inventory snapshots (triggered manually)
refreshInventorySnapshotJob:
enabled: true
retryOnError: false
maxRetryAttempts: 3
# Refresh inventory snapshots after transaction (only for transaction entries)
refreshInventorySnapshotAfterTransactionJob:
enabled: true
retryOnError: false
maxRetryAttempts: 3
# Refresh order summary snapshots
refreshOrderSummaryJob:
enabled: true
cronExpression: "0 0 2 * * ?" # at 02:00:00am every day
# Refresh product availability materialized view
refreshProductAvailabilityJob:
enabled: true
cronExpression: "0 0 0/2 * * ?" # every two hours
delayStart: true
delayInMilliseconds: 5000
# Refresh transaction fact table
refreshTransactionFactJob:
enabled: true
cronExpression: "0 0 0 * * ?" # every day at midnight
# Refresh stockout data for yesterday
refreshStockoutDataJob:
enabled: true
cronExpression: "0 0 1 * * ?" # at 01:00:00am every day
# Refresh demand fact table
refreshDemandDataJob:
enabled: true
cronExpression: "0 0 1 * * ?" # at 01:00:00am every day
# Assign identifier job
assignIdentifierJob:
enabled: true
cronExpression: "0 * * * * ?" # every minute
# Calculate historical quantity on hand
calculateHistoricalQuantityJob:
enabled: false
cronExpression: "0 0 0 * * ?" # every day at midnight
daysToProcess: 540 # 18 months
# Data Cleaning Job
dataCleaningJob:
enabled: true
cronExpression: "0 */5 * * * ?" # every five minutes
# Data Migration Job (enabled, but needs to be triggered manually)
dataMigrationJob:
enabled: true
updateExchangeRatesJob:
enabled: false
cronExpression: "0 0 * * * ?" # every hour
# LDAP configuration
ldap:
enabled: false
context:
managerDn: "cn=read-only-admin,dc=example,dc=com"
managerPassword: "password"
server:
host: "ldap.forumsys.com"
port: 389
# LDAP Search
search:
base: "dc=example,dc=com"
filter: "(uid={0})"
searchSubtree: true
attributesToReturn: ['mail', 'givenName']
# Stock Card > Consumption > Reason codes
# Examples: Stock out, Low stock, Expired, Damaged, Could not locate, Insufficient quantity reconditioned
stockCard:
consumption:
stockout: &stockout 1
low_stock: &low_stock 2
expired: &expired 3
damaged: &damaged 4
could_not_locate: &could_not_locate 14
insufficient_quantity_reconditioned: &insufficient_quantity_reconditioned 19
reasonCodes: [*stockout, *low_stock, *expired, *damaged, *could_not_locate, *insufficient_quantity_reconditioned]
# Localization configuration - default and supported locales
locale:
custom:
enabled: false
defaultLocale: 'en'
localizationModeLocale: 'ach'
supportedLocales: ['ar', 'ach', 'de', 'en', 'es', 'es_MX', 'fr', 'ht', 'it', 'pt', 'fi', 'zh']
# Currency configuration
defaultCurrencyCode: "USD"
defaultCurrencySymbol: '\$'
supportedCurrencyCodes: ["USD", "CAD", "EUR", "GBP"]
currencyApi:
url: "https://api.exchangeratesapi.io/latest?base=%s"
apiKey: ""
password: ""
translationApi:
uri: "https://translate.yandex.net/api/v1.5/tr.json/translate?key=%s&text=%s&lang=%s&format=%s"
apiKey: ""
format: "plain"
# Accounting (Budget Code, GL Account)
accounting:
enabled: true
# Inventory snapshot configuration
inventorySnapshot:
batchSize: 100
# Allow users to customize logo image url as well as label
logo:
url: "/assets/openboxes_logo_40x40.jpg"
label: ""
report:
logo:
url: "https://openboxes.com/img/logo_100.png"
# Allow system to anonymize user data to prevent it from being accessed by unauthorized users
anonymize:
enabled: false
generateName:
separator: " - "
# Disable feature during development
shipping:
search:
maxResults: 1000
# Automatically create temporary receiving locations for shipments
receiving:
createReceivingLocation:
enabled: true
receivingLocation:
prefix: "R"
# Indicates which activities are required for a location to allow logins
chooseLocation:
requiredActivities: ["MANAGE_INVENTORY"]
expirationDate:
minValue: "01/01/2000"
cycleCount:
additionalColumns: {}
api:
pagination:
enabled: true
pageSize: 10
mail:
error:
enabled: false
debug: false
to: 'errors@openboxes.com'
server: "localhost"
port: "25"
from: "info@openboxes.com"
username: null
password: null
prefix: "[OpenBoxes]"
uiperformance:
enabled: false
# TODO OBGM 1: Compare the loggers in log4j = { } to make sure they exist in logback.groovy
# TODO OBGM 2: Add grails-cache plugin config if will be needed (See OBGM-71)
# TODO OBGM 3: Investigate if Joda-Time plugin is still needed
# TODO OBGM 4: Add resources plugin config if will be needed
grails:
# request parameters to mask when logging exceptions
exceptionresolver:
params:
exclude:
- 'password'
- 'passwordConfirm'
# enabled native2ascii conversion of i18n properties files
enable:
native2ascii: true
# whether to install the java.util.logging bridge for sl4j. Disable fo AppEngine!
logging:
jul:
usebridge: true
sentry:
# TODO: For some reason adding the "sentry-spring-boot-starter" dependency causes:
# - java.lang.IllegalStateException: Error processing condition on io.sentry.spring.boot.SentryAutoConfiguration$HubConfiguration$SentryWebMvcConfiguration.transactionNameProvider
# - Caused by: java.lang.reflect.MalformedParameterizedTypeException: null
# https://github.com/getsentry/sentry-java/blob/6.34.0/sentry-spring-boot/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java#L268-L272
# Find a way to bypass this auto-configuration or provide a default implementation of transactionNameProvider.
# Possibly related to: https://github.com/getsentry/sentry-java/issues/1863
# Until this is resolved, all sentry related properties must be defined in sentry.properties.
dsn: ${SENTRY_DSN_BACKEND:${SENTRY_DSN:""}}
# A custom setting that defines the format of Sentry HTTP transaction names
httpTransactionNameFormat: CONTROLLER_METHOD
# Application-level logger config. See logback.xml for Logback-specific configuration.
logging:
# How the logs are formatted. See https://logback.qos.ch/manual/layouts.html for config options.
pattern:
console: "%date{ISO8601} %-5level [%thread] %logger{40}: %message%n%xException"
level:
root: INFO