Most Powerful Open Source ERP

ERP5 How To Migrate Form Fields To Proxy Fields

Describing the conceptual steps of converting form fields into proxy fields.
  • Last Update:2017-03-20
  • Version:001
  • Language:en

This How To describes the approach to proxify form fields to keep customisation to a minimum by reusing existing field libraries. From Guidelines on Module Creation.

What Is A Field Library

Field library is an ERP5 form which will not be accessed from users but used as a container of proxy fields used as template field by other fields contained in other real forms and reports. In other words, it is a collection of template fields of proxy fields commonly used in a business template.

Why Differentiate Field Library And Proxy Field?

Using proxy field is very useful for providing consistent UI and reducing code duplications.

For UI

For example, comment field is one of the very common fields in whole ERP5 system and it should be always the same size everywhere. Then we use proxy field, we can define the height and width only once to the template field in the core field library and the remaining is that all other comment fields just inherit the core template field. This way, we can make consistent UI easily. If we did not use proxy field, we had to set the same height and width for all comment fields one by one, this is very hard to maintain.

About field library, this is a kind of buffer between the core field library in erp5_core and the real fields to be displayed to users. We saw an example of comment field above, it was a common field globally. But sometimes we want to change an appearance of generic fields only in some business template. In such case, we cannot change the core template fields, because they are used globally. So we can change a field library of a target business template instead. Then we can customize some fields only in a business template and this does not affect UIs defined by other business templates.

For code reuse/abstraction

Sometimes we can find similar patterns in ERP5. For example, when we use a RelationStringField, we often name it like "my_source_title" by following our naming convention. And from such names, we can find a pattern. The name suggests this field uses source category and searches document by title. And we can make a template field for RelationStringField and put a tales expression to parse field id and find category name and index property. Once we have such a template field which is an abstraction of a pattern we don't have to enter a category name and an index property name each time when adding RelationStringField, but just using a proxy field and inherit the template field is enough. We can omit entering various parameters and it is also useful for maintenance, future changes. Above is a very wide range example which can apply whole ERP5, but we can find many other small patterns in a specific context managed by single business template like Accounting, DMS. Therefore finding a pattern and making a template field is very practical use case of proxy field and field library.

Define once and applying to many

Sometimes we have to enter the same information in multiple places. For example, a company has the same reference naming rule for Service and Product. In such case, we have to apply the same input validation functionality to Product_view.my_reference and Service_view.my_reference. Then we can say that both my_reference in Product_view and Service_view are the same in reality. In such case, we should make a template field in field library and reuse the field to inherit from proxy fields in both Product_view nd Service_view. And in this way even if the input validation rule was changed, we only have to update the template field and no need to touch proxy fields.

How To Use The Proxify Tool To Migrate Existing Business Templates To Proxy Fields

This section describes the procedure that has been used to convert erp5_base business template to use proxy fields. The goal is to have configuration bits shared by multiple fields defined in only one place.

Think How To Group Fields In Field Libraries

Look at existing document types and find out what information is shared by those documents. For example, Organisations, Person both share the concept of geographical address, which is the fields city, postal code or region. Those fields are also used by Address portal type itself.

Create Conceptual Field Libraries

In our address example, you should create a field library named Address_viewFieldLibrary, containing fields like my_city or my_region. Fields in the field library will be proxyfields to level 0 fields, from Base_viewFieldLibrary, which defines the default look of the fields.

For this you should use fields from existing business forms as a starting point, for example, you can copy and paste Address_view/my_city as Address_viewFieldLibrary/my_city and then use proxify tool on Address_viewFieldLibrary to make my_city a proxyfield of the default string field from Base_viewFieldLibrary.

Fields in those "conceptual" field libraries must usually define title and description.

Use Field Libraries

Replace all fields in your business forms by fields from conceptual field library you just created. For this you should also use the proxify tool. Fields in those forms (like Organisation_view) should delegate almost all their values, especially title and description which must be defined in only one place. The proxify tool doesn't delegate values that are differents from the original field than the target relation field.

For rare cases where the field is not shared by any other forms, you can make a proxyfield directly to the first level field from Base_viewFieldLibrary.

Check The Result

The important rule is that your proxyfields must delegate everything possible. Everytime a value is NOT delagated, it's an exception, and it should have an explanation. You can use this code to display all non delegated values:

print '<html>'
skin_folder = context.getPortalObject().portal_skins.erp5_base # <- XXX configure this

for field_id, field in skin_folder.ZopeFind(skin_folder, search_sub=1, obj_metatypes=('ProxyField',)):
  form = field.aq_parent
  if form.getId().endswith('FieldLibrary'):
    continue

field_path = '%s/%s' % (form.getId(), field.getId())
print '<a href="%s/%s/manage_main">%s</a><br/>' % (skin_folder.absolute_url(), field_path, field_path)

tf = field.getRecursiveTemplateField()
for v in tf.values:
  if not field.is_delegated(v):
    print "  %s<br/>" % v
    print

return printed