Skip to content

Commit

Permalink
Hotfix 0.7.8 (#141)
Browse files Browse the repository at this point in the history
* minor cleanup to prevent the assign identifier quartz job from throwing hundreds of "Duplicate key" errors if the pool of identifiers is small enough to cause lots of collisions

* removed unnecessarily verbose logging from inventory service

* Purchase Order UI changes to make it more consistent with other pages

* fixed #133: added ability to import order line items into an existing order; also added rollback feature

* fixed #50: Illegal attempt to associate a collection with two open sessions when receiving against purchase order

* Minor enhancements to make UI a little more consistent across entire app

* bumped app version to 0.7.8

* removed annoying inventory sampling report constraint
  • Loading branch information
jmiranda committed Apr 28, 2016
1 parent aa9bf1e commit b636e7e
Show file tree
Hide file tree
Showing 18 changed files with 411 additions and 107 deletions.
4 changes: 2 additions & 2 deletions application.properties
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#Grails Metadata file
#Fri Aug 14 12:16:18 CDT 2015
#Mon Apr 18 20:15:11 CDT 2016
app.buildDate=02 Feb 2012 11\:17\:30 PM
app.buildNumber=1
app.context=/openboxes
app.grails.version=1.3.7
app.name=openboxes
app.revisionNumber=11160
app.servlet.version=2.4
app.version=0.7.7
app.version=0.7.8
plugins.barcode4j=0.2.1
plugins.bubbling=2.1.4
plugins.clickstream=0.2.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.pih.warehouse.core.Location
import org.pih.warehouse.core.User
import org.pih.warehouse.shipping.Shipment
import org.pih.warehouse.shipping.ShipmentItem
import org.springframework.web.multipart.MultipartFile

// import java.util.Date

Expand Down Expand Up @@ -472,6 +473,86 @@ class OrderController {
}
}

def downloadOrderItems = {
def orderInstance = Order.get(params.id)
if (!orderInstance) {
flash.message = "${warehouse.message(code: 'default.not.found.message', args: [warehouse.message(code: 'order.label', default: 'Order'), params.id])}"
redirect(action: "list")
//render(text: 'Unable to find purchase order found', status: 404)

}
else {

def date = new Date();
response.setHeader("Content-disposition", "attachment; filename='PO${orderInstance.orderNumber}-${orderInstance?.description?.encodeAsHTML()}-${date.format("MM-dd-yyyy")}.csv'")
response.contentType = "text/csv"
def csv = ""

csv += "${warehouse.message(code:'product.productCode.label')}," +
"${warehouse.message(code:'product.name.label')}," +
"${warehouse.message(code:'product.vendorCode.label')}," +
"${warehouse.message(code:'orderItem.quantity.label')}," +
"${warehouse.message(code:'product.unitOfMeasure.label')}," +
"${warehouse.message(code:'orderItem.unitPrice.label')}," +
"${warehouse.message(code:'orderItem.totalPrice.label')}," +
"\n"

def totalPrice = 0.0

orderInstance?.listOrderItems()?.each { orderItem ->
totalPrice += orderItem.totalPrice()?:0

String quantityString = formatNumber(number:orderItem?.quantity, maxFractionDigits: 1, minFractionDigits: 1)
String unitPriceString = formatNumber(number:orderItem?.unitPrice, maxFractionDigits: 4, minFractionDigits: 2)
String totalPriceString = formatNumber(number:orderItem?.totalPrice(), maxFractionDigits: 2, minFractionDigits: 2)

csv += "${orderItem?.product?.productCode}," +
"${StringEscapeUtils.escapeCsv(orderItem?.product?.name)}," +
"${orderItem?.product?.vendorCode?:''}," +
"${quantityString}," +
"${orderItem?.product?.unitOfMeasure?:'EA'}," +
"${StringEscapeUtils.escapeCsv(unitPriceString)}," +
"${StringEscapeUtils.escapeCsv(totalPriceString)}" +
"\n"
}
render csv

}
}

def importOrderItems = {
def orderInstance = Order.get(params.id)
if (!orderInstance) {
flash.message = "${warehouse.message(code: 'default.not.found.message', args: [warehouse.message(code: 'order.label', default: 'Order'), params.id])}"
redirect(action: "list")
}
else {

try {
MultipartFile multipartFile = request.getFile('fileContents')
if (multipartFile.empty) {
flash.message = "File cannot be empty. Please select a packing list to import."
redirect(action: "show", id: params.id)
return;
}
List lineItems = orderService.parseOrderItems(multipartFile.inputStream)
log.info "Line items: " + lineItems

if (orderService.importOrderItems(params.id, lineItems)) {
flash.message = "Successfully imported ${lineItems?.size()} order line items. "

} else {
flash.message = "Failed to import packing list items due to an unknown error."
}
} catch (Exception e) {
log.error("Failed to import packing list due to the following error: " + e.message, e)
flash.message = "Failed to import packing list due to the following error: " + e.message
}
}
redirect(action: "show", id: params.id)
}


def upload = {
def orderInstance = Order.get(params.id)
if (!orderInstance) {
Expand Down Expand Up @@ -531,9 +612,24 @@ class OrderController {


}

}


def rollbackOrderStatus = {

def orderInstance = Order.get(params.id)
if (!orderInstance) {
flash.message = "${warehouse.message(code: 'default.not.found.message', args: [warehouse.message(code: 'order.label', default: 'Order'), params.id])}"
redirect(action: "list")
}
else {
orderService.rollbackOrderStatus(params.id)

}
redirect(action: "show", id: params.id)

}




Expand Down
4 changes: 2 additions & 2 deletions grails-app/i18n/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ default.browseByTag.label = Browse by attribute
default.browseByType.label = Browse by type
default.button.add.label = Add
default.button.addItem.label = Add Item
default.button.back.label = Back
default.button.back.label = << Back
default.button.cancel.label = Cancel
default.button.change.label = Change
default.button.clear.label = Clear
Expand All @@ -268,7 +268,7 @@ default.button.find.label = Find
default.button.finish.label = Finish
default.button.import.label = Import
default.button.move.label = Move
default.button.next.label = Next
default.button.next.label = Next >>
default.button.notSupported.message = This feature is not currently supported.
default.button.previous.label = Previous
default.button.review.label = Review
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
**/
package org.pih.warehouse.core

import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException
import org.apache.commons.lang.RandomStringUtils
import org.hibernate.ObjectNotFoundException
import org.pih.warehouse.inventory.Transaction
Expand Down Expand Up @@ -138,13 +139,20 @@ class IdentifierService {
def products = Product.findAll("from Product as p where productCode is null or productCode = ''")
products.each { product ->
try {
println "Assigning identifier to product " + product.id + " " + product.name
product.productCode = generateProductIdentifier()
if (!product.merge(flush: true, validate: false)) {
println product.errors
def productCode = generateProductIdentifier()
println "Assigning identifier ${productCode} to product " + product.id + " " + product.name

// Check to see if there's already a product with that product code
if (!Product.findByProductCode(productCode)) {
product.productCode = productCode
if (!product.merge(flush: true, validate: false)) {
println product.errors
}
}
} catch (MySQLIntegrityConstraintViolationException e) {
log.warn ("Unable to assign identifier due to constraint violation: " + e.message, e)
} catch (Exception e) {
println("Unable to assign identifier to product with ID " + product?.id + ": " + e.message)
log.warn("Unable to assign identifier to product with ID " + product?.id + ": " + e.message, e)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2079,7 +2079,7 @@ class InventoryService implements ApplicationContextAware {
inventoryItem.lotNumber = lotNumber
inventoryItem.expirationDate = expirationDate;
inventoryItem.product = product
inventoryItem.save()
inventoryItem.save(flush:true)
}
return inventoryItem

Expand Down Expand Up @@ -3172,18 +3172,15 @@ class InventoryService implements ApplicationContextAware {
Integer maxSize = inventoryItemKeys.size()

if (n > maxSize) {
throw new RuntimeException("You cannot request more items than are available at this location [requested=${n},available=${maxSize}].")
n = maxSize
//throw new RuntimeException("You cannot request more items than are available at this location [requested=${n},available=${maxSize}].")
}

Random random = new Random()
def randomIntegerList = []
(1..n).each {
println "n: " + n
println "maxSize: " + maxSize
def randomIndex = random.nextInt(maxSize)
println "randomIndex: " + randomIndex
def inventoryItem = inventoryItemKeys.get(randomIndex)
println "lotNumber: " + inventoryItem.lotNumber
inventoryItems << inventoryItem
}
return inventoryItems;
Expand Down Expand Up @@ -4018,7 +4015,6 @@ class InventoryService implements ApplicationContextAware {

// Get the inventory levels for all products at the given location
def inventoryLevelMap = InventoryLevel.findAllByInventory(location.inventory)?.groupBy { it.product }
log.info inventoryLevelMap

// Group entries by generic product
genericProductMap = entries.inject([:].withDefault { [
Expand Down
Loading

0 comments on commit b636e7e

Please sign in to comment.