Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docker/openboxes.client-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,17 @@ openboxes:
# siteKey: CHANGE_ME
# secretKey: CHANGE_ME

# -------------------------------------------------------------------------
# Custom: damaged stock adjustments
# Default (key absent): user-initiated damaged adjustments are enabled.
# Set to false to disable the Adjust Stock / Create Damaged Transaction paths
# and require the transfer-to-Damaged-bin workflow instead.
# -------------------------------------------------------------------------
# custom:
# adjustments:
# damaged:
# enabled: false

# -------------------------------------------------------------------------
# LDAP (optional β€” enable only for clients using corporate auth)
# -------------------------------------------------------------------------
Expand Down
5 changes: 5 additions & 0 deletions docker/openboxes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ openboxes:
expirationDate:
minValue: "01/01/2026"

custom:
adjustments:
damaged:
enabled: false

jobs:
sendStockAlertsJob:
enabled: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.pih.warehouse.core.ReasonCode
class ReasonCodeApiController {

def locationService
def customReasonCodeService
def messageSource
def localizationService

Expand All @@ -30,7 +31,7 @@ class ReasonCodeApiController {
} else if (ActivityCode.MODIFY_REQUISITION_ITEM in activityCodes) {
reasonCodes.addAll(getReasonCodes(ReasonCode.listRequisitionQuantityChangeReasonCodes()))
} else if (ActivityCode.ADJUST_INVENTORY in activityCodes) {
reasonCodes.addAll(getReasonCodes(ReasonCode.listInventoryAdjustmentReasonCodes()))
reasonCodes.addAll(getReasonCodes(customReasonCodeService.listInventoryAdjustmentReasonCodes()))
} else if (ActivityCode.CYCLE_COUNT in activityCodes) {
reasonCodes.addAll(getReasonCodes(ReasonCode.listCycleCountReasonCodes()))
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.pih.warehouse.custom.damagedAdjustments

class DamagedAdjustmentInterceptor {

def customReasonCodeService

// Runs early (before RoleInterceptor) β€” no session state dependency.
int order = HIGHEST_PRECEDENCE + 1

DamagedAdjustmentInterceptor() {
match(controller: 'inventory', action: 'createDamaged')
}

boolean before() {
if (!customReasonCodeService.damagedEnabled) {
log.warn "Damaged adjustment blocked for user=${session.user?.username} (openboxes.custom.adjustments.damaged.enabled=false)"
redirect(controller: 'errors', action: 'handleForbidden')
return false
}
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.pih.warehouse.custom.damagedAdjustments

import org.pih.warehouse.core.ReasonCode

class CustomReasonCodeService {

static transactional = false

def grailsApplication

// Absent config = enabled; only literal `false` opts out.
boolean isDamagedEnabled() {
return grailsApplication.config.openboxes.custom.adjustments.damaged.enabled != false
}

List<ReasonCode> listInventoryAdjustmentReasonCodes() {
List<ReasonCode> base = ReasonCode.listInventoryAdjustmentReasonCodes()
return damagedEnabled ? base : base.findAll { it != ReasonCode.DAMAGED }
}
}
6 changes: 5 additions & 1 deletion grails-app/taglib/org/pih/warehouse/SelectTagLib.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class SelectTagLib {
def shipmentService
def requisitionService
def organizationService
def customReasonCodeService
CategoryService categoryService

/**
Expand Down Expand Up @@ -227,7 +228,7 @@ class SelectTagLib {
}

def selectInventoryAdjustmentReasonCode = { attrs, body ->
attrs.from = ReasonCode.listInventoryAdjustmentReasonCodes()
attrs.from = customReasonCodeService.listInventoryAdjustmentReasonCodes()
attrs.optionValue = { format.metadata(obj: it) }
out << g.select(attrs)
}
Expand Down Expand Up @@ -670,6 +671,9 @@ class SelectTagLib {
disabledTransactionTypes = transactionTypes.findAll { it.id in disabledTransactionTypes }
transactionTypes.removeAll(disabledTransactionTypes)
}
if (!customReasonCodeService.damagedEnabled) {
transactionTypes.removeAll { it.id == Constants.DAMAGE_TRANSACTION_TYPE_ID }
}

attrs.from = transactionTypes
attrs.optionKey = 'id'
Expand Down
3 changes: 1 addition & 2 deletions grails-app/views/inventoryItem/_adjustStock.gsp
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,8 @@
<tr class="prop">
<td valign="top" class="name"><label><warehouse:message code="default.reasonCode.label" default="Reason Code"/></label></td>
<td valign="top" class="">
<g:select name="reasonCode"
<g:selectInventoryAdjustmentReasonCode name="reasonCode"
value="${params.reasonCode}"
from="${org.pih.warehouse.core.ReasonCode.listInventoryAdjustmentReasonCodes()}"
noSelection="['':'']"
data-placeholder="${g.message(code: 'default.selectAnOption.label', default: 'Select an Option')}"
class="chzn-select-deselect"/>
Expand Down
2 changes: 2 additions & 0 deletions grails-app/views/product/_actions.gsp
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,14 @@
<warehouse:message code="inventory.inventoryExpired.label" />
</g:link>
</div>
<g:if test="${grailsApplication.config.openboxes.custom.adjustments.damaged.enabled != false}">
<div class="action-menu-item">
<g:link controller="inventory" action="createDamaged" params="['product.id':productInstance?.id]">
<img src="${resource(dir:'images/icons/silk',file:'package_delete.png')}"/>&nbsp;
<warehouse:message code="inventory.inventoryDamaged.label" />
</g:link>
</div>
</g:if>
<div class="action-menu-item">
<hr />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-21
Loading