Book Image

Apache OfBiz Cookbook

Book Image

Apache OfBiz Cookbook

Overview of this book

Apache Open For Business (OFBiz) is an enterprise resource planning (ERP) system that provides a common data model and an extensive set of business processes. But without proper guidance on developing performance-critical applications, it is easy to make the wrong design and technology decisions. The power and promise of Apache OFBiz is comprehensively revealed in a collection of self-contained, quick, practical recipes in this Cookbook. This book covers a range of topics from initial system setup to web application and HTML page creation, Java development, and data maintenance tasks. Focusing on a series of the most commonly performed OFBiz tasks, it provides clear, cogent, and easy-to-follow instructions designed to make the most of your OFBiz experience. Let this book be your guide to enhancing your OFBiz productivity by saving you valuable time. Written specifically to give clear and straightforward answers to the most commonly asked OFBiz questions, this compendium of OFBiz recipes will show you everything you need to know to get things done in OFBiz. Whether you are new to OFBiz or an old pro, you are sure to find many useful hints and handy tips here. Topics range from getting started to configuration and system setup, security and database management through the final stages of developing and testing new OFBiz applications.
Table of Contents (15 chapters)
Apache OFBiz Cookbook
Credits
About the Author
About the Reviewers
Preface

Putting it all together with a data model example


Since OFBiz comes with over 900 entities and a ready-made database schema defining the relationships of those entities to one another, we would be hard pressed to find a business situation where the existing data model doesn't meet most of our needs. The OFBiz data model includes entities and entity relationship definitions for everything from managing users, whether they be customers, suppliers, vendors, or the system administrator, to selling products and controlling inventory, handling accounting, creating invoices, and even modeling complex workflow scenarios.

Since the goal of this section is to take you from the conception of a new business idea through an implementation using Entity Engine tools and techniques, we shall not use existing entities, but rather devise a new data model. With a little bit of research, we have come up with a use case that is not directly supported by the existing data model. To illustrate how to create new entities and view-entities, read, write, and remove data from an OFBiz data source, we are going to model the business of a bakery.

Sample use case

As a bakery, we manufacture edible products based on recipes mom brought over from the old country. There are many different types of recipes in our collection, including, but not limited to cakes, cookies, pies, bread, and for those dog lovers, dog treats. We should note here that the number of different types of recipes, and thus the goods we plan to bake using these recipes, should remain open ended and not be limited to the initial five identified.

Within each recipe is a sequential list of ingredients. Each ingredient has a value that represents the amount of the ingredient to use in the recipe and a unit of measure indicator. For example, a recipe may have an ingredient of flour, with an amount of "5" and a unit of measure of "cup". To keep things simple, we shall not consider the list of ingredients as steps in the mixing and/or baking process.

Note

Note: the existing data model does support a process-oriented business operation such as a bakery. We have chosen to ignore certain existing data model entities in favor of going at it alone and doing it ourselves, primarily as a vehicle to demonstrate the versatility of the OFBiz Entity Engine. You are free to use existing entities such as "Product", "ProductConfig", and "ProductConfigItem" to model recipes.

Entity diagram

The data model for our additions to OFBiz are graphically depicted in the following figure. We will be adding four new entities: Recipe, Ingredient, RecipeType, and RecipeIngredient, each with primary and foreign keys shown here:

In addition to the four new entities shown in the figure, we shall use the existing Uom entity to give our ingredients access to several hundred standardized units of measure (UOM) values already preloaded in the database.

New entity definitions

Based on our business case and data model, we need to create five new entities. Definitions for each of these entities are shown below. We may either create a new entity definition file and update the component.xml file with the new entity definition file location, or add these entities to an existing entity definition file. In the interest of time, we shall add these to an existing entity definition file.

In the following entity definitions, notice that we use a package name of org.ofbiz.bakery. We are using this name specifically so that we may easily find our entities when using the WebTools Interactive Entity Reference utility. As this tool groups together like-named packages, finding a particular entity is made much easier when using a meaningful package name.

The following defines the Ingredient entity:

<entity entity-name="Ingredient"
package-name="org.ofbiz.bakery"
title=
"One record for each ingredient that makes up a recipe">
<field name="ingredientId" type="id-ne"></field>
<field name="ingredientName" type="id"></field>
<!-- Note: some day make an IngredientType entity -->
<field name="ingredientType" type="id"></field>
<field name="packagingUomId" type="id"></field>
<prim-key field="ingredientId"/>
<relation type="one" fk-name="REC_ING_UOM" rel-entity-name="Uom">
<key-map field-name="packagingUomId" rel-field-name="uomId"/>
</relation>
</entity>

The RecipeType entity that holds information about the type of recipe (cookies, cakes and so on) may be defined as follows:

<entity entity-name="RecipeType"
package-name="org.ofbiz.bakery"
title=
"Recipes come in all shapes and sizes. Keep that info here.">
<field name="recipeTypeId" type="id-ne"></field>
<field name="description" type="description"></field>
<prim-key field="recipeTypeId"/>
</entity>

A Recipe entity with the unique recipe identifier, a recipe name, and pointers to other related entities (foreign keys) is given here:

<entity entity-name="Recipe"
package-name="org.ofbiz.bakery"
title="Recipe holds information about our recipes">
<field name="recipeId" type="id-ne"></field>
<field name="recipeName" type="id-long"></field>
<field name="recipeTypeId" type="id"></field>
<field name="notes" type="very-long"></field>
<prim-key field="recipeId"/>
<relation type="one" fk-name="REC_TO_TYPE"
rel-entity-name="RecipeType">
<key-map field-name="recipeTypeId"/>
</relation>
</entity>

And finally, the entity that ties the recipe with its ingredients is defined here:

<entity entity-name="RecipeIngredient"
package-name="org.ofbiz.bakery"
title=
"A recipe is nothing more than a collection of ingredients.
Here's where the rubber meets the road.">
<field name="recipeId" type="id-ne"></field>
<field name="recipeSeqNo" type="numeric"></field>
<field name="ingredientId" type="id-ne"></field>
<field name="amountUomId" type="id"></field>
<field name="amount" type="numeric"></field>
<field name="fromDate" type="date-time"></field>
<field name="thruDate" type="date-time"></field>
<prim-key field="recipeId"/>
<prim-key field="recipeSeqNumber"/>
<prim-key field="fromDate"/>
<relation type="one" fk-name="REC_ING_ING"
rel-entity-name="Ingredient">
<key-map field-name="ingredientId"/>
</relation>
<relation type="one" fk-name="REC_AMT_UOM" rel-entity-name="Uom">
<key-map field-name="amountUomId" rel-field-name="uomId"/>
</relation>
</entity>

Once all our new entity definitions are created, the next task is to test these entities to ensure accuracy. An easy and reliable way to begin testing is to first see if the entities are present and viewable using the OFBiz WebTools Entity Reference - Interactive Version. To run this test, restart OFBiz, making sure that no obvious entity-related errors are posted to the command-line window and/or primary OFBiz log file (ofbiz/runtime/ofbiz.log). If errors are encountered during startup, we need to go back and fix our entity definitions.

If OFBiz startup is successful, we may navigate to the WebTools Entity Reference - Interactive Version main web page, and since our new entities were created using the package name org.ofbiz.bakery, we may easily scroll down the left side of the web page to locate our package name and link as shown in the following figure:

Note

If you find that your entities are not showing up here, then go back and check each entity definition and or the logfiles. Most definition syntax errors are reported to ~runtime/logs/ofbiz.log during OFBiz startup.

From the WebTools Entity Reference - Interactive Version, we may test adding data to our new entities. And so we would, but to speed things up a bit, we shall use the WebTools XML Data Import tool to load data a little at a time—so we can view results—from XML documents that we created offline. For example, here we add data to the RecipeType entity by copying from a text file and then pasting in the XML Import to DataSource tool's HTML form:

To verify that our data is indeed added to the database, use WebTools and list the RecipeType entity as shown here:

So, it looks like we are on the right track with our entity definitions. In the real world, we would be writing an OFBiz webapp to allow for HTML form-based data entry in addition to loading data directly into the database. For the rest of this chapter, we shall assume that the following data has been preloaded:

Entity name: Ingredient

  

ingredientId

ingredientName

packagingUomId

10009

eggs

OTH_ea

10001

milk

OTH_ea

10002

pure water

OTH_ea

10003

city water

OTH_ea

10004

wheat flour

OTH_ea

10005

organic wheat flour

OTH_ea

10006

salt

OTH_ea

Entity name: Recipe

   

recipeId

recipeName

recipeTypeId*

notes

r001

Moms Doggie Delights

dogbiscuits

This one goes way back.

r002

Dont try this one at home!

bread

Same ole stuff but you gotta have it.

r003

Going Nuts, Nut Bread For…

bread

This one goes way back (too).

r004

Moms Goes Green

bread

Green, Healthy Bread. Has spinach to boot!

Entity name: RecipeIngredient

     

recipeId

recipeSeqNo

ingredientId*

amountUomId*

amount

fromDate

r001

001

10001

 

1

**

r001

002

10010

VLIQ_qt

 

**

r001

003

10005

VLIQ_pt

 

**

r001

004

10002

VLIQ_tsp

 

**

* Because this field is designated as a foreign key, any values added must already exist in the related table.

** fromDate set to "2010-01-01 00:00:00.000" for all records.

2-way SQL join view-entity

A report we want to produce quickly after going live with our new OFBiz bakery and recipe system is a list of all the recipes by type. For example, a list of all the cookie recipes. To create such a list using our existing data model requires that we access more than one entity. To do that, that is, join together data from multiple entities, we create an OFBiz view-entity.

Our first view-entity will merge together data from the RecipeType and Recipe entity as shown here:

<view-entity entity-name="RecipeTypeView"
package-name="org.ofbiz.bakery"
title="Show all recipes by type">
<member-entity entity-alias="REC" entity-name="Recipe"/>
<member-entity entity-alias="TYP" entity-name="RecipeType"/>
<alias-all entity-alias="REC"/>
<alias-all entity-alias="TYP"/>
<view-link entity-alias="REC" rel-entity-alias="TYP">
<key-map field-name="recipeTypeId"
rel-field-name="recipeTypeId"/>
</view-link>
</view-entity>

3-way SQL join view-entity

Not one to gloat over our success so far using the Entity Engine, the next report will draw from three different tables to list all the recipes with ingredients, by type:

<view-entity entity-name="RecipeTypeAndIngredientsView"
package-name="org.ofbiz.bakery"
title="Show all recipes by type">
<member-entity entity-alias="REC" entity-name="Recipe"/>
<member-entity entity-alias="TYP" entity-name="RecipeType"/>
<member-entity entity-alias="REIN" entity-name="RecipeIngredient"/>
<alias-all entity-alias="REC"/>
<alias-all entity-alias="TYP"/>
<alias-all entity-alias="REIN"/>
<view-link entity-alias="REC" rel-entity-alias="TYP">
<key-map field-name="recipeTypeId"
rel-field-name="recipeTypeId"/>
</view-link>
<!-- Note the order of entity-alias here is important.
Each Recipe record points to one or more
RecipeIngredient records -->
<view-link entity-alias="REC" rel-entity-alias="REIN">
<key-map field-name="recipeId" />
</view-link>
<relation type="many" rel-entity-name="RecipeIngredient">
<key-map field-name="recipeId"/>
</relation>
</view-entity>

Note

Writing view-entities is even easier than writing regular entities. Unlike regular entities, where changes to field type definitions or the addition/removal of fields usually requires that you first drop the database table, if you make a mistake with a view-entity, you only need to edit the view-entity definition and restart OFBiz. View-entities are not created or stored as part of the database. Rather, they are used, on demand, to create entity SQL based joins.

View-entity reports

With the view-entities in place, we can easily query the database without constructing complex SQL statements. To test that our new view-entities are doing the job, we can use the OFBiz WebTools Entity Reference - Interactive Version to run a quick report as shown here:

Next steps

That's it. That is how easy it is to augment OFBiz to support additional application data storage needs. Your experiences will be informed by how complex your data model becomes. With OFBiz, you can have your cake and eat it too. You can start by developing a simple prototype as shown in this section, and grow your data management capabilities as your business grows. You can even move your entire database from vendor-to-vendor (tired of Oracle? Ccheckout PostgreSQL, SQL Server, mySQL or just about any database imaginable) without changing a single line of code.

In the next few sections, we shall take a closer look at using some Java application-level tools provided by OFBiz to implement data-driven applications programmatically.