ERP5: Designing for Maximum Adaptability > The Underlying Zope Platform

21.3. The Underlying Zope Platform

To understand why ERP5 is said to be document-driven, it is necessary first to understand how Zope and its Content Management Framework (CMF) work. Zope was originally developed as a web content management environment that provides a series of services to manage the life cycle of web documents. With time, people started to note that it can be also used to implement any kind of web-based application.

In keeping with Zope's web content focus, its CMF is a framework that aims to speed the development of applications based on content types. It provides a series of services associated to these types, such as workflow, searching, security, design, and testing. From Zope, CMF inherits access to the ZODB (Zope Object Database), which provides transactions and undo functionality.

CMF implements the structural part of applications through CMF Types, maintained by the portal_types service, which is in turn a kind of registry tool for the recognized types of a given portal. The visible part of a portal type is a document that represents it. To implement behavior, portal types have actions associated with them, composing a workflow, which in turn is the implementation of a business process. An action on a document changes its state and is implemented by a Python script that realizes some business logic; for instance, calculating the total cost of an order. Given this framework, when developing an application in ERP5, we have to think in terms of documents that hold business process data and whose life cycles are kept by workflows, which implement the business process behavior.

To take advantage of the CMF structure, ERP5 code is divided into a four-level architecture that implements a chain of concept transformations, with configuration tasks at the highest level.

The first level comprises the five conceptual core classes. They have no code, only a skeleton, for the sake of simple documentation:

	class Movement:
	  """
	    Movement of a quantity of a resource in a given variation
	    from a source to a destination.
	  """

At the second level is the real core classes' implementation in Python. But here, they are still abstract classes. Still, there is already some Zope stuff in the classes, and they inherit from XMLObject, which means that every object can be serialized into XML for synchronization or exporting.

Class attributes are organized into property sheets. Property sheets are configurable sets of attributes that facilitate the creation of different object views, potentially manipulated by different sets of class methods. Moreover, these views allow system administrators to set up security in a very flexible and sophisticated way.

For instance, the SimpleItem sheet bears title, short_title, and description attributes. The system administrator can set a security scheme where some users can only view these attributes, while others can write to them:

	class Movement(XMLObject):
	  """
	    Movement of a quantity of a resource in a given variation
	    from a source to a destination.
	  """
	  # defines the name of the type
	  meta_type = 'ERP5 Movement'
	  # defines the CMF type name
	  portal_type = 'Movement'
	  # adds basic Zope security configuration
	  add_permission = Permissions.AddPortalContent
	  # the type is listed as a valid content type
	  isPortalContent = 1
	  # this type is enabled for ERP5 Rapid Application Development facilities
	  isRADContent = 1
	  # used for trade and inventory operations
	  isMovement = 1

	  # Declarative security
	         # stores basic class's security information
	  security = ClassSecurityInfo()
	         # as default, allows authenticated users to view the object
	  security.declareObjectProtected(Permissions.AccessContentsInformation)

	  # Declarative properties
	    property_sheets = ( PropertySheet.Base
	                    , PropertySheet.SimpleItem
	                    , PropertySheet.Amount
	                    , PropertySheet.Task
	                    , PropertySheet.Arrow
	                    , PropertySheet.Movement
	                    , PropertySheet.Price
	                    )


					    

The third level holds the Meta classes, which are instantiable classes. At this tier, classes already represent specific business entities:

	class  DeliveryLine(Movement):
	    """

	      A DeliveryLine object allows lines to be implemented in
	      Deliveries (packing list, order, invoice etc).
	      It may include a price (for insurance, for customs, for invoices,
	      for orders etc).
	    """

	    meta_type = 'ERP5 Delivery Line'
	    portal_type = 'Delivery Line'

	    # Declarative properties
	        # it is necessary the overload the property_sheets property
	        # inherited from Movement 
	    property_sheets = ( PropertySheet.Base
	                      , PropertySheet.XMLObject
	                      , PropertySheet.CategoryCore
	                      , PropertySheet.Amount
	                      , PropertySheet.Task
	                      , PropertySheet.Arrow
	                      , PropertySheet.Movement
	                      , PropertySheet.Price
	                      , PropertySheet.VariationRange
	                      , PropertySheet.ItemAggregation
	                      , PropertySheet.SortIndex
	                      )


					    

Finally, at the fourth level are the Portal classes, which are CMF-based. This is the level at which configuration takes place. For instance, Figure 21-2 shows the main part of the Properties tab. This screenshot shows, in particular, the properties of Task Report Line. This type is an implementation of the Delivery Line Meta type. It is interesting to note that new property sheets can be added at this tab, but they are not needed for our project tool.

Figure 21-2. Properties tab


Figure 21-3 shows the Actions tab, listing actions associated with the Task Report Line type. Actions implement specific services for this type. In the figure, you can see the View and Print services.

Figure 21-3. Actions tab


The four-level structure representing system classes makes it easy to add functionality and platform features incrementally. It also allows a practice that is very common in ERP5: implementing new portal types without creating new classes in the system. All the programmer has to do is change the appearance of one, because ERP5's core concepts can represent entities of specific business domains.

For instance, a Movement can be used to represent both a cash withdrawal in the finances module and a transference of material from the warehouse to the factory in the inventory module. To do so, we create one portal type to represent a cash withdrawal and another to represent a material transfer, each using the appropriate business terms that appear in the GUI.

Besides using basic CMF features, ERP5 also implements some extra features to enhance programming productivity. Perhaps the most interesting is the concept of relationship managers, which are objects responsible for keeping the relationships between pairs of objects. Coding relationship logic into each business class is often tedious and error-prone. Also, traditional relationship code spreads the implementation (back-pointers, deletion notifications, and so on) among many business classes, which is more difficult to track, maintain, and keep in sync than mediated approaches.

In ERP5, a portal service called Portal Categories records all the one-to-one, one-to-many, and many-to-many relationships between groups of related objects. Query methods, getters and setters, and relationship code are automatically generated.

This service holds base category objects, which connect classes that collaborate to carry out a given business process. For every base category, ERP5 automatically generates all necessary getters and setters. As an example, the base category source is a reference for objects of the Node type. If, in a given ERP5 implementation, the class Order is configured to have this base category, the system will automatically include all the methods and references necessary to navigate from orders to nodes, and vice versa if desired.