Showing posts with label Grails. Show all posts
Showing posts with label Grails. Show all posts

Wednesday, January 13, 2010

Creating a Groovy DSL for Financial Product Fee Schedules


I'm currently working on a project that requires a variable fee schedule.
E.g.

Product Name Category Feature Value Date Range Functional Setting Applicability
General ACH Generation






ACH Generation Fees ACH Transaction Fee 1.00 Account Open Date Account Closed Date 0 to 10 transactions


ACH Transaction Fee .50 Account Open Date Account Closed Date 10 or more transactions

Credit Card Generation Fees CC Transaction Fee 1.00 Account Open Date Account Closed Date 0 to 10 transactions


CC Transaction Fee .50 Account Open Date Account Closed Date 10 or more transactions

I need a way to specify the date range that would include things such as account open date and plus 3 months and transaction ranges. Groovy DSL seems like the perfect fit. See Guillame Laforge's example here.

I came up with the following:

package com.aps.utils

import com.aps.util.DateUtil
import org.codehaus.groovy.runtime.TimeCategory


class ProductCatalogDSLTests extends GroovyTestCase {


def account

void setUp() {
account = new Account(from: DateUtil.sdf.parse("01-01-2010"))
}

void testAccountOpenedDate() {
def rule = 'transactionDate > account.from'
def binding = new Binding()
binding.account = account
def shell = new GroovyShell(binding)
def date = DateUtil.sdf.parse('01-10-2010')
binding.transactionDate = date
assert shell.evaluate(rule)
binding.transactionDate = DateUtil.sdf.parse('05-10-2009')
assertFalse shell.evaluate(rule)

}

void testAccountOpenedDate_plus3() {
def rule = 'transactionDate < account.from+6.months'
def binding = new Binding()
binding.account = account
def shell = new GroovyShell(binding)
def date = DateUtil.sdf.parse('01-10-2010')
binding.transactionDate = date
use(TimeCategory) {
assert shell.evaluate(rule)
binding.transactionDate = DateUtil.sdf.parse('05-10-2010')
assert shell.evaluate(rule)
}
}

void testTransactionMinimum() {
def rule1 = 'account.transactions.size < 10'
def rule2 = 'account.transactions.size >= 10'
def date = DateUtil.sdf.parse('01-10-2010')
0..5.each {
account.transactions << new AccountTransaction(amount: 15.00, postDate: date)
}
def binding = new Binding()
binding.account = account
def shell = new GroovyShell(binding)
binding.transactionDate = date
use(TimeCategory) {
assert shell.evaluate(rule1)
assertFalse shell.evaluate(rule2)
}
}

void testTransactionMinimumThisMonth() {
def rule1 = 'account.transactions.collect{it.postDate.month == transactionDate.month}.size < 10'
def rule2 = 'account.transactions.collect{it.postDate.month == transactionDate.month}.size >= 10'
def date = DateUtil.sdf.parse('01-10-2010')
use(TimeCategory) {
assertEquals 0 , date.month
assertEquals 10 , date.date
assertEquals 2010 - 1900 , date.year
0..5.each {
account.transactions << new AccountTransaction(amount: 15.00, postDate: date)
}
def binding = new Binding()
binding.account = account
def shell = new GroovyShell(binding)
binding.transactionDate = date
assert shell.evaluate(rule1)
assertFalse shell.evaluate(rule2)
}
}
}
class Account {
Date from
Date to
def transactions = []
}
class AccountTransaction {
BigDecimal amount
Date postDate
}

It ended up working well for dynamic business rule selectors.

Tuesday, July 7, 2009

Using GraphViz to automatically Diagram your Grails Domain Model



I'm working on a feature that automatically diagrams the Domain model stored in Grails, similar to the method prototyped by the Curious Bunny here. His example works pretty well for a simple model, but begins to break down due to a seeming Grails limitation.

In my model, I have a Party, Organization and Company class. Company extends Organization, Organization extends Party.
Party <--- Organization < --- Company Inside of my Controller that produces the Graph, I iterate through a classes subclasses like so:

domainClass.subClasses.each {subClass ->
out.println """"$domainClass.name" -> "$subClass.name" """
}

This works ok, but when this is run on Company, both Party and Organization are in the set. In a UML diagram, I don't really want both of them, I only want one of them. I.e. it produces a diagram that is more cluttered than it needs to be.

This diagram represents a simplified subset of my domain, based off the Party Pattern Archetype in the book: Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML

Notice the redundant inheritance.

Anybody know how to only get direct subclasses, instead of recursive subclasses?