source: branches/features/purchaseOrders/grails-app/services/InventoryCsvService.groovy @ 911

Last change on this file since 911 was 721, checked in by gav, 14 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.