source: trunk/grails-app/services/InventoryItemService.groovy @ 549

Last change on this file since 549 was 549, checked in by gav, 10 years ago

Add InventoryItemService savePicture(), part 2.
Add some more comments, another error code and ensure the inputStream gets closed.
Add gnuMims logo as an example picture to the demo inventory items.

File size: 11.9 KB
Line 
1/**
2* Provides a service class for the InventoryItem domain class.
3*/
4class InventoryItemService {
5
6    boolean transactional = false
7
8    /**
9    * Prepare a sorted list of possible alternateItems.
10    */
11    def getPossibleAlternateItems(inventoryItemInstance) {
12        def criteria = inventoryItemInstance.createCriteria()
13        def possibleAlternateItems = criteria {
14            and {
15                eq('isActive', true)
16                notEqual('id', inventoryItemInstance.id)
17            }
18        }.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
19    }
20
21    /**
22    * Prepare the data for the show view.
23    * The result can be used to easily construct the model for the show view.
24    * @param params The incoming params as normally passed to the show view
25    * primarily including the id of the inventoryItem.
26    * @returns A map containing result.error, if any error, otherwise result.inventoryItemInstance.
27    */
28    def show(params) {
29        def result = [:]
30
31        def fail = { Map m ->
32            result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
33            return result
34        }
35
36        result.inventoryItemInstance = InventoryItem.get( params.id )
37
38        if(!result.inventoryItemInstance)
39            return fail(code:"default.not.found")
40
41        def p = [:]
42
43        if(params.paginate == "purchases") {
44            params.showTab = "showPurchasingTab"
45            p.max = Math.min(params.max?.toInteger() ?: 10, 100)
46            p.offset = params.offset?.toInteger() ?: 0
47            p.sort = params.sort ?: null
48            p.order = params.order ?: null
49        }
50        else {
51            p.max = 10
52            p.offset = 0
53        }
54
55        result.inventoryItemPurchasesTotal = InventoryItemPurchase.countByInventoryItem(result.inventoryItemInstance)
56
57        result.inventoryItemPurchases = InventoryItemPurchase.withCriteria {
58                eq("inventoryItem", result.inventoryItemInstance)
59                maxResults(p.max)
60                firstResult(p.offset)
61                // Sorting:
62                // Default is to sort by order number then id.
63                // When a sortable column is clicked then we sort by that.
64                // If the sortable column clicked is order number then we add id as the second sort.
65                if(p.sort && p.order) {
66                    order(p.sort, p.order)
67                    if(p.sort == "purchaseOrderNumber") order('id', 'asc')
68                }
69                else {
70                    order('purchaseOrderNumber', 'desc')
71                    order('id', 'asc')
72                }
73            }
74
75        result.showTab = [:]
76        switch (params.showTab) {
77            case "showDetailTab":
78                result.showTab.detail =  new String("true")
79                break
80            case "showMovementTab":
81                result.showTab.movement =  new String("true")
82                break
83            case "showPurchasingTab":
84                result.showTab.purchasing =  new String("true")
85                break
86            default:
87                result.showTab.inventory = new String("true")
88        }
89
90        p.max = result.inventoryMovementListMax = 10
91        p.offset = 0
92        p.order = "desc"
93        p.sort = "id"
94        result.inventoryMovementList = InventoryMovement.findAllByInventoryItem(result.inventoryItemInstance, p)
95        result.inventoryMovementListTotal = InventoryMovement.countByInventoryItem(result.inventoryItemInstance)
96
97
98        // Success.
99        return result
100
101    } // end show()
102
103    def delete(params) {
104        InventoryItem.withTransaction { status ->
105            def result = [:]
106
107            def fail = { Map m ->
108                status.setRollbackOnly()
109                if(result.inventoryItemInstance && m.field)
110                    result.inventoryItemInstance.errors.rejectValue(m.field, m.code)
111                result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
112                return result
113            }
114
115            result.inventoryItemInstance = InventoryItem.get(params.id)
116
117            if(!result.inventoryItemInstance)
118                return fail(code:"default.not.found")
119
120            if(result.inventoryItemInstance.inventoryMovements)
121                return fail(code:"inventoryMovement.still.associated")
122
123            result.inventoryItemInstance.removeReverseAlternateItems()
124
125            try {
126                result.inventoryItemInstance.delete(flush:true)
127                return result //Success.
128            }
129            catch(org.springframework.dao.DataIntegrityViolationException e) {
130                return fail(code:"default.delete.failure")
131            }
132
133        } //end withTransaction
134    } // end delete()
135
136    def edit(params) {
137        def result = [:]
138        def fail = { Map m ->
139            result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
140            return result
141        }
142
143        result.inventoryItemInstance = InventoryItem.get(params.id)
144
145        if(!result.inventoryItemInstance)
146            return fail(code:"default.not.found")
147
148        // Success.
149        return result
150    }
151
152    def update(params) {
153        InventoryItem.withTransaction { status ->
154            def result = [:]
155
156            def fail = { Map m ->
157                status.setRollbackOnly()
158                if(result.inventoryItemInstance && m.field)
159                    result.inventoryItemInstance.errors.rejectValue(m.field, m.code)
160                result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
161                return result
162            }
163
164            result.inventoryItemInstance = InventoryItem.get(params.id)
165
166            if(!result.inventoryItemInstance)
167                return fail(code:"default.not.found")
168
169            // Optimistic locking check.
170            if(params.version) {
171                if(result.inventoryItemInstance.version > params.version.toLong())
172                    return fail(field:"version", code:"default.optimistic.locking.failure")
173            }
174
175            def previousAlternateItems = new ArrayList(result.inventoryItemInstance.alternateItems)
176
177            result.inventoryItemInstance.properties = params
178
179            if(result.inventoryItemInstance.hasErrors() || !result.inventoryItemInstance.save())
180                return fail(code:"default.update.failure")
181
182            result.inventoryItemInstance.removeReverseAlternateItems(previousAlternateItems)
183            result.inventoryItemInstance.addReverseAlternateItems()
184
185            // Success.
186            return result
187
188        } //end withTransaction
189    }  // end update()
190
191    def create(params) {
192        def result = [:]
193        def fail = { Map m ->
194            result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
195            return result
196        }
197
198        result.inventoryItemInstance = new InventoryItem()
199        result.inventoryItemInstance.properties = params
200
201        // success
202        return result
203    }
204
205    def save(params) {
206        InventoryItem.withTransaction { status ->
207            def result = [:]
208
209            def fail = { Map m ->
210                status.setRollbackOnly()
211                if(result.inventoryItemInstance && m.field)
212                    result.inventoryItemInstance.errors.rejectValue(m.field, m.code)
213                result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
214                return result
215            }
216
217            result.inventoryItemInstance = new InventoryItem(params)
218
219            if(result.inventoryItemInstance.hasErrors() || !result.inventoryItemInstance.save())
220                return fail(code:"default.create.failure")
221
222            // success
223            return result
224
225        } //end withTransaction
226    }
227
228    /**
229    * Save an inventory item picture.
230    * @param pictureSource A supported source to get the picture image from.
231    * Supported sources:
232    * HttpServletRequest e.g: 'request' var from controller to run getFile('file') against.
233    * ServletContextResource e.g: grailsApplication.mainContext.getResource('images/logo.png')
234    */
235    def savePicture(params, pictureSource) {
236        InventoryItem.withTransaction { status ->
237            def result = [:]
238
239            def kByteMultiplier = 1000
240
241            def fail = { Map m ->
242                status.setRollbackOnly()
243                if(result.inventoryItemInstance && m.field)
244                    result.inventoryItemInstance.errors.rejectValue(m.field, m.code)
245                result.error = [ code: m.code, args: m.args ?: ["InventoryItem", params.id] ]
246                return result
247            }
248
249            result.inventoryItemInstance = InventoryItem.get(params.id)
250
251            if(!result.inventoryItemInstance)
252                return fail(code:"default.not.found")
253
254            // Optimistic locking check.
255            if(params.version) {
256                if(result.inventoryItemInstance.version > params.version.toLong())
257                    return fail(field:"version", code:"default.optimistic.locking.failure")
258            }
259
260            if(result.inventoryItemInstance.picture)
261                return fail(field:"picture", code:"inventory.item.already.has.picture")
262
263            // Declare some more variables, since we appear to have most of what we need.
264            def picture = new Picture(inventoryItem: result.inventoryItemInstance)
265            def imaging = new Imaging()
266            def images = null
267            def pictureFile
268            def pictureFileName = ''
269            def pictureInputStream
270
271            // Check the supplied pictureSource and get the inputStream.
272            if(pictureSource instanceof javax.servlet.http.HttpServletRequest) {
273                def multiPartFile = pictureSource.getFile('file')
274                pictureFileName = multiPartFile.originalFilename
275
276                if(!multiPartFile || multiPartFile.isEmpty())
277                    return fail(code: "default.file.not.supplied")
278
279                if (multiPartFile.getSize() > Image.MAX_SIZE)
280                    return fail(code: "default.file.over.max.size", args: [Image.MAX_SIZE/kByteMultiplier, "kB"])
281
282                pictureInputStream = multiPartFile.inputStream
283            }
284            else if(pictureSource instanceof org.springframework.web.context.support.ServletContextResource) {
285                pictureFile = pictureSource.getFile()
286                pictureFileName = pictureFile.name
287
288                if ( !pictureFile.isFile() || (pictureFile.length() == 0) )
289                    return fail(code:"default.file.not.supplied")
290
291                if (pictureFile.length() > Image.MAX_SIZE)
292                    return fail(code:"default.file.over.max.size", args: [Image.MAX_SIZE/kByteMultiplier, "kB"])
293
294                pictureInputStream = pictureSource.inputStream
295            }
296            else {
297                    return fail(code:"inventory.item.picture.source.not.supported")
298            }
299
300            // Create the Images.
301            try {
302                images = imaging.createAll(result.inventoryItemInstance, picture, pictureInputStream)
303                // Ensure the stream is closed.
304                pictureInputStream.close()
305            }
306            catch(Exception ex) {
307                log.error("picture save", ex)
308                // Ensure the stream is closed.
309                pictureInputStream.close()
310                return fail(code:"inventory.item.picture.file.unrecognised", args: [pictureFileName])
311            }
312
313            // Add images to picture.
314            images.each { image ->
315                picture.addToImages(image)
316            }
317
318            // Save picture.
319            if(picture.hasErrors() || !picture.save())
320                return fail(code:"default.create.failure", args: ["Picture"])
321
322            result.inventoryItemInstance.picture = picture
323
324            // Save inventoryItem.
325            if(result.inventoryItemInstance.hasErrors() || !result.inventoryItemInstance.save())
326                return fail(code:"default.create.failure")
327
328            // success
329            return result
330
331        } //end withTransaction
332    }
333
334} // end class
Note: See TracBrowser for help on using the repository browser.