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

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

Imrovements to InventoryCsvService.
Update inventory import function, turn off searchable index mirroring during import and manually test as per ticket #79.

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