source: trunk/grails-app/services/InventoryCsvService.groovy @ 719

Last change on this file since 719 was 719, checked in by gav, 9 years ago

Domain change: as per ticket #96 - Remove unused fields from InventoryItem?.
Removed InventoryItem?.preferredManufacturer and manufacturersPartNumber.

File size: 33.4 KB
Line 
1import grails.util.GrailsUtil
2import au.com.bytecode.opencsv.CSVWriter
3import au.com.bytecode.opencsv.CSVReader
4import org.apache.commons.lang.WordUtils
5
6/**
7 * Provides some csv import/export methods.
8 * Requires the opencsv jar to be available which is included in the grails-export plugin.
9 */
10class InventoryCsvService {
11
12    boolean transactional = false
13
14    def dateUtilService
15
16    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
17
18    def sessionFactory
19    def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
20
21    /**
22    * Import inventory creating items as required.
23    * @param request The http request to run getFile against.
24    * Get file should return a csv format file containing the inventory as per template.
25    */
26    def importInventory(request) {
27        InventoryItem.withTransaction { status ->
28            def result = [:]
29
30            def kByteMultiplier = 1000
31            def fileMaxSize = 800 * kByteMultiplier
32            def logFileLink = g.link(controller: "appCore", action: "appLog") {"log"}
33
34            def multiPartFile = request.getFile('file')
35
36            InputStreamReader sr = new InputStreamReader(multiPartFile.inputStream)
37            CSVReader reader = new CSVReader(sr)
38
39            def fail = { Map m ->
40                status.setRollbackOnly()
41                reader.close()
42                result.error = [ code: m.code, args: m.args ]
43                return result
44            }
45
46            if(!multiPartFile || multiPartFile.isEmpty())
47                return fail(code: "default.file.not.supplied")
48
49            if (multiPartFile.getSize() > fileMaxSize)
50                return fail(code: "default.file.over.max.size", args: [fileMaxSize/kByteMultiplier, "kB"])
51
52            def line = []
53            def lineNumber = 0
54            def maxNumberOfColumns = 20
55            def inventoryParams = [:]
56            def inventoryProperties = ["name", "description", "comment", "unitsInStock", "reorderPoint", "reorderQuantity",
57                                                        "unitOfMeasure", "estimatedUnitPriceAmount", "estimatedUnitPriceCurrency",
58                                                        "enableReorderListing", "inventoryLocation", "inventoryStore", "site",
59                                                        "inventoryGroup", "inventoryType",
60                                                        "suppliersPartNumber", "preferredSupplier", "alternateSuppliers",
61                                                        "alternateItems", "spareFor"]
62
63            def siteInstance
64            def alternateSupplierInstance
65            def preferredSupplierInstance
66            def supplierTypeInstance
67            def supplierTypeUnknown = SupplierType.get(1)
68            def spareForInstance
69            def alternateItemInstance
70            def inventoryTypeInstance
71            def unitOfMeasureInstance
72            def inventoryGroupInstance
73            def inventoryItemInstance
74            def inventoryStoreInstance
75            def inventoryLocationInstance
76
77            def tempPreferredSupplierItemAndType = ''
78            def tempPreferredSupplierItem = ''
79            def tempPreferredSupplierType = ''
80
81            def tempAlternateSuppliers = []
82            def tempSupplierItem = ''
83            def tempSupplierType = ''
84            def tempSupplierItemAndType = []
85
86            def tempSpareFor = []
87            def tempAlternateItems = []
88
89            def nextLine = {
90                    line = reader.readNext()
91                    lineNumber ++
92                    log.info "Processing line: " + lineNumber
93            }
94
95            def parseInputList = {
96                if( (it == null) || (it.trim() == '') ) return []
97                return it.split(";").collect{it.trim()}
98            }
99
100            def parseItemAndType = {
101                return it.split("@").collect{it.trim()}
102            }
103
104            // Get first line.
105            nextLine()
106
107            // Check for header line 1.
108            if(line != templateHeaderLine1) {
109                log.error "Failed to find header line 1. "
110                log.error "Required: " + templateHeaderLine1.toString()
111                log.error "Supplied: " + line.toString()
112                return fail(code: "default.file.no.header")
113            }
114
115            log.info "Header line found."
116
117            // Prepare the first body line.
118            nextLine()
119
120            // Primary loop.
121            while(line) {
122
123                if(line.size() > maxNumberOfColumns) {
124                    log.error "Too many columns on line: " + lineNumber
125                    return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
126                }
127
128                // Ignore comment lines.
129                if(line.toString().toLowerCase().contains("comment")) {
130                    log.info "Comment line found."
131                    nextLine()
132                    continue
133                }
134
135                // Ignore example lines.
136                if(line.toString().toLowerCase().contains("example")) {
137                    log.info "Example line found."
138                    nextLine()
139                    continue
140                }
141
142                // Parse the line into the params map.
143                inventoryParams = [:]
144                line.eachWithIndex { it, j ->
145                    inventoryParams."${inventoryProperties[j]}" = it.trim()
146                }
147
148                // Debug
149                log.debug " Supplied params: "
150                log.debug inventoryParams
151
152                // Ignore blank lines.
153                if(inventoryParams.name == '') {
154                    log.info "No name found."
155                    nextLine()
156                    continue
157                }
158
159                /** Prepare the params and create supporting items as required. */
160
161                // Site
162                inventoryParams.site = WordUtils.capitalize(inventoryParams.site)
163                siteInstance = Site.findByName(inventoryParams.site)
164                if(!siteInstance) {
165                    siteInstance = new Site(name: inventoryParams.site)
166                    if(!siteInstance.save()) {
167                        log.error "Failed to create site on line: " + lineNumber
168                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
169                    }
170                }
171
172                // InventoryStore
173                inventoryParams.inventoryStore = WordUtils.capitalizeFully(inventoryParams.inventoryStore)
174                inventoryStoreInstance = InventoryStore.findByName(inventoryParams.inventoryStore)
175                if(!inventoryStoreInstance) {
176                    inventoryStoreInstance = new InventoryStore(name: inventoryParams.inventoryStore,
177                                                                                                site: siteInstance)
178                    if(!inventoryStoreInstance.save()) {
179                        log.error "Failed to create inventory store on line: " + lineNumber
180                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
181                    }
182                }
183
184                // InventoryLocation
185                inventoryParams.inventoryLocation = WordUtils.capitalize(inventoryParams.inventoryLocation)
186                inventoryLocationInstance = InventoryLocation.findByName(inventoryParams.inventoryLocation)
187                if(!inventoryLocationInstance) {
188                    inventoryLocationInstance = new InventoryLocation(name: inventoryParams.inventoryLocation,
189                                                                                                        inventoryStore: inventoryStoreInstance)
190                    if(!inventoryLocationInstance.save()) {
191                        log.error "Failed to create inventory location on line: " + lineNumber
192                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
193                    }
194                }
195
196                // InventoryGroup
197                inventoryParams.inventoryLocation = WordUtils.capitalizeFully(inventoryParams.inventoryLocation)
198                inventoryGroupInstance = InventoryGroup.findByName(inventoryParams.inventoryGroup)
199                if(!inventoryGroupInstance) {
200                    inventoryGroupInstance = new InventoryGroup(name: inventoryParams.inventoryGroup)
201                    if(!inventoryGroupInstance.save()) {
202                        log.error "Failed to create inventory group on line: " + lineNumber
203                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
204                    }
205                }
206
207                // InventoryType
208                inventoryParams.inventoryType = WordUtils.capitalizeFully(inventoryParams.inventoryType)
209                inventoryTypeInstance = InventoryType.findByName(inventoryParams.inventoryType)
210                if(!inventoryTypeInstance) {
211                    inventoryTypeInstance = new InventoryType(name: inventoryParams.inventoryType)
212                    if(!inventoryTypeInstance.save()) {
213                        log.error "Failed to create inventory type on line: " + lineNumber
214                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
215                    }
216                }
217
218                // UnitOfMeasure.
219                unitOfMeasureInstance = UnitOfMeasure.findByName(inventoryParams.unitOfMeasure)
220                if(!unitOfMeasureInstance) {
221                    unitOfMeasureInstance = new UnitOfMeasure(name: inventoryParams.unitOfMeasure)
222                    if(!unitOfMeasureInstance.save()) {
223                        log.error "Failed to create unit of measure on line: " + lineNumber
224                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
225                    }
226                }
227
228                // Preferred Supplier
229                if(inventoryParams.preferredSupplier) {
230                    tempPreferredSupplierItemAndType = parseItemAndType(inventoryParams.preferredSupplier)
231                    tempPreferredSupplierItem = WordUtils.capitalize(tempPreferredSupplierItemAndType[0])
232
233                    preferredSupplierInstance = Supplier.findByName(tempPreferredSupplierItem)
234                    if(!preferredSupplierInstance) {
235
236                        // SupplierType.
237                        if(tempPreferredSupplierItemAndType.size == 2) {
238                            tempPreferredSupplierType = WordUtils.capitalize(tempPreferredSupplierItemAndType[1])
239                            supplierTypeInstance = SupplierType.findByName(tempPreferredSupplierType)
240                        }
241                        else
242                            supplierTypeInstance = supplierTypeUnknown
243                        if(!supplierTypeInstance) {
244                            log.error "Failed to find preferred supplier type on line: " + lineNumber
245                            return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
246                        }
247
248                        preferredSupplierInstance = new Supplier(name: tempPreferredSupplierItem,
249                                                                                            supplierType: supplierTypeInstance)
250                        if(!preferredSupplierInstance.save()) {
251                            log.error "Failed to create preferred supplier on line: " + lineNumber
252                            return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
253                        }
254                    }
255                }
256                else
257                    preferredSupplierInstance = null
258
259                // Alternate Suppliers.
260                tempAlternateSuppliers = parseInputList(inventoryParams.alternateSuppliers)
261                inventoryParams.alternateSuppliers = []
262
263                for(tempSupplier in tempAlternateSuppliers) {
264                    tempSupplierItemAndType = parseItemAndType(tempSupplier)
265                    tempSupplierItem = WordUtils.capitalizeFully(tempSupplierItemAndType[0])
266
267                    alternateSupplierInstance = Supplier.findByName(tempSupplierItem)
268                    if(!alternateSupplierInstance) {
269
270                        // SupplierType.
271                        if(tempSupplierItemAndType.size == 2) {
272                            tempSupplierType = WordUtils.capitalize(tempSupplierItemAndType[1])
273                            supplierTypeInstance = SupplierType.findByName(tempSupplierType)
274                        }
275                        else
276                            supplierTypeInstance = supplierTypeUnknown
277                        if(!supplierTypeInstance) {
278                            log.error "Failed to find alternate supplier type on line: " + lineNumber
279                            return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
280                        }
281
282                        alternateSupplierInstance = new Supplier(name: tempSupplierItem,
283                                                                            supplierType: supplierTypeInstance)
284                        if(!alternateSupplierInstance.save()) {
285                            log.error "Failed to create alternate suppliers on line: " + lineNumber
286                            return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
287                        }
288                    }
289
290                    inventoryParams.alternateSuppliers.add(alternateSupplierInstance)
291                }
292
293                // AlternateItems.
294                tempAlternateItems = parseInputList(inventoryParams.alternateItems)
295                inventoryParams.alternateItems = []
296
297                for(tempAlternateItem in tempAlternateItems) {
298                    tempAlternateItem = WordUtils.capitalize(tempAlternateItem)
299                    alternateItemInstance = InventoryItem.findByName(tempAlternateItem)
300                    if(!alternateItemInstance) {
301                        alternateItemInstance = new InventoryItem(name: tempAlternateItem,
302                                                                                                description: "Generated from alternateItems during import, details may not be correct.",
303                                                                                                reorderPoint: 0,
304                                                                                                inventoryGroup: inventoryGroupInstance,
305                                                                                                inventoryType: inventoryTypeInstance,
306                                                                                                unitOfMeasure: unitOfMeasureInstance,
307                                                                                                inventoryLocation: inventoryLocationInstance)
308                        if(!alternateItemInstance.save()) {
309                            log.error "Failed to create alternateItems on line: " + lineNumber
310                            return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
311                        }
312                    }
313
314                    inventoryParams.alternateItems.add(alternateItemInstance)
315                }
316
317                // spareFor.
318                tempSpareFor = parseInputList(inventoryParams.spareFor)
319                inventoryParams.spareFor = []
320
321                for(asset in tempSpareFor) {
322
323                    asset = WordUtils.capitalize(asset)
324
325                    spareForInstance = Asset.findByName(asset)
326                    if(!spareForInstance) {
327                        log.error "Failed to find 'Spare For' asset on line: " + lineNumber
328                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
329                    }
330
331                    inventoryParams.spareFor.add(spareForInstance)
332                }
333
334                // Assign the retrieved or created instances to params.
335                inventoryParams.inventoryLocation = inventoryLocationInstance
336                inventoryParams.inventoryGroup = inventoryGroupInstance
337                inventoryParams.inventoryType = inventoryTypeInstance
338                inventoryParams.unitOfMeasure = unitOfMeasureInstance
339                inventoryParams.preferredSupplier = preferredSupplierInstance
340
341                // Name.
342                // Checked above for blank string.
343                inventoryParams.name = WordUtils.capitalize(inventoryParams.name)
344
345                // Description.
346                if(inventoryParams.description != '')
347                    inventoryParams.description = inventoryParams.description[0].toUpperCase() + inventoryParams.description[1..-1]
348
349                // Debug
350                log.debug "InventoryParams: "
351                log.debug inventoryParams
352
353                // Create new or update.
354                inventoryItemInstance = InventoryItem.findByName(inventoryParams.name)
355                if(inventoryItemInstance) {
356                    log.info "Updating existing item: " + inventoryItemInstance
357                    inventoryItemInstance.properties = inventoryParams
358                }
359                else {
360                    log.info "Creating new item: " + inventoryParams.name
361                    inventoryItemInstance = new InventoryItem(inventoryParams)
362                }
363
364                // Save inventoryItem.
365                if(inventoryItemInstance.hasErrors() || !inventoryItemInstance.save()) {
366                    log.error "Failed to create item on line: " + lineNumber
367                    log.debug inventoryItemInstance.errors
368                    return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
369                }
370
371                if(lineNumber % 100 == 0)
372                    cleanUpGorm()
373
374                if(!result.error) nextLine()
375            } //while(line)
376
377            // Success.
378            log.info "End of file."
379            reader.close()
380            return result
381
382        } //end withTransaction
383    } // end importInventory()
384
385    /**
386    * Build an inventory template csv file.
387    * This template can then be populated for import.
388    * @returns The template as a String in csv format.
389    */
390    def buildInventoryTemplate() {
391
392        StringWriter sw = new StringWriter()
393        CSVWriter writer = new CSVWriter(sw)
394
395        writeTemplateLines(writer)
396
397        writer.close()
398        return sw.toString()
399    }
400
401    private writeTemplateLines(writer) {
402        writer.writeNext(templateHeaderLine1 as String[])
403        writer.writeNext()
404        writer.writeNext("Comment: The header line is required.")
405        writer.writeNext("Comment: Required columns are marked with a (*) in the header line.")
406        writer.writeNext("Comment: Lists of items in a column must be separated by a semicolon (;), not a comma.")
407        writer.writeNext("Comment: The at symbol (@) is reserved for indicating supplier types.")
408        writer.writeNext("Comment: Identical and existing names will be considered as the same item.")
409        writer.writeNext("Comment: Lines containing 'comment' will be ignored.")
410        writer.writeNext("Comment: Lines containing 'example' will be ignored.")
411        writer.writeNext("Comment: This file must be saved as a CSV file before import.")
412        writer.writeNext()
413    }
414
415    /**
416    * Build an inventory example/test file.
417    * This test file can be imported to test the import and export methods.
418    * @returns The test file as a String in csv format.
419    */
420    def buildInventoryExample() {
421
422        StringWriter sw = new StringWriter()
423        CSVWriter writer = new CSVWriter(sw)
424
425        writeTemplateLines(writer)
426
427        // Requires creation of some of the base/group/type data.
428        writer.writeNext(["Split19", "19mm split pin", "Very usefull item.",
429                                        "1024", "0", "1",
430                                        "each", "5", "NZD",
431                                        "false", "BR4",
432                                        "Store #99", "Inventory Depot",
433                                        "Mechanical Stock",
434                                        "Consumable",
435                                        "123", "Multi Supplier@Local",
436                                        "Multi Distributors1@OEM; Multi Distributors2@Local",
437                                        "2204E-2RS", ""
438                                        ] as String[])
439
440        // Using existing base data.
441        writer.writeNext(["2204E-2RS", "Double Row Self Align Ball Bearing 2204E-2RS - Sealed - 20/47x18", "",
442                                        "4", "1", "9",
443                                        "each", "16.35", "USD",
444                                        "TRUE", "BR4",
445                                        "Store #99", "Inventory Depot",
446                                        "Mechanical Stock",
447                                        "Consumable",
448                                        "456KL", "Multi Supplier",
449                                        "Multi Distributors1; Multi Distributors2",
450                                        "", ""
451                                        ] as String[])
452
453        writer.close()
454        return sw.toString()
455    }
456
457    /**
458    * Build complete inventory for export.
459    * @param inventoryItemList The list of inventory items to build.
460    * @returns The inventory as a String in csv format.
461    */
462    def buildInventory(List inventoryItemList) {
463
464        def sw = new StringWriter()
465        def writer = new CSVWriter(sw)
466
467        writeTemplateLines(writer)
468
469        //Rows
470        def row
471
472        inventoryItemList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { inventoryItem ->
473            row = []
474            row.add(inventoryItem.name)
475            row.add(inventoryItem.description)
476            row.add(inventoryItem.comment)
477            row.add(inventoryItem.unitsInStock)
478            row.add(inventoryItem.reorderPoint)
479            row.add(inventoryItem.reorderQuantity)
480            row.add(inventoryItem.unitOfMeasure)
481            row.add(inventoryItem.estimatedUnitPriceAmount)
482            row.add(inventoryItem.estimatedUnitPriceCurrency)
483            row.add(inventoryItem.enableReorderListing)
484            row.add(inventoryItem.inventoryLocation)
485            row.add(inventoryItem.inventoryLocation.inventoryStore)
486            row.add(inventoryItem.inventoryLocation.inventoryStore.site)
487            row.add(inventoryItem.inventoryGroup)
488            row.add(inventoryItem.inventoryType)
489            row.add(inventoryItem.suppliersPartNumber)
490
491            if(inventoryItem.preferredSupplier)
492                row.add( inventoryItem.preferredSupplier.name + "@" + inventoryItem.preferredSupplier.supplierType )
493            else
494                row.add('')
495
496            row.add( inventoryItem.alternateSuppliers.sort { p1, p2 ->
497                p1.name.compareToIgnoreCase(p2.name)
498            }.collect { it.name + "@" + it.supplierType }.join(';') )
499
500            row.add(inventoryItem.spareFor.sort { p1, p2 ->
501                p1.name.compareToIgnoreCase(p2.name)
502            }.collect { it.name }.join(';'))
503
504            writer.writeNext(row as String[])
505        }
506
507        writer.close()
508        return sw.toString()
509    } // end buildInventory()
510
511    /**
512    * Import inventoryItemPurchases creating items as required.
513    */
514    def importInventoryItemPurchases(request) {
515        InventoryItemPurchase.withTransaction { status ->
516            def result = [:]
517
518            def kByteMultiplier = 1000
519            def fileMaxSize = 800 * kByteMultiplier
520            def logFileLink = g.link(controller: "appCore", action: "appLog") {"log"}
521
522            def multiPartFile = request.getFile('file')
523
524            InputStreamReader sr = new InputStreamReader(multiPartFile.inputStream)
525            CSVReader reader = new CSVReader(sr)
526
527            def fail = { Map m ->
528                status.setRollbackOnly()
529                reader.close()
530                result.error = [ code: m.code, args: m.args ]
531                return result
532            }
533
534            if(!multiPartFile || multiPartFile.isEmpty())
535                return fail(code: "default.file.not.supplied")
536
537            if (multiPartFile.getSize() > fileMaxSize)
538                return fail(code: "default.file.over.max.size", args: [fileMaxSize/kByteMultiplier, "kB"])
539
540            def line = []
541            def lineNumber = 0
542            def maxNumberOfColumns = 10
543            def inventoryItemPurchaseParams = [:]
544            def inventoryItemPurchaseProperties = ["inventoryItem", "purchaseOrderNumber", "quantity",
545                                                                                "inventoryItemPurchaseType",
546                                                                                "costCode", "enteredBy", "dateEntered",
547                                                                                "orderValueAmount", "orderValueCurrency", "invoiceNumber"]
548
549            def personInstance
550            def costCodeInstance
551            def inventoryItemInstance
552            def inventoryItemPurchaseInstance
553            def inventoryItemPurchaseTypeInstance
554
555            def nextLine = {
556                    line = reader.readNext()
557                    lineNumber ++
558                    log.info "Processing line: " + lineNumber
559            }
560
561            def parseInputDate = {
562                if( (it == null) || (it.trim() == '') ) {
563                    log.error "Failed to find any date on line: " + lineNumber
564                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
565                }
566
567                def d = it.split("/").collect{it.trim()}
568                if(d.size() != 3) {
569                    log.error "Failed to find full date on line: " + lineNumber
570                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
571                }
572                dateUtilService.makeDate(d[0], d[1], d[2])
573            }
574
575            // Get first line.
576            nextLine()
577
578            // Check for header line 1.
579            if(line != purchasesTemplateHeaderLine1) {
580                log.error "Failed to find header line 1. "
581                log.error "Required: " + purchasesTemplateHeaderLine1.toString()
582                log.error "Supplied: " + line.toString()
583                return fail(code: "default.file.no.header")
584            }
585
586            log.info "Header line found."
587
588            // Prepare the first body line.
589            nextLine()
590
591            // Primary loop.
592            while(line) {
593
594                if(line.size() > maxNumberOfColumns) {
595                    log.error "Too many columns on line: " + lineNumber
596                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
597                }
598
599                // Ignore comment lines.
600                if(line.toString().toLowerCase().contains("comment")) {
601                    log.info "Comment line found."
602                    nextLine()
603                    continue
604                }
605
606                // Ignore example lines.
607                if(line.toString().toLowerCase().contains("example")) {
608                    log.info "Example line found."
609                    nextLine()
610                    continue
611                }
612
613                // Parse the line into the params map.
614                inventoryItemPurchaseParams = [:]
615                line.eachWithIndex { it, j ->
616                    inventoryItemPurchaseParams."${inventoryItemPurchaseProperties[j]}" = it.trim()
617                }
618
619                // Debug
620                log.debug " Supplied params: "
621                log.debug inventoryItemPurchaseParams
622
623                // Ignore blank lines.
624                if(inventoryItemPurchaseParams.inventoryItem == '') {
625                    log.info "No inventory item name found."
626                    nextLine()
627                    continue
628                }
629
630                // Inventory Item.
631                inventoryItemPurchaseParams.inventoryItem = WordUtils.capitalize(inventoryItemPurchaseParams.inventoryItem)
632                inventoryItemInstance = InventoryItem.findByName(inventoryItemPurchaseParams.inventoryItem)
633                if(!inventoryItemInstance) {
634                    log.error "Inventory item not found on line: " + lineNumber
635                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
636                }
637                inventoryItemPurchaseParams.inventoryItem = inventoryItemInstance
638
639                // Quantity.
640                if(inventoryItemPurchaseParams.quantity.isInteger())
641                    inventoryItemPurchaseParams.quantity = inventoryItemPurchaseParams.quantity.toInteger()
642                else {
643                    log.error "Quantity is not a valid number on line: " + lineNumber
644                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
645                }
646
647                // InventoryItemPurchaseType.
648                inventoryItemPurchaseParams.inventoryItemPurchaseType = WordUtils.capitalizeFully(inventoryItemPurchaseParams.inventoryItemPurchaseType)
649                inventoryItemPurchaseTypeInstance = InventoryItemPurchaseType.findByName(inventoryItemPurchaseParams.inventoryItemPurchaseType)
650                if(!inventoryItemPurchaseTypeInstance) {
651                    log.error "Inventory item purchase type not found on line: " + lineNumber
652                    log.debug inventoryItemPurchaseParams.inventoryItemPurchaseType
653                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
654                }
655                inventoryItemPurchaseParams.inventoryItemPurchaseType = inventoryItemPurchaseTypeInstance
656
657                // CostCode.
658                if(inventoryItemPurchaseParams.costCode != '') {
659                    inventoryItemPurchaseParams.costCode = WordUtils.capitalizeFully(inventoryItemPurchaseParams.costCode)
660                    costCodeInstance = CostCode.findByName(inventoryItemPurchaseParams.costCode)
661                    if(!costCodeInstance) {
662                        costCodeInstance = new CostCode(name: inventoryItemPurchaseParams.costCode)
663                        if(!costCodeInstance.save()) {
664                            log.error "Failed to create cost code on line: " + lineNumber
665                            return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
666                        }
667                    }
668                    inventoryItemPurchaseParams.costCode = costCodeInstance
669                }
670
671                // Entered By.
672                inventoryItemPurchaseParams.enteredBy = inventoryItemPurchaseParams.enteredBy.toLowerCase()
673                personInstance = Person.findByLoginName(inventoryItemPurchaseParams.enteredBy)
674                if(!personInstance) {
675                    log.error "Entered by person not found on line: " + lineNumber
676                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
677                }
678                inventoryItemPurchaseParams.enteredBy = personInstance
679
680                // Date Entered.
681                inventoryItemPurchaseParams.dateEntered = parseInputDate(inventoryItemPurchaseParams.dateEntered)
682
683                // Debug
684                log.debug "InventoryItemPurchaseParams: "
685                log.debug inventoryItemPurchaseParams
686
687                // Save inventoryItem.
688                log.info "Creating new purchase."
689                inventoryItemPurchaseInstance = new InventoryItemPurchase(inventoryItemPurchaseParams)
690
691                if(inventoryItemPurchaseInstance.hasErrors() || !inventoryItemPurchaseInstance.save()) {
692                    log.error "Failed to create item on line: " + lineNumber
693                    log.debug inventoryItemPurchaseInstance.errors
694                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
695                }
696
697                if(lineNumber % 100 == 0)
698                    cleanUpGorm()
699
700                if(!result.error) nextLine()
701            } //while(line)
702
703            // Success.
704            log.info "End of file."
705            reader.close()
706            return result
707
708
709         } //end withTransaction
710    } // end importInventoryItemPurchases()
711
712    private getTemplateHeaderLine1() {
713            ["Name*", "Description", "Comment", "Units In Stock", "Reorder Point*", "Reorder Quantity", "Unit Of Measure*",
714            "Estimated Unit Price", "Currency", "Enable Reorder", "Location*", "Store*", "Site*", "Group*", "Type*",
715            "Supplier's Part Number", "Preferred Supplier", "Alternate Suppliers",
716            "Alternate Item", "Spare For"]
717    }
718
719    private getPurchasesTemplateHeaderLine1() {
720            ["Inventory Item*", "Purchase Order Number*", "Quantity*", "Purchase Type*", "Cost Code*", "Entered By*",
721            "Date Entered*", "Order Value", "Currency", "Invoice Number"]
722    }
723
724    /**
725    * This cleans up the hibernate session and a grails map.
726    * For more info see: http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/
727    * The hibernate session flush is normal for hibernate.
728    * The map is apparently used by grails for domain object validation errors.
729    * A starting point for clean up is every 100 objects.
730    */
731    def cleanUpGorm() {
732        def session = sessionFactory.currentSession
733        session.flush()
734        session.clear()
735        propertyInstanceMap.get().clear()
736    }
737
738} // end class
Note: See TracBrowser for help on using the repository browser.