views:

123

answers:

2

I am creating an invoice management application using Grails, and am experiencing problems with inheritance.

If is my intention that each invoice should contain a collection of lines/items, and that when the invoice is formatted for printing, the items are sorted by date, separated into lists by category, then have the price of each line calculated in a different way for each concrete type (Timed items will lookup the hourly in the rates property, Priced items are assigned a price on creation).

Node Invoice has a property "items", which is a collection of Item objects.

Source of my domain classes:

class Invoice {
    static constraints = {
    }        
    String client

    Date dateCreated
    Date lastUpdated
    CostProfile rates

    def relatesToMany = [items : Item]
    Set items = new HashSet()
}

abstract class Item{
    static constraints = {
    }
    String description
    Date date
    enum category {SERVICE,GOODS,OTHER}
    def belongsTo = Invoice
    Invoice invoice
}

class TimedItem extends Item{

    static constraints = {
    }

    int minutes
}

class PricedItem extends Item{

    static constraints = {
    }

    BigDecimal cost
    BigDecimal taxrate
}

Source of the problematic code:

invoiceInstance.items.add(new TimedItem(description:"waffle", minutes:60, date:new Date(),category:"OTHER"))
def firstList = []
def lastList = []
invoiceInstance.items.sort{it.date}
invoiceInstance.items.each(){
    switch(((Item)it).category){
        case "LETTER":
            firstList.add(it)
        break;
        default:
            lastList.add(it)
    }
}

Error message:
groovy.lang.MissingPropertyException: No such property: category for class: TimedItem

Stacktrace indicates the 6th line of the above example.

A: 

Is there a reason you cast to Item? That seems unnecessary to me.

Snake
I was attempting to force it to find the "category" by explicitly telling it where to look!
Emyr
A: 

You are using enum wrong. The enum keyword is similar to the class keyword. So while you defined your enum type, you never gave your class an instance of it. While you could leave the definition of the enum inside the abstract Item class, I moved it outside for clarity.

class Invoice {
    Set items = new HashSet()
}

enum ItemCategory {SERVICE,GOODS,OTHER}

abstract class Item{
    String description
    ItemCategory category
}

class TimedItem extends Item{
    int minutes
}


def invoice = new Invoice()
invoice.items.add(new TimedItem(description:"waffle", minutes:60, category: ItemCategory.OTHER))

invoice.items.each(){
    switch(it.category){
        case ItemCategory.OTHER:
            println("Other found")
        break
        default:
            println("Default")
    }
}
Blacktiger
I've put the enum definition in grails-app/domain/ItemCategory.groovyOn line: invoice.items.add(new TimedItem(description:"waffle", minutes:60, category: ItemCategory.OTHER))I'm getting this: groovy.lang.MissingPropertyException: No such property: ItemCategory for class: InvoiceControllerDo I need some kind of import statement to access the magic values of ItemCategory?
Emyr
I believe that is correct. import a.package.ItemCategory
Blacktiger
OK, I haven't declared any packages in this app yet, do I need to add one just for this enum??
Emyr
As far as I can tell you will need to add packages. Java doesn't play well with classes declared in the default package. Maybe someone else knows how to get around that?
Blacktiger