Index: trunk/grails-app/conf/Config.groovy
===================================================================
--- trunk/grails-app/conf/Config.groovy	(revision 632)
+++ trunk/grails-app/conf/Config.groovy	(revision 633)
@@ -401,4 +401,12 @@
             [order:91, controller:'inventoryItemPurchaseDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
         ]
+    ],
+    [order:230, controller:'purchasingGroupDetailed', title:'purchasingGroup', action:'list',
+        subItems: [
+            [order:10, controller:'purchasingGroupDetailed', title:'Purchasing Group List', action:'list', isVisible: { true }],
+            [order:20, controller:'purchasingGroupDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'purchasingGroupDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'purchasingGroupDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
     ]
 ]
Index: trunk/grails-app/controllers/CostCodeDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/CostCodeDetailedController.groovy	(revision 632)
+++ trunk/grails-app/controllers/CostCodeDetailedController.groovy	(revision 633)
@@ -78,4 +78,6 @@
             }
             costCodeInstance.properties = params
+            // Trim name to avoid spaces.
+            costCodeInstance.name = costCodeInstance.name.trim()
             if(!costCodeInstance.hasErrors() && costCodeInstance.save(flush: true)) {
                 flash.message = "CostCode ${params.id} updated"
@@ -100,4 +102,6 @@
     def save = {
         def costCodeInstance = new CostCode(params)
+        // Trim name to avoid spaces.
+        costCodeInstance.name = costCodeInstance.name.trim()
         if(!costCodeInstance.hasErrors() && costCodeInstance.save(flush: true)) {
             flash.message = "CostCode ${costCodeInstance.id} created"
Index: trunk/grails-app/controllers/InventoryItemPurchaseDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/InventoryItemPurchaseDetailedController.groovy	(revision 632)
+++ trunk/grails-app/controllers/InventoryItemPurchaseDetailedController.groovy	(revision 633)
@@ -226,6 +226,13 @@
         params.returnTo = params.returnTo ?: 'inventoryItem'
 
-        if(!result.error)
-            return [ inventoryItemPurchaseInstance : result.inventoryItemPurchaseInstance ]
+        def costCodes = []
+
+        if(!result.error) {
+            if(inventoryPurchaseService.isPersonInPurchasingGroup(result.inventoryItemPurchaseInstance.costCode.purchasingGroup))
+                costCodes = inventoryPurchaseService.getCostCodesByPerson()
+
+            return [ inventoryItemPurchaseInstance : result.inventoryItemPurchaseInstance,
+                            'costCodes': costCodes ]
+        }
 
         flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
@@ -248,5 +255,14 @@
         }
 
-        render(view:'edit', model:[inventoryItemPurchaseInstance: result.inventoryItemPurchaseInstance.attach()])
+        result.inventoryItemPurchaseInstance.attach()
+        result.inventoryItemPurchaseInstance.costCode.attach()
+        result.inventoryItemPurchaseInstance.costCode.purchasingGroup.attach()
+
+        def costCodes = []
+        if(inventoryPurchaseService.isPersonInPurchasingGroup(result.inventoryItemPurchaseInstance.costCode.purchasingGroup))
+            costCodes = inventoryPurchaseService.getCostCodesByPerson()
+
+        render(view:'edit', model:[inventoryItemPurchaseInstance: result.inventoryItemPurchaseInstance,
+                                                'costCodes': costCodes])
     }
 
@@ -262,5 +278,8 @@
         }
 
-        return ['inventoryItemPurchaseInstance':inventoryItemPurchaseInstance]
+        def costCodes = inventoryPurchaseService.getCostCodesByPerson()
+
+        return ['inventoryItemPurchaseInstance': inventoryItemPurchaseInstance,
+                        'costCodes': costCodes]
     }
 
@@ -282,6 +301,9 @@
         }
 
+        def costCodes = inventoryPurchaseService.getCostCodesByPerson()
+
         params.errorMessage = g.message(code: result.error.code, args: result.error.args)
-        render(view:'create', model:['inventoryItemPurchaseInstance': result.inventoryItemPurchaseInstance])
+        render(view:'create', model:['inventoryItemPurchaseInstance': result.inventoryItemPurchaseInstance,
+                                                    'costCodes': costCodes])
     }
 
Index: trunk/grails-app/controllers/PersonController.groovy
===================================================================
--- trunk/grails-app/controllers/PersonController.groovy	(revision 632)
+++ trunk/grails-app/controllers/PersonController.groovy	(revision 633)
@@ -157,4 +157,5 @@
             person.properties = params
             person.setPersonGroupsFromCheckBoxList(params.personGroups)
+            person.setPurchasingGroupsFromCheckBoxList(params.purchasingGroups)
 
             if(params.pass == "") {
@@ -194,4 +195,5 @@
             person.password = authenticateService.encodePassword(params.pass)
             person.setPersonGroupsFromCheckBoxList(params.personGroups)
+            person.setPurchasingGroupsFromCheckBoxList(params.purchasingGroups)
             if (person.save(flush: true)) {
                 addRemoveAuthorities(person)
Index: trunk/grails-app/controllers/PurchasingGroupDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/PurchasingGroupDetailedController.groovy	(revision 633)
+++ trunk/grails-app/controllers/PurchasingGroupDetailedController.groovy	(revision 633)
@@ -0,0 +1,110 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
+class PurchasingGroupDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ purchasingGroupInstanceList: PurchasingGroup.list( params ), purchasingGroupInstanceTotal: PurchasingGroup.count() ]
+    }
+
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def purchasingGroupInstance = PurchasingGroup.get( params.id )
+
+        if(!purchasingGroupInstance) {
+            flash.message = "PurchasingGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ purchasingGroupInstance : purchasingGroupInstance ] }
+    }
+
+    def delete = {
+        def purchasingGroupInstance = PurchasingGroup.get( params.id )
+        if(purchasingGroupInstance) {
+            try {
+                purchasingGroupInstance.delete(flush:true)
+                flash.message = "PurchasingGroup ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "PurchasingGroup ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "PurchasingGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def purchasingGroupInstance = PurchasingGroup.get( params.id )
+
+        if(!purchasingGroupInstance) {
+            flash.message = "PurchasingGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ purchasingGroupInstance : purchasingGroupInstance ]
+        }
+    }
+
+    def update = {
+        def purchasingGroupInstance = PurchasingGroup.get( params.id )
+        if(purchasingGroupInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(purchasingGroupInstance.version > version) {
+                    
+                    purchasingGroupInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[purchasingGroupInstance:purchasingGroupInstance])
+                    return
+                }
+            }
+            purchasingGroupInstance.properties = params
+            if(!purchasingGroupInstance.hasErrors() && purchasingGroupInstance.save(flush: true)) {
+                flash.message = "PurchasingGroup ${params.id} updated"
+                redirect(action:show,id:purchasingGroupInstance.id)
+            }
+            else {
+                render(view:'edit',model:[purchasingGroupInstance:purchasingGroupInstance])
+            }
+        }
+        else {
+            flash.message = "PurchasingGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def purchasingGroupInstance = new PurchasingGroup()
+        purchasingGroupInstance.properties = params
+        return ['purchasingGroupInstance':purchasingGroupInstance]
+    }
+
+    def save = {
+        def purchasingGroupInstance = new PurchasingGroup(params)
+        if(!purchasingGroupInstance.hasErrors() && purchasingGroupInstance.save(flush: true)) {
+            flash.message = "PurchasingGroup ${purchasingGroupInstance.id} created"
+            redirect(action:show,id:purchasingGroupInstance.id)
+        }
+        else {
+            render(view:'create',model:[purchasingGroupInstance:purchasingGroupInstance])
+        }
+    }
+}
Index: trunk/grails-app/domain/CostCode.groovy
===================================================================
--- trunk/grails-app/domain/CostCode.groovy	(revision 632)
+++ trunk/grails-app/domain/CostCode.groovy	(revision 633)
@@ -1,3 +1,6 @@
 class CostCode {
+
+    PurchasingGroup purchasingGroup
+
     String name
     String description = ""
@@ -7,10 +10,23 @@
 
     static constraints = {
-        name(maxSize:50,unique:true,blank:false)
+        name(blank:false, maxSize:50, validator: {val, obj ->
+            // Name must be unique for a purchasingGroup.
+            def list = CostCode.withCriteria {
+                eq('purchasingGroup', obj.purchasingGroup)
+                eq('name', obj.name)
+                if(obj.id)
+                    notEqual('id', obj.id)
+            }
+            if(list.size() > 0)
+                return 'not.unique.for.purchasing.group'
+            // Success.
+            return true
+        })
         description(maxSize:100)
     }
 
     String toString() {
-        "${this.name}"
+        "${this.name}.${this.purchasingGroup}"
     }
+
 }
Index: trunk/grails-app/domain/Person.groovy
===================================================================
--- trunk/grails-app/domain/Person.groovy	(revision 632)
+++ trunk/grails-app/domain/Person.groovy	(revision 633)
@@ -7,5 +7,6 @@
                         tasks: Task,
                         contacts: Contact,
-                        addresses: Address]
+                        addresses: Address,
+                        purchasingGroups: PurchasingGroup]
 
     static belongsTo = [Authority]
@@ -68,3 +69,20 @@
     }
 
+    //  This additional setter is used to convert the checkBoxList string or string array
+    //  of ids selected to the corresponding domain objects.
+    public void setPurchasingGroupsFromCheckBoxList(ids) {
+        def idList = []
+        if(ids instanceof String) {
+                if(ids.isInteger())
+                    idList << ids.toInteger()
+        }
+        else {
+            ids.each() {
+                if(it.isInteger())
+                    idList << it.toInteger()
+            }
+        }
+        this.purchasingGroups = idList.collect { PurchasingGroup.get( it ) }
+    }
+
 } // end class
Index: trunk/grails-app/domain/PurchasingGroup.groovy
===================================================================
--- trunk/grails-app/domain/PurchasingGroup.groovy	(revision 633)
+++ trunk/grails-app/domain/PurchasingGroup.groovy	(revision 633)
@@ -0,0 +1,19 @@
+class PurchasingGroup {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [persons : Person,
+                                    costCodes: CostCode]
+
+    static belongsTo = [Person]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: trunk/grails-app/i18n/messages.properties
===================================================================
--- trunk/grails-app/i18n/messages.properties	(revision 632)
+++ trunk/grails-app/i18n/messages.properties	(revision 633)
@@ -45,4 +45,6 @@
 person.pass.doesNotMatch=Passwords must match
 
+costCode.name.not.unique.for.purchasing.group=CostCode name must be unique for purchasingGroup.
+
 #
 # Help Balloon and property definitions.
@@ -61,4 +63,6 @@
 may also provide a record of persons qualified or trained in a specific area. \
     Groups provide no application authorisations.
+person.purchasingGroups=Purchasing Groups
+person.purchasingGroups.help=Purchasing groups determine the available cost codes that a person may purchase against.
 person.loginName=Login Name
 person.loginName.help=This is the id or name that the person will use to login to the application.
@@ -231,4 +235,5 @@
 inventoryItemPurchase.delete.failure.payment.approved=Could not delete, payment has been approved.
 inventoryItemPurchase.operation.not.permitted.on.inactive.or.obsolete.item=This operation is not permitted on an inactive or obsolete inventory item.
+inventoryItemPurchase.costCodes.not.found=No cost codes found, a person needs to be assigned to a purchasing group that has cost codes.
 
 assignedGroup.task.not.found=Please select a task and then ''Add Assigned Group''.
Index: trunk/grails-app/services/CreateDataService.groovy
===================================================================
--- trunk/grails-app/services/CreateDataService.groovy	(revision 632)
+++ trunk/grails-app/services/CreateDataService.groovy	(revision 633)
@@ -115,5 +115,4 @@
 
         // Person and Utils
-        createDemoPersons()
         createDemoSites()
         createDemoDepartments()
@@ -121,5 +120,7 @@
         createDemoManufacturers()
         createDemoProductionReference()
+        createDemoPurchasingGroups()  /// @todo: Perhaps a 'createQuickStartData' method?
         createDemoCostCodes()
+        createDemoPersons()
 
         // Assets
@@ -307,4 +308,7 @@
         personInstance.addToAuthorities(Authority.get(2)) // ROLE_Manager.
         personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
+        personInstance.addToPersonGroups(PersonGroup.get(1))
+        personInstance.addToPurchasingGroups(PurchasingGroup.get(1))
+        personInstance.addToPurchasingGroups(PurchasingGroup.get(2))
 
         //Person #4
@@ -697,4 +701,19 @@
     }
 
+    void createDemoPurchasingGroups() {
+
+        // PurchasingGroup
+        def purchasingGroupInstance
+
+        purchasingGroupInstance = new PurchasingGroup(name:"R&M")
+        saveAndTest(purchasingGroupInstance)
+
+        purchasingGroupInstance = new PurchasingGroup(name:"Raw Materials")
+        saveAndTest(purchasingGroupInstance)
+
+        purchasingGroupInstance = new PurchasingGroup(name:"Safety")
+        saveAndTest(purchasingGroupInstance)
+    }
+
     def createDemoCostCodes() {
 
@@ -703,9 +722,16 @@
 
         // CostCode #1
-        costCodeInstance = new CostCode(name: "RM Reelstand")
+        costCodeInstance = new CostCode(name: "Reelstand.172",
+                                                                    purchasingGroup: PurchasingGroup.get(1))
         saveAndTest(costCodeInstance)
 
         // CostCode #2
-        costCodeInstance = new CostCode(name: "CAPEX Reelstand")
+        costCodeInstance = new CostCode(name: "Reelstand.CAPEX",
+                                                                    purchasingGroup: PurchasingGroup.get(1))
+        saveAndTest(costCodeInstance)
+
+        // CostCode #2
+        costCodeInstance = new CostCode(name: "PrintUnit.123",
+                                                                    purchasingGroup: PurchasingGroup.get(3))
         saveAndTest(costCodeInstance)
     }
Index: trunk/grails-app/services/InventoryPurchaseService.groovy
===================================================================
--- trunk/grails-app/services/InventoryPurchaseService.groovy	(revision 632)
+++ trunk/grails-app/services/InventoryPurchaseService.groovy	(revision 633)
@@ -89,4 +89,37 @@
     }
 
+    /**
+    * Get costCodes by person and the purchasingGroups they have been assigned.
+    * @param person A Person, defaults to currentUser.
+    * @returns A list of CostCodes.
+    */
+    def getCostCodesByPerson(person = authService.currentUser) {
+        if(person.purchasingGroups) {
+            CostCode.withCriteria {
+                    eq('isActive', true)
+                    or {
+                        person.purchasingGroups.each() { purchasingGroup ->
+                            eq('purchasingGroup', purchasingGroup)
+                        }
+                    }
+            }.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } // withCriteria
+        }
+        else
+            []
+    } // getCostCodesByPerson
+
+    /**
+    * Check if a person is in a purchasing group.
+    * @param person A PurchasingGroup to check for.
+    * @param person A Person, defaults to currentUser.
+    * @returns True if person is in group.
+    */
+    def isPersonInPurchasingGroup(purchasingGroup, person = authService.currentUser) {
+        for(pg in person.purchasingGroups) {
+            if(pg.id == purchasingGroup.id)
+                return true
+        }
+    } // isPersonInPurchasingGroup
+
     def delete(params) {
         InventoryItemPurchase.withTransaction { status ->
Index: trunk/grails-app/views/appCore/manager.gsp
===================================================================
--- trunk/grails-app/views/appCore/manager.gsp	(revision 632)
+++ trunk/grails-app/views/appCore/manager.gsp	(revision 633)
@@ -27,4 +27,6 @@
                                 <a href="${createLink(controller:'personGroupDetailed', action:'list')}">Assigned Groups</a>
                                 <br />
+                                <a href="${createLink(controller:'costCodeDetailed', action:'list')}">Cost Codes</a>
+                                <br />
                                 <a href="${createLink(controller:'departmentDetailed', action:'list')}">Departments</a>
                                 <br />
@@ -38,4 +40,6 @@
                                 <br />
                                 <a href="${createLink(controller:'manufacturerDetailed', action:'list')}">Manufacturers</a>
+                                <br />
+                                <a href="${createLink(controller:'purchasingGroupDetailed', action:'list')}">Purchasing Groups</a>
                                 <br />
                                 <a href="${createLink(controller:'productionReferenceDetailed', action:'list')}">Production Reference</a>
Index: trunk/grails-app/views/costCodeDetailed/create.gsp
===================================================================
--- trunk/grails-app/views/costCodeDetailed/create.gsp	(revision 632)
+++ trunk/grails-app/views/costCodeDetailed/create.gsp	(revision 633)
@@ -35,4 +35,20 @@
                             <tr class="prop">
                                 <td valign="top" class="name">
+                                    <label for="purchasingGroup">Purchasing Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:costCodeInstance,field:'purchasingGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                    from="${PurchasingGroup.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                    name="purchasingGroup.id"
+                                                    value="${costCodeInstance?.purchasingGroup?.id}" >
+                                    </g:select>
+                                    <p>
+                                        <g:link controller="purchasingGroupDetailed" action="create">+Add Group</g:link>
+                                    </p>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
                                     <label for="description">Description:</label>
                                 </td>
Index: trunk/grails-app/views/costCodeDetailed/edit.gsp
===================================================================
--- trunk/grails-app/views/costCodeDetailed/edit.gsp	(revision 632)
+++ trunk/grails-app/views/costCodeDetailed/edit.gsp	(revision 633)
@@ -37,4 +37,20 @@
                             <tr class="prop">
                                 <td valign="top" class="name">
+                                    <label for="purchasingGroup">Purchasing Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:costCodeInstance,field:'purchasingGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                    from="${PurchasingGroup.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                    name="purchasingGroup.id"
+                                                    value="${costCodeInstance?.purchasingGroup?.id}" >
+                                    </g:select>
+                                    <p>
+                                        <g:link controller="purchasingGroupDetailed" action="create">+Add Group</g:link>
+                                    </p>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
                                     <label for="description">Description:</label>
                                 </td>
Index: trunk/grails-app/views/costCodeDetailed/list.gsp
===================================================================
--- trunk/grails-app/views/costCodeDetailed/list.gsp	(revision 632)
+++ trunk/grails-app/views/costCodeDetailed/list.gsp	(revision 633)
@@ -23,4 +23,6 @@
                    	        <g:sortableColumn property="name" title="Name" />
                         
+                            <g:sortableColumn property="purchasingGroup" title="Group" />
+                        
                    	        <g:sortableColumn property="description" title="Description" />
                         
@@ -41,4 +43,8 @@
                             <td onclick='window.location = "${request.getContextPath()}/costCodeDetailed/show/${costCodeInstance.id}"'>
                                 ${fieldValue(bean:costCodeInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/costCodeDetailed/show/${costCodeInstance.id}"'>
+                                ${fieldValue(bean:costCodeInstance, field:'purchasingGroup')}
                             </td>
                         
Index: trunk/grails-app/views/costCodeDetailed/show.gsp
===================================================================
--- trunk/grails-app/views/costCodeDetailed/show.gsp	(revision 632)
+++ trunk/grails-app/views/costCodeDetailed/show.gsp	(revision 633)
@@ -34,4 +34,13 @@
                     
                         <tr class="prop">
+                            <td valign="top" class="name">Purchasing Group:</td>
+                            <td valign="top" class="value">
+                                <g:link controller="purchasingGroupDetailed" action="show" id="${costCodeInstance?.purchasingGroup?.id}">
+                                    ${costCodeInstance?.purchasingGroup?.encodeAsHTML()}
+                                </g:link>
+                            </td>
+                        </tr>
+                    
+                        <tr class="prop">
                             <td valign="top" class="name">Description:</td>
                             
@@ -44,17 +53,4 @@
                             
                             <td valign="top" class="value">${fieldValue(bean:costCodeInstance, field:'isActive')}</td>
-                            
-                        </tr>
-                    
-                        <tr class="prop">
-                            <td valign="top" class="name">Inventory Item Purchases:</td>
-                            
-                            <td  valign="top" style="text-align:left;" class="value">
-                                <ul>
-                                <g:each var="i" in="${costCodeInstance.inventoryItemPurchases}">
-                                    <li><g:link controller="inventoryItemPurchaseDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
-                                </g:each>
-                                </ul>
-                            </td>
                             
                         </tr>
Index: trunk/grails-app/views/inventoryItemPurchaseDetailed/create.gsp
===================================================================
--- trunk/grails-app/views/inventoryItemPurchaseDetailed/create.gsp	(revision 632)
+++ trunk/grails-app/views/inventoryItemPurchaseDetailed/create.gsp	(revision 633)
@@ -15,4 +15,10 @@
         <div class="body">
             <g:render template="/shared/messages" />
+            <g:if test="${!costCodes}" >
+                <div class="errors">
+                    <ul>
+                        <li><g:message code="inventoryItemPurchase.costCodes.not.found" /><li>
+                </div>
+            </g:if>
             <g:hasErrors bean="${inventoryItemPurchaseInstance}">
             <div class="errors">
@@ -66,5 +72,5 @@
                                 <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'costCode','errors')}">
                                     <g:select optionKey="id"
-                                                        from="${ CostCode.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }"
+                                                        from="${ costCodes }"
                                                         name="costCode.id"
                                                         value="${inventoryItemPurchaseInstance?.costCode?.id}"
Index: trunk/grails-app/views/inventoryItemPurchaseDetailed/edit.gsp
===================================================================
--- trunk/grails-app/views/inventoryItemPurchaseDetailed/edit.gsp	(revision 632)
+++ trunk/grails-app/views/inventoryItemPurchaseDetailed/edit.gsp	(revision 633)
@@ -59,5 +59,5 @@
                                 </td>
                             </tr> 
-                        
+
                             <tr class="prop">
                                 <td valign="top" class="name">
@@ -65,9 +65,16 @@
                                 </td>
                                 <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'costCode','errors')}">
-                                    <g:select optionKey="id"
-                                                        from="${ CostCode.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }"
-                                                        name="costCode.id"
-                                                        value="${inventoryItemPurchaseInstance?.costCode?.id}" >
-                                    </g:select>
+                                    <g:if test="${costCodes}">
+                                        <g:select optionKey="id"
+                                                            from="${ costCodes }"
+                                                            name="costCode.id"
+                                                            value="${inventoryItemPurchaseInstance.costCode?.id}" >
+                                        </g:select>
+                                    </g:if>
+                                    <g:else>
+                                        <g:link controller="costCodeDetailed" action="show" id="${inventoryItemPurchaseInstance?.costCode?.id}">
+                                            ${inventoryItemPurchaseInstance?.costCode?.encodeAsHTML()}
+                                        </g:link>
+                                    </g:else>
                                     <g:helpBalloon code="inventoryItemPurchase.cost.code" />
                                 </td>
@@ -96,6 +103,5 @@
                                                         from="${ Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }"
                                                         name="supplier.id"
-                                                        value="${inventoryItemPurchaseInstance?.supplier?.id}"
-                                                        noSelection="['null':/${g.message(code:'default.please.select.text')}/]">
+                                                        value="${inventoryItemPurchaseInstance?.supplier?.id}">
                                     </g:select>
                                     <g:helpBalloon code="inventoryItemPurchase.supplier" />
Index: trunk/grails-app/views/person/create.gsp
===================================================================
--- trunk/grails-app/views/person/create.gsp	(revision 632)
+++ trunk/grails-app/views/person/create.gsp	(revision 633)
@@ -105,4 +105,21 @@
 
                     <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="purchasingGroups">Purchasing Groups:</label>
+                        </td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'purchasingGroups','errors')}">
+                            <g:helpBalloon class="helpballoon" code="person.purchasingGroups" />
+                            <custom:checkBoxList name="purchasingGroups"
+                                                            from="${PurchasingGroup.findAllByIsActive(true)}"
+                                                            value="${person?.purchasingGroups?.collect{it.id}}"
+                                                            optionKey="id"
+                                                            sortBy="name"
+                                                            linkController="purchasingGroupDetailed"
+                                                            linkAction="show"/>
+                            <g:link controller="purchasingGroupDetailed" action="create">+Add Group</g:link>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
                         <td valign="top" class="name" align="left">
                             Authorities:
Index: trunk/grails-app/views/person/edit.gsp
===================================================================
--- trunk/grails-app/views/person/edit.gsp	(revision 632)
+++ trunk/grails-app/views/person/edit.gsp	(revision 633)
@@ -144,4 +144,21 @@
 
                     <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="purchasingGroups">Purchasing Groups:</label>
+                        </td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'purchasingGroups','errors')}">
+                            <g:helpBalloon class="helpballoon" code="person.purchasingGroups" />
+                            <custom:checkBoxList name="purchasingGroups"
+                                                            from="${PurchasingGroup.findAllByIsActive(true)}"
+                                                            value="${person?.purchasingGroups?.collect{it.id}}"
+                                                            optionKey="id"
+                                                            sortBy="name"
+                                                            linkController="purchasingGroupDetailed"
+                                                            linkAction="show"/>
+                            <g:link controller="purchasingGroupDetailed" action="create">+Add Group</g:link>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
                         <td valign="top" class="name" align="left">
                             Authorities:
Index: trunk/grails-app/views/person/show.gsp
===================================================================
--- trunk/grails-app/views/person/show.gsp	(revision 632)
+++ trunk/grails-app/views/person/show.gsp	(revision 633)
@@ -89,6 +89,29 @@
                     <td valign="top" class="value">
                         <ul>
-                        <g:each in="${person.personGroups}" var='group'>
-                            <li>${group}</li>
+                        <g:each var='group' in="${ person.personGroups.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                            <li>
+                                <g:link controller="personGroupDetailed"
+                                                action="show"
+                                                id="${group.id}">
+                                    ${group.encodeAsHTML()}
+                                </g:link>
+                            </li>
+                        </g:each>
+                        </ul>
+                    </td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Purchasing Groups:</td>
+                    <td valign="top" class="value">
+                        <ul>
+                        <g:each  var='a' in="${ person.purchasingGroups.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                            <li>
+                                <g:link controller="purchasingGroupDetailed"
+                                                action="show"
+                                                id="${a.id}">
+                                    ${a.encodeAsHTML()}
+                                </g:link>
+                            </li>
                         </g:each>
                         </ul>
Index: trunk/grails-app/views/purchasingGroupDetailed/create.gsp
===================================================================
--- trunk/grails-app/views/purchasingGroupDetailed/create.gsp	(revision 633)
+++ trunk/grails-app/views/purchasingGroupDetailed/create.gsp	(revision 633)
@@ -0,0 +1,62 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create PurchasingGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${purchasingGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${purchasingGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:purchasingGroupInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:purchasingGroupInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${purchasingGroupInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: trunk/grails-app/views/purchasingGroupDetailed/edit.gsp
===================================================================
--- trunk/grails-app/views/purchasingGroupDetailed/edit.gsp	(revision 633)
+++ trunk/grails-app/views/purchasingGroupDetailed/edit.gsp	(revision 633)
@@ -0,0 +1,66 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit PurchasingGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${purchasingGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${purchasingGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${purchasingGroupInstance?.id}" />
+                <input type="hidden" name="version" value="${purchasingGroupInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:purchasingGroupInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:purchasingGroupInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${purchasingGroupInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: trunk/grails-app/views/purchasingGroupDetailed/list.gsp
===================================================================
--- trunk/grails-app/views/purchasingGroupDetailed/list.gsp	(revision 633)
+++ trunk/grails-app/views/purchasingGroupDetailed/list.gsp	(revision 633)
@@ -0,0 +1,69 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>PurchasingGroup List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${purchasingGroupInstanceList}" status="i" var="purchasingGroupInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}"/>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/purchasingGroupDetailed/show/${purchasingGroupInstance.id}"'>
+                                ${fieldValue(bean:purchasingGroupInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/purchasingGroupDetailed/show/${purchasingGroupInstance.id}"'>
+                                ${fieldValue(bean:purchasingGroupInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/purchasingGroupDetailed/show/${purchasingGroupInstance.id}"'>
+                                ${fieldValue(bean:purchasingGroupInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/purchasingGroupDetailed/show/${purchasingGroupInstance.id}"'>
+                                ${fieldValue(bean:purchasingGroupInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${purchasingGroupInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${purchasingGroupInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: trunk/grails-app/views/purchasingGroupDetailed/show.gsp
===================================================================
--- trunk/grails-app/views/purchasingGroupDetailed/show.gsp	(revision 633)
+++ trunk/grails-app/views/purchasingGroupDetailed/show.gsp	(revision 633)
@@ -0,0 +1,89 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show PurchasingGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:purchasingGroupInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:purchasingGroupInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:purchasingGroupInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:purchasingGroupInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Cost Codes:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="i" in="${purchasingGroupInstance.costCodes}">
+                                    <li><g:link controller="costCodeDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                                <g:link controller="costCodeDetailed" params="['purchasingGroup.id':purchasingGroupInstance?.id]" action="create">+Add Cost Code</g:link>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Persons:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="i" in="${purchasingGroupInstance.persons}">
+                                    <li><g:link controller="person" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                                <g:link controller="person" action="list">+Add Person</g:link>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${purchasingGroupInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
