1. Introduction

GR8 CRM is a set of Grails Web Application Framework plugins that makes it easy to develop web applications with CRM functionality.

You can find more information about GR8 CRM on the main documentation site http://gr8crm.github.io.

1.1. Customer Relationship Management

Customer relationship management (CRM) is a system for managing a company’s interactions with current and future customers. It involves using technology to organize, automate and synchronize sales, marketing, customer service, and technical support. Wikipedia

The GR8 CRM "Ecosystem" currently contains over 40 Grails plugins. For a complete list of plugins see http://gr8crm.github.io.

Each GR8 CRM plugin defines a Bounded Context that focus on one specific domain, for example contact, project or document.

2. Product Management Plugin

This plugin provide storage and services for managing products in GR8 CRM applications. A product is an item that you sell or have in your inventory. A product have properties like identification number, name, description and product group. The following features are supported by the crm-product plugin.

  • Multiple prices, specified by price lists

  • Staggered prices

  • Product compositions (includes, replaces, equivalent, etc.)

  • Attachments (images, brochures) if combined with the crm-content plugin

  • Reference to product suppliers if combined with the crm-contact plugin

Note that this plugin does not contain any user interface components. This plugin contains domain classes and services only. The plugin crm-product-ui provides a Twitter Bootstrap based user interface for managing products and price lists. crm-product-ui depends on crm-product so you only need to include crm-product-ui in your BuildConfig.groovy if you want end-user product management features.

3. Domain Model

Product Management Domain Model

3.1. CrmProduct

Property Type Description



Product ID / Item Number



Secondary Item Number



Product name



Secondary product name, typically displayed in web shop or catalogues



A longer description of the product (max 2000 characters)



The supplier’s item number



Supplier identity (primary key), if supplier exists as a CrmContact



Name of the product’s supplier



Product group



The product’s bar code



The product’s customs code



The product’s weight



Flag that tells if the product is enabled/active or disabled

4. CrmProductService

Like most other GR8 CRM plugins this plugin have a main service with methods for creating, searching and updating products.

4.1. Create a product group

CrmProductGroup createProductGroup(Map params, boolean save = false)

A product belongs to a product group. Product groups can be created with createProductGroup().

4.2. Create a price list

CrmPriceList createPriceList(Map params, boolean save = false)

A product can have multiple prices. Each product price references a price list. A price list can be created with a call to createPriceList().

4.3. Create a new product

CrmProduct createProduct(Map params, boolean save = false)

To create a product you call the createProduct method with a map of property values.

def hardware = crmProductService.createProductGroup(name: "Hardware", true)
def std = crmProductService.createPriceList(param: 'standard', name: 'Standard price list', true)
def product = crmProductService.createProduct(number: "USB18", name: "USB Cable 1.8 meter", group: hardware, true)
product.addToPrices(priceList: std, unit: 'pcs', outPrice: 6.99, vat: 0.20)
println "The price for $product is €${product.price} excl. VAT"

4.4. Search for products

As usual in GR8 CRM plugins the main service has a list() method that performs a query.

The list() method is @Selectable which means you can use the selection plugin to query for products.

def list(Map query, Map params)

To search for products you initialize the query map with query values. With the params map you can specify things like sort order and pagination. The following query keys can be used in the query map.

Key Description Type


Product number

String (wildcard supported)


Product name

String (wildcard supported)


Product group

String (wildcard supported)


Name of supplier

String (wildcard supported)


Supplier’s item number

String (wildcard supported)


Bar code

String (wildcard supported)


Customs code

String (wildcard supported)





Product price





The following example will find all enabled products in the hardware product group that has usb in the product name. As you can see you can combine several query values when you search for domain instances.

def result = crmProductService.list([group: 'hardware', name: '*usb*', enabled: true], [:])
println "Found ${result.size()} USB products"

4.5. Product price

Double getPrice(String productNumber, Integer amount = null, Object priceList = null, String unit = null)

Because a product can have many prices depending on different price lists or how many items you want to buy, retrieving the product price can be complicated. However there is a price property on CrmProduct that makes it easier. The price property returns the first available price on the product instance. This works well if you only have one price per product. If you have multiple prices per product you can use CrmProduct#getPrice(...) with optional parameters or use CrmProductService#getPrice(...).

CrmProductService#getPrice() parameters

  • productNumber Product number to get price for

  • amount Amount to base price on

  • priceList CrmPriceList instance or CrmPriceList.param string

  • unit unit to get price for

def pc = crmProductService.createProductGroup(name: "PC", true)
def priceList = crmProductService.createPriceList(param: "b2b", name: "Small Businesses", true)
def p = crmProductService.createProduct(number: "dellxps15", name: "Dell XPS 15\"", group: pc)

p.addToPrices(priceList: priceList, unit: 'pcs', fromAmount: 1, inPrice: 0, outPrice: 1299.99, vat: 0.20)
p.addToPrices(priceList: priceList, unit: 'pcs', fromAmount: 10, inPrice: 0, outPrice: 1199.99, vat: 0.20)
p.addToPrices(priceList: priceList, unit: 'pcs', fromAmount: 100, inPrice: 0, outPrice: 999.99, vat: 0.20)

p.save(flush: true)

assert crmProductService.getPrice("dellxps15") == 1299.99
assert crmProductService.getPrice("dellxps15", 1) == 1299.99
assert crmProductService.getPrice("dellxps15", 5) == 1299.99
assert crmProductService.getPrice("dellxps15", 15) == 1199.99
assert crmProductService.getPrice("dellxps15", 50) == 1199.99
assert crmProductService.getPrice("dellxps15", 150) == 999.99

4.6. Delete a product

String deleteProduct(CrmProduct crmProduct)

A product can be deleted with a call to deleteProduct. If the operation succeeds the name of the deleted product will be returned. Otherwise an exception will be thrown.

Before the product is deleted the crmProduct.delete event will be sent and after the deletion crmProduct.deleted will be sent.

5. Changes


Plugin upgraded to Grails 2.4.5


First version to support Grails 2.4.x


Fixed cascading problem when deleting a product with relations


First public release

6. License

This plugin is licensed with Apache License version 2.0

7. Source Code

The source code for this plugin is available at https://github.com/goeh/grails-crm-product

8. Contributing

Please report issues or suggestions.

Want to improve the plugin: Fork the repository and send a pull request.