Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Articles
Recherche: 

Multi-level cost calculation
Hilmar Zonneveld, November 1, 2006
A standard requirement in a production system, or in systems for cost calculation, is to add up all the raw materials for a number of finished articles, to get the total cost, or simply to purchase the materials. In this article, Hilmar outlines how to do this with multiple levels of intermediate ar...
Summary
A standard requirement in a production system, or in systems for cost calculation, is to add up all the raw materials for a number of finished articles, to get the total cost, or simply to purchase the materials. In this article, Hilmar outlines how to do this with multiple levels of intermediate articles such as where individual parts have a list of materials, whereas the parts appear in the finished articles. Using multiple levels helps avoid redundancy, since the materials required for the parts do not need to be repeated in every article that uses them.
Description
A standard requirement in computer systems that manage cost calculation and production control is to add up all the raw materials for a number of finished articles, in order to get the total cost, but also to simply know what materials have to be purchased. In this article, I will outline how to do this with multiple levels of intermediate articles, i.e., individual parts have a list of materials, whereas the parts appear in the finished articles. Using multiple levels helps avoid redundancy, since the materials required for the parts don't need to be repeated in every article that uses them. The basic principles involved are actually quite simple.

Prerequisites

For some parts of this article it is convenient to understand the basics of recursion. You can read my introductory article on this topic Universal Thread Magazine, January 2003.

Single level

First, let us start with a single level of containment, just to get an overview. That is, a finished article only contains raw materials; no intermediate products yet.

Terminology

Here is the basic terminology as used in this article:

Terminology Description
Material, or raw material Anything our company buys from outside. Used as inputs to create the goods.
Article, or finished article The product sold by our company. A finished article requires several materials for its manufacture.
Intermediate article (Used later in this - umm - "piece of writing") An intermediate step between the finished article and the raw material. An intermediate article will appear in one or more finished articles, but it will also have its own list of materials.

Requirements

The requirements of our system, then, or of the part that concerns us here, are to have a list of materials including current prices, and a list of finished articles our company produces. Also, we need to record what materials make up each finished article (what material, in what quantity), so that we can calculate what it costs us to produce the finished article. (At least, the part of the cost related to raw materials; things like wages, social benefits, machine depreciation, taxes, etc., can introduce additional complications, which go beyond the scope of this article.)

Data structure

The data structures are actually quite simple. For a start, we need one table for the material and one for the finished article.

Table Description
Materials Let's call this table MaterialList. Fields would include the product code and a product description, among others.(Of course, other fields will be added, depending on specific requirements. I will concentrate on the basics here.)
Articles Let's call this table ArticleList. Essential fields the product code, a description, and the current price. (For the finished article, the price won't be provided by the user, but calculated, eventually, as the total value of materials (plus any other cost you want to include in the calculation).

Note 1: A more logical name for the article table would be "Article", but then the referential integrity may fail if there is another table that starts with the same name, like "ArticleMaterial" which we will use later. This is due to a bug in the Referential Integrity code.

Note 2: For the primary fields, I am assuming some sort of auto-generated value, for instance, an Integer with a default value of SerialNumber("TableName"); where the function SerialNumber() fetches the next value from a table of sequences. Other alternatives include functions that generate some pseudo-random value, such as a GUID, or the VFP function sys(2015). If you prefer to use the product code itself for the primary key, that is of course also possible, but a few adjustments are required.

ArticleMaterial We also need to store information about what materials are required for each article, and in what quantities. Here we have a many-to-many relation between articles and materials, i.e., one article can contain several materials, and one material can be used in many articles. Therefore we need a third table. The many-to-many relationship is thus separated into two one-to-many relationships.

Field structure

Note that this section is for the single-level system. The multi-level system is explained later.

MaterialList - The list of raw materials:

Field Type Length Description
Material Integer Default value: SerialNumber("MaterialList")
MaterialCode Character 10 The product code
MaterialName Character 30 Product description
CurrentPrice Y The current unit price
Unit Integer FK for table UnitList (or a character field where the user just types a description for the unit)

ArticleList - The list of finished articles:

Field Type Length Description
Article Integer PK. Default value: SerialNumber("ArticleList")
ArticleCode Character 10 The product code
ArticleName Character 30 Product description
CurrentPrice Y The calculated price

ArticleMaterial - Materials required for each article:

Field Type Length Description
ArticleMaterial Integer PK. Default value: SerialNumber("ArticleMaterial")
Article Integer FK for table ArticleList
Material Integer FK for table MaterialList
Quantity Y What quantity of this material is requird for this article

Multilevel - advantages

Now, before we start exploring the structures for a multilevel production system (i.e., one that includes intermediate products), let's take a look at some of the advantages.

The idea is that some finished articles contain intermediate products, which in turn contain raw materials. For example, a finished shoe will be sold in a box; the box is result of another manufacturing process, and might require, as raw materials, cardboard, a sticker, and glue, plus some work input. (Note that work is not considered in detail in this article.) Other example of intermediate articles (specifically for the case of a shoe production) include leather, soles, and diverse mixtures of chemicals - assuming, in all of these cases, that the shoe factory does all of these steps itself, for instance, that it does its own tannery (leather processing).

The big advantage of the intermediate article is that all the parts required for the intermediate article need to be listed only once, in the finished article. Equally important, any change in the definition of the intermediate article needs to be done only once.

Of course, this convenience comes at a price; as in many other cases, making things easier for the end-user means more work for the programmer. But it is worthwhile to consider this, at least for larger production systems: At our company, where we use intermediate articles, a typical list of materials for a shoe fits on a single page; I heard about another shoe factory, whose computer system doesn't support intermediate articles, where a typical list of materials, for an article, spans 3-4 pages, because it has to list all the materials for what we consider "intermediate articles", directly in the listing of the finished article.

Multilevel table structures

Consider the required relations, considering that an intermediate article can play both the role of an article (something that contains), and of a material (something that is contained).

A finished article can contain both raw materials, and intermediate articles. The relations between tables are quite complicated if raw materials and intermediate articles are in separate tables, therefore, they must be stored together, in the same table.

Also, a raw material may be contained either in a finished article, or in an intermediate article. Therefore, the finished articles and the intermediate articles must also be stored in the same table, to simplify relations.

The conclusion seems inescapable: All steps in the production process, from raw materials, passing through possibly several levels of intermediate articles, up to the finished article, must be stored in a single table. At least, it seems to me that this is the only sensible way to structure this particular problem.

The tables required, then, are two:

Table Description
ArticleList Now contains finished articles, intermediate articles, and raw material
ArticleMaterial Indicates which article contains which material

ArticleList - now contains finished articles, raw material, and intermediate articles:

Field Type Length Description
ArticleList Integer PK. Default value: SerialNumber("ArticleList")
ArticleCode Character 10 The product code
ArticleName Character 30 The description
ArticleLevel Character 1 A one-letter code that indicates whether the record represents a finished article, an intermediate article, or a raw material.
Unit Integer A foreign key to a table of units (or a character field, to type the unit directly into the table)

ArticleMaterial - materials contained in each article. Every finished article or intermediate article contains several intermediate articles or raw materials:

Field Type Length Description
ArticleMaterial Integer PK. Default value: SerialNumber("ArticleMaterial")
Article Integer Indicates a containing article (finished or intermediate). Foreign key to table ArticleList.
Material Integer Indicates a contained article (intermediate article or raw material). Foreign key to table ArticleList.
Quantity Y Indicates how much of the material is needed for the article.
Unit Integer A foreign key to a table of units (or a character field, to type the unit directly into the table)

Additional fields may be required, depending on the needs; in the case of table ArticleList, some of these may only be appropriate for finished articles, or for materials, for example. You may want to put some of these into separate tables, to save space (with a one-to-one relationship); my personal preference is to keep them in a single table, for simplicity.

Some selected procedures

Now that we have the data structures, let me briefly outline some of the procedures you need to carry out with this multilevel structure. I will not give any source code here, just the basic idea.

First of all, since all the "articles" are now on the same level (with respect to the data structures, at least), you have to ensure that an article doesn't contain itself – either directly or indirectly. That is, if article "A" contains article "A", there is a problem, but there is also a problem if article "A" contains article "B", and article "B", in turn, contains article "A". (Specifically, this "circular reference" will cause great problems when you calculate the cost of an article, or when you get the list of materials required for one or more articles.) This requires some sort of recursive procedure. The check is best done as part of the data validation, when the user changes data; for greater safety, you should also have a report that lists invalid articles, i.e., articles that contain themselves.

Another procedure you will probably need is to get the list of materials required for a single article, or for a list of articles. (In our system, we get this from the tables for production planning.) This, too, is some sort of recursive procedure; I suggest a generic procedure that can be used for many different reports. The procedure might take, as its "input", a cursor with a list of articles and their corresponding quantities (plus any additional data of interest, for example, for what date the production is planned, in case you want data for a range of dates). That is, the "input" cursor is prepared beforehand, and then the procedure is invoked. The result of running this procedure might be another cursor, with the detailed information on materials and quantities. Since this is meant to be a generic procedure, you may want to include: For what article the material is used; what material is used; in what quantity; and for what date of production (in case you include this information). You may also want to include information about how many levels are required to get from the finished article to the material. This information can then be grouped as needed for specific reports (for instance, in some reports you will only want information about the materials required, and not, for what articles the materials are used for). The recursion basically works like this: For each finished article, put all required materials into the result cursor. If one of the resulting materials is an intermediate article, repeat the procedure for this intermediate article. The result cursor will contain all the intermediate articles and the raw materials. I suggest to also include the original article that is being planned.

Yet another procedure that is required is to recalculate the cost of an article, or the cost of all articles. I do not recommend recursion in this case, since it would be very inefficient: to calculate a finished article you would first have to recalculate all of its intermediate articles. To recalculate all finished articles, a recursive procedure would recalculate the intermediate articles many times (once for each of the articles where it is used).

Instead, I did the following, to recalculate all articles: Replace the price of all articles (not including raw materials) with NULL. Then, loop through all the articles, and recalculate them, by adding the prices of materials that make up the article. If an article happens to have intermediate prices with a NULL price (i.e., the intermediate article was not yet calculated), interrupt the cost calculation for this specific article, leaving the prices at NULL. Another alternative is to store a separate cursor of articles to be processed, and eliminate the articles that have been recalculated.

After going through all articles in this manner, repeat from the beginning, perhaps several times, until all articles have been calculated.

Summary

Managing a multi-level production and cost-calculation system is quite simple, in principle, but of course it will take some time to fine-tune all the little details.

Hilmar Zonneveld, Independent Consultant
Hilmar Zonneveld works in programming since 1986, using dBASE, FoxPro and Visual FoxPro. He is available as an independent consultant. He currently works as a programmer at Bata Shoe Organization; also as an instructor at Cisco Networking Academy. You can contact him through the Universal Thread, or, via e-mail, at hilmarz@yahoo.com. Personal Web page (mainly in Spanish): www.geocities.com/hilmarz.
More articles from this author
Hilmar Zonneveld, May 1, 2003
An audit-trail is a record of who did what changes, and when. In Visual FoxPro, this can easily be accomplished through triggers. I hinted at the possibility of doing an audit-trail, in my article on triggers - now, as a reaction to questions in the Universal Thread, I want to present a sample...
Hilmar Zonneveld, December 6, 2001
(The latest update contains minor edits only.) Five easy and fun ways to get yourself into trouble with inheritance. A frequent source of problems in OOP is called "breaking inheritance". This document briefly describes what inheritance is, how it applies to properties and methods, and how it ...
Hilmar Zonneveld, July 1, 2002
Introduction Buffering is a feature in Visual FoxPro that allows us to give the user "undo" and "save" capabilities. In the old FoxPro 2.x days, programmers either didn't provide this capability, or edited memory variables, and copied information between these variables and the table fiel...
Hilmar Zonneveld, October 6, 2005
Due to a recent Windows security fix, users can no longer access a CHM file on a server. The table of contents appears, but the individual pages are replaced by error messages. Access to CHM files in specific folders can be explicitly allowed through special registry settings.
Hilmar Zonneveld, July 20, 2001
(The last update contains minor edits only.) The idea is to have several controls on a form controlled with an array. Thus, you can quickly go through all the controls on the form, managing the array. The sample code included will help you get started quickly. You can easily adapt it to manage...
Hilmar Zonneveld, September 1, 2002
With Automation, you can control all aspects of Excel, Word, or other programs that provide this feature, from Visual FoxPro. In this article, I will concentrate on Excel. Its purpose is to provide a starting point, especially for people new to automation. Introduction With automation, you bas...
Hilmar Zonneveld, March 1, 2003
Introduction One common task in programming is to keep track of what problems are pending. For this purpose, I use a "hierarchical to-do list": a list of items, each of which can have sub-items. All you need is Microsoft Word. Alternatives are available as freeware or shareware, but in t...
Hilmar Zonneveld, October 7, 2005
This is a step-by-step tutorial to show inheritance, specifically in Visual FoxPro forms, as a guidance for people who are not familiar with inheritance in general, or who don’t know how to implement it in Visual FoxPro. The basic idea of inheritance is that all your forms, or several of your for...
Hilmar Zonneveld, May 30, 2004
The code shows how to quickly obtain the greatest common factor, and the least common multiple. Both functions are used when manipulating fractions, among others. Several methods are possible; the method usually taught in school involves prime numbers, but this code will execute much faster (and it ...
Hilmar Zonneveld, August 1, 2002
Overview The purpose of this article is to give an overview of normalization. Basically, normalization refers to having an efficient table structure. I will not discuss the famous "first to fifth normal forms" - if you want that information, enough texts exist about it in other places (search sit...
Hilmar Zonneveld, November 8, 2001
The following function will open any document, with its default association (the same application that will be called when you double-click on the file, in Windows Explorer). Use it to open a text-file, a Word or Excel document, an image, etc., with an external application.
Hilmar Zonneveld, May 1, 2002
Introduction This document explains the meaning of primary key, foreign key and candidate index in Visual FoxPro. A discussion of natural and surrogate keys (keys visible, or not visible, to the end-user) is included, including the advantages of each approach, as well as different methods for o...
Hilmar Zonneveld, January 1, 2003
Continuing my series of introductory articles, this article presents an introduction of a simple yet powerful programming concept: recursion. Introduction "To understand recursion, you must first understand recursion." "To make yogurt, you need milk and yogurt." If you are not accustomed...
Hilmar Zonneveld, December 1, 2002
Introduction This article presents an introduction to coding shortcuts in Visual FoxPro - when to use them, and when not to. Notes on coding in general This article is about coding shortcuts; however, I should first emphasize that making the code as small as possible is usually not the number...
Hilmar Zonneveld, July 20, 2001
Rushmore Optimization can help make queries much faster. However, "Full Rushmore Optimization" is not always a desirable goal. "Partial Optimization" is sometimes much faster. It is often believed that to speed things up, you need to have as many indices as possible. This article explains that so...
Hilmar Zonneveld, June 7, 2002
If you need to check elapsed time with seconds() or a datetime value, this function allows you to display the elapsed time in a human-readable format, that is, hours:minutes:seconds, instead of the total number of seconds. Just pass a number of seconds as a parameter.
Hilmar Zonneveld, April 1, 2002
SQL is a standard language used to manipulate databases. Several of the SQL commands are integrated into the Visual FoxPro language. Select This is a very flexible command, used to select data from a table, or from several tables. This command has options to get totals from several record...
Hilmar Zonneveld, August 1, 2003
In this article, I will show several ways to manipulate text-files. Knowledge of these methods is often important to import and export specific formats. Some of the techniques can also be used to work with files of any content; however, this article will concentrate on text-files. When ...
Hilmar Zonneveld, June 1, 2002
The purpose of this article is to show how to use some aspects provided by the Visual FoxPro database engine, to control our data. Indices Perhaps most readers already know indices; anyway, I find it convenient to include a brief summary of the topic, since this is a requisite to understan...
Hilmar Zonneveld, November 1, 2002
A help file can be used either for interactive help, or as an online manual. In this article, I will give an overview over creating help files in the new help format (CHM), for Visual FoxPro 6 and later. This article is introductory and assumes no prior knowledge of the Help Compiler, or of HTML cod...
Hilmar Zonneveld, February 1, 2003
Introduction Any real-world application will sooner or later misbehave. It is important to be able to find those problems. Visual FoxPro's built-in debugger can help a lot to find out why your program doesn't work as you thought it would. Most of the material in this article applies to Visual...
Hilmar Zonneveld, May 1, 2006
This article is an introduction to VisioModeler. This is a free CASE tool, that can help you design your database, in the process sharing the information with the client in a visual, easy-to-understand, format.