Skip to content

Commit

Permalink
* PIMS-2085 Assign identifiers during startup (disabled validation to
Browse files Browse the repository at this point in the history
force the identifier to be saved).
* Added new indicators to the dashboard (low stock, expiring/expired
stock, reorder level). Linked indicators to exisiting report pages.
* PIMS-1832 Generate new identifier when creating a new product.
* UI enhancements to the edit product page.
* Fixed shipment service unit tests that might have been failing due to
a change to the InventoryItem.equals() method.
  • Loading branch information
jmiranda committed Feb 6, 2013
1 parent 9510440 commit 3c7eb8e
Show file tree
Hide file tree
Showing 29 changed files with 1,186 additions and 689 deletions.
10 changes: 5 additions & 5 deletions grails-app/conf/BootStrap.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ class BootStrap {
shipments.each { shipment ->
println "Assigning identifier to " + shipment.id + " " + shipment.name
shipment.shipmentNumber = productService.generateIdentifier("NNNLLL")
if (!shipment.save(flush:true)) {
if (!shipment.save(flush:true,validate:false)) {
println shipment.errors
}
}
Expand All @@ -253,7 +253,7 @@ class BootStrap {
requisitions.each { requisition ->
println "Assigning identifier to " + requisition.id + " " + requisition.name
requisition.requestNumber = productService.generateIdentifier("NNNLLL")
if (!requisition.save(flush:true)) {
if (!requisition.save(flush:true,validate:false)) {
println requisition.errors
}
}
Expand All @@ -264,7 +264,7 @@ class BootStrap {
orders.each { order ->
println "Assigning identifier to " + order.id + " " + order.name
order.orderNumber = productService.generateIdentifier("NNNLLL")
if (!order.save(flush:true)) {
if (!order.save(flush:true,validate:false)) {
println order.errors
}
}
Expand All @@ -274,7 +274,7 @@ class BootStrap {
transactions.each { transaction ->
println "Assigning identifier to " + transaction.id
transaction.transactionNumber = productService.generateIdentifier("AAA-AAA-AAA")
if (!transaction.save(flush:true)) {
if (!transaction.save(flush:true,validate:false)) {
println transaction.errors
}
}
Expand All @@ -286,7 +286,7 @@ class BootStrap {
products.each { product ->
println "Assigning identifier to " + product.id + " " + product.name
product.productCode = productService.generateIdentifier("LLNN")
if (!product.save(flush:true)) {
if (!product.save(flush:true,validate:false)) {
println product.errors
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,17 @@ class InventoryController {
[ transactions: transactions, transactionsByDate: transactionsByDate, dateSelected: dateSelected ]
}

/*
def listLowStock = {
def warehouse = Location.get(session.warehouse.id)
def categorySelected = (params.category) ? Category.get(params.category) : null;
def lowStock = inventoryService.getLowStock(warehouse);
def quantityMap = inventoryService.getQuantityForInventory(warehouse.inventory)
[inventoryItems:lowStock, quantityMap:quantityMap]
}
*/

def listExpiredStock = {
def warehouse = Location.get(session.warehouse.id)
Expand All @@ -334,15 +345,15 @@ class InventoryController {


def listExpiringStock = {
def threshhold = (params.threshhold) ? params.threshhold as int : 0;
def threshold = (params.threshold) ? params.threshold as int : 0;
def category = (params.category) ? Category.get(params.category) : null;
def location = Location.get(session.warehouse.id)
def expiringStock = inventoryService.getExpiringStock(category, location, threshhold)
def expiringStock = inventoryService.getExpiringStock(category, location, threshold)
def categories = expiringStock?.collect { it?.product?.category }?.unique().sort { it.name } ;
def quantityMap = inventoryService.getQuantityForInventory(location.inventory)

[inventoryItems:expiringStock, quantityMap:quantityMap, categories:categories,
categorySelected:category, threshholdSelected:threshhold ]
categorySelected:category, thresholdSelected:threshold ]
}

def listLowStock = {
Expand Down Expand Up @@ -372,6 +383,34 @@ class InventoryController {
categories: categories, categorySelected: categorySelected, showUnsupportedProducts: params.showUnsupportedProducts, inventoryLevelByProduct: inventoryLevelByProduct]
}

def listReorderStock = {
def warehouse = Location.get(session.warehouse.id)
def results = inventoryService.getProductsBelowMinimumAndReorderQuantities(warehouse.inventory, params.showUnsupportedProducts ? true : false)

Map inventoryLevelByProduct = new HashMap();
inventoryService.getInventoryLevelsByInventory(warehouse.inventory).each {
inventoryLevelByProduct.put(it.product, it);
}

// Set of categories that we can filter by
def categories = [] as Set
categories.addAll(results['reorderProductsQuantityMap']?.keySet().collect { it.category })
categories.addAll(results['minimumProductsQuantityMap']?.keySet().collect { it.category })
categories = categories.findAll { it != null }

// poor man's filter
def categorySelected = (params.category) ? Category.get(params.category) : null;
log.debug "categorySelected: " + categorySelected
if (categorySelected) {
results['reorderProductsQuantityMap'] = results['reorderProductsQuantityMap'].findAll { it.key?.category == categorySelected }
results['minimumProductsQuantityMap'] = results['minimumProductsQuantityMap'].findAll { it.key?.category == categorySelected }
}

[reorderProductsQuantityMap: results['reorderProductsQuantityMap'], minimumProductsQuantityMap: results['minimumProductsQuantityMap'],
categories: categories, categorySelected: categorySelected, showUnsupportedProducts: params.showUnsupportedProducts, inventoryLevelByProduct: inventoryLevelByProduct]
}


def searchRecall = {

log.info "searchRecall " + params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import com.google.zxing.BarcodeFormat;
import java.net.URLEncoder;

import grails.converters.XML;
import grails.validation.ValidationException;

class ProductController {

Expand Down Expand Up @@ -164,7 +165,9 @@ class ProductController {

def productInstance = new Product();
productInstance.properties = params

if (!productInstance.productCode) {
productInstance.productCode = productService.generateProductIdentifier();
}
// Add tags
try {
if (params.tagsToBeAdded) {
Expand Down Expand Up @@ -261,6 +264,20 @@ class ProductController {
}
productInstance.properties = params

if (!productInstance.productCode) {
productInstance.productCode = productService.generateProductIdentifier();
}
/*
try {
productService.saveProduct(productInstance)
}
catch (ValidationException e) {
productInstance = Product.read(params.id)
productInstance.errors = e.errors
render view: "edit", model: [productInstance:productInstance]
}
*/

Map existingAtts = new HashMap();
productInstance.attributes.each() {
existingAtts.put(it.attribute.id, it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import org.pih.warehouse.inventory.Transaction;
class DashboardController {

def orderService
def shipmentService;
def shipmentService
def inventoryService
def productService


Expand All @@ -37,11 +38,25 @@ class DashboardController {
def transaction = Transaction.findByTransactionNumber(params.searchTerms)
if (transaction) {
redirect(controller: "inventory", action: "showTransaction", id: transaction.id)
return;
}

def product = Product.findByProductCodeOrId(params.searchTerms, params.searchTerms)
if (product) {
redirect(controller: "inventoryItem", action: "showStockCard", id: product.id)
return;
}

def requisition = Requisition.findByRequestNumber(params.searchTerms)
if (requisition) {
redirect(controller: "requisition", action: "show", id: requisition.id)
return;
}

def shipment = Shipment.findByShipmentNumber(params.searchTerms)
if (shipment) {
redirect(controller: "shipment", action: "showDetails", id: shipment.id)
return;
}

redirect(controller: "inventory", action: "browse", params:params)
Expand All @@ -65,6 +80,15 @@ class DashboardController {
def allOutgoingShipments = shipmentService.getShipmentsByOrigin(location)
def allIncomingShipments = shipmentService.getShipmentsByDestination(location)

def expiredStock = inventoryService.getExpiredStock(null, location)
def expiringStockWithin30Days = inventoryService.getExpiringStock(null, location, 30)
def expiringStockWithin90Days = inventoryService.getExpiringStock(null, location, 90)
def expiringStockWithin180Days = inventoryService.getExpiringStock(null, location, 180)
def expiringStockWithin365Days = inventoryService.getExpiringStock(null, location, 365)
def lowStock = inventoryService.getLowStock(location)
def reorderStock = inventoryService.getReorderStock(location)


def activityList = []
def shipments = Shipment.executeQuery( "select distinct s from Shipment s where s.lastUpdated >= :lastUpdated and \
(s.origin = :origin or s.destination = :destination)", ['lastUpdated':new Date()-daysToInclude, 'origin':location, 'destination':location], [max: 10] );
Expand Down Expand Up @@ -181,6 +205,13 @@ class DashboardController {
allIncomingShipments : allIncomingShipments,
outgoingOrders : outgoingOrders,
incomingOrders : incomingOrders,
expiredStock : expiredStock,
expiringStockWithin30Days : expiringStockWithin30Days,
expiringStockWithin90Days : expiringStockWithin90Days,
expiringStockWithin180Days : expiringStockWithin180Days,
expiringStockWithin365Days : expiringStockWithin365Days,
lowStock: lowStock,
reorderStock: reorderStock,
rootCategory : productService.getRootCategory(),
outgoingOrdersByStatus: orderService.getOrdersByStatus(outgoingOrders),
incomingOrdersByStatus: orderService.getOrdersByStatus(incomingOrders),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,25 @@ class InventoryItem implements Serializable {
]
}


@Override
String toString() { return "${lotNumber}:${expirationDate}"; }

@Override
int hashCode() {
if (this.id != null) {
return this.id.hashCode();
}
return super.hashCode();
}

@Override
boolean equals(Object o) {
if (o instanceof InventoryItem) {
InventoryItem that = (InventoryItem)o;
return this.id == that.id;
}
return false;
}


}
8 changes: 7 additions & 1 deletion grails-app/domain/org/pih/warehouse/product/Product.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class Product implements Comparable, Serializable {
User updatedBy


static transients = ["rootCategory", "images", "genericProduct", "thumbnail"];
static transients = ["rootCategory", "images", "genericProduct", "thumbnail", "binLocation"];

static hasMany = [
categories : Category,
Expand Down Expand Up @@ -265,6 +265,12 @@ class Product implements Comparable, Serializable {
return this?.productGroups?this?.productGroups?.sort()?.first():null
}

InventoryLevel getInventoryLevel(locationId) {
def location = Location.get(locationId)
return InventoryLevel.findByProductAndInventory(this, location.inventory)
}


String toString() { return "$name"; }

/**
Expand Down
Loading

0 comments on commit 3c7eb8e

Please sign in to comment.