contribute: Add Davide Peressoni
[worg.git] / org-contrib / org-bom.org
blob1d1e62e2750699d925fd24d832e085b8e58194fd
1 #+TITLE:      BOM : Bills-of-materials
2 #+AUTHOR:     Christian Fortin
3 #+EMAIL:      frozenlock AT gmail DOT com
4 #+OPTIONS:    H:3 num:nil toc:t \n:nil ::t |:t ^:t -:t f:t *:t tex:t d:(HIDE) tags:not-in-toc
5 #+STARTUP:    align fold nodlcheck hidestars oddeven lognotestate
6 #+SEQ_TODO:   TODO(t) INPROGRESS(i) WAITING(w@) | DONE(d) CANCELED(c@)
7 #+TAGS:       Write(w) Update(u) Fix(f) Check(c) 
8 #+LANGUAGE:   en
9 #+CATEGORY:   worg-tutorial
11 # This file is released by its authors and contributors under the GNU
12 # Free Documentation license v1.3 or later, code examples are released
13 # under the GNU General Public License v3 or later.
15 [[file:index.org][{Back to Worg's index}]]
18 * BOM introduction
20   This add-on collects components across the entire org buffer (even
21   in drawers), making it easy to retrieve and sort data. It uses the
22   column special name as a landmark. We will refer to them as
23   'Keywords'. The keywords are searched using a string-match function,
24   which gives the ability to have multiple column with the same
25   functionality, but also to use the column name as we would usually
26   with org-mode. For example, we can have 'tag' and 'tag2', both are
27   recognized by the BOM add-on and can be used in a spreadsheet-like
28   formula without any confusion. The keywords are also
29   case-insensitive. 'Component' and 'component' will work in the same
30   way.
32   The BOM is usually used with a dynamic block. (You can use the
33   different functions in emacs-lisp code, but this is beyond the
34   purpose of this tutorial.) Here is the basic dynamic block:
36 :  #+BEGIN: bom
37 :  #+END:
39   And here is what we obtain at this point:
40 :  #+BEGIN: bom
41 : | Section | Tag | Component | Quantity |
42 : |---------+-----+-----------+----------|
43 :  #+END:
45   The table is empty, because we have to either:
46   1. Add keywords in a table;
47   2. Add a line-component.
49 * BOM keywords
50 ** Component
52      This is the most important keyword and act as the trigger. For
53   this example, let's say we write down things we want to buy. In 
54   this case, a new keyboard for our computer.  This is how the
55   table should be:
56   
57 :  |   | Material  |
58 :  | ! | Component |
59 :  |---+-----------|
60 :  |   | Keyboard  |
61   
62   The '!' character is used in org table to specify column name, such
63   as our keyword, 'component'.
64   And here is what the bill-of-materials for this table is:
65      
66 :  #+BEGIN:  bom 
67 : | Section   | Tag | Component | Quantity |
68 : |-----------+-----+-----------+----------|
69 : | Component |     | Keyboard  |        1 |
70 :  #+END:
72   As you can see, the heading (Component) was automatically
73   used as the 'section', which doesn't require attention for
74   now. The quantity is, unsurprisingly, 1. There is nothing in the tag
75   column for now, so let's dismiss it by adding the parameter *:no-tag
76   t*. 
77   This will results in the following:
78 :  #+BEGIN: bom  :no-tag t
79 : | Section   | Component | Quantity |
80 : |-----------+-----------+----------|
81 : | Component | Keyboard  |        1 |
82 :  #+END: 
83   
84   Now suppose that our friend too wants a new keyboard.
86 :  |   | For    | Material  |
87 :  | ! |        | Component |
88 :  |---+--------+-----------|
89 :  |   | Me     | Keyboard  |
90 :  |   | Friend | Keyboard  |
91      
92 :   #+BEGIN: bom :no-tag t
93 :  | Section   | Component | Quantity |
94 :  |-----------+-----------+----------|
95 :  | Component | Keyboard  |        2 |
96 :   #+END:
98   As expected, we get 2 keyboards.
99      
100 ** Section
101    
102      The section is used to separate what would otherwise be an
103   identical component. Suppose we don't want our friend's wishes to be
104   in the same BOM as our, but still have them in the same table.
106 :  |   | For     | Material  |
107 :  | ! | Section | Component |
108 :  |---+---------+-----------|
109 :  |   | Me      | Keyboard  |
110 :  |   | Friend  | Keyboard  |
112   This will results in the following BOM:
114 :  #+BEGIN: bom :no-tag t
115 : | Section | Component | Quantity |
116 : |---------+-----------+----------|
117 : | Friend  | Keyboard  |        1 |
118 : | Me      | Keyboard  |        1 |
119 :  #+END:
121   Please note that when a component is given a section, it isn't
122   associated with the heading anymore. As an alternative, you can set
123   a ':SECTION:' property in the heading, which will be inherited by
124   all the components _without_ a specified section.
125   Section's priorities are as follow: 
127   1. Given section with the 'section' keyword;
128   2. The SECTION property;
129   3. The heading.
131 ** Qty
133      With this keyword, it is possible to specify a quantity for the
134   associated component. In our always improving scenario, we now want to
135   give a keyboard to another of our friend (as a gift). This is going to
136   be bought at the same time as our keyboard, so they belong together.
138 :  |   | For     | Material  |     |
139 :  | ! | Section | Component | Qty |
140 :  |---+---------+-----------+-----|
141 :  |   | Me      | Keyboard  |   2 |
142 :  |   | Friend  | Keyboard  |   1 |
144 :   #+BEGIN: bom :no-tag t
145 :  | Section | Component | Quantity |
146 :  |---------+-----------+----------|
147 :  | Friend  | Keyboard  |        1 |
148 :  | Me      | Keyboard  |        2 |
149 :   #+END:
150      
151   *Important*: If Qty keyword is present, then any empty field will
152   be considered as _zero_. This way, multiple column quantity are
153   made quite easily:
154      
155 :  |   | For     | Material  | Personal | Gift |
156 :  | ! | Section | Component |      Qty | Qty2 |
157 :  |---+---------+-----------+----------+------|
158 :  |   | Me      | Keyboard  |        1 | 1    |
159 :  |   | Friend  | Keyboard  |        1 |      |
161 :   #+BEGIN: bom :no-tag t
162 :  | Section | Component | Quantity |
163 :  |---------+-----------+----------|
164 :  | Friend  | Keyboard  |        1 |
165 :  | Me      | Keyboard  |        2 |
166 :   #+END:  
168 ** Tag
170      When a BOM starts to get big, we often need a quick reminder of
171   why we need certain component. Another use is also to identify the
172   component. As the Qty keyword, multiple Tag columns can be associated
173   with a single component. Here we will simply use the tag as a reminder
174   of what we want to look for in the store.
176 :  |   | For     | Material  | Personal | Gift | Need               |
177 :  | ! | Section | Component |      Qty | Qty2 | Tag                |
178 :  |---+---------+-----------+----------+------+--------------------|
179 :  |   | Me      | Keyboard  |        1 | 1    | Matching colors    |
180 :  |   | Friend  | Keyboard  |        1 |      | Dinosaurs pictures |
182   To show the tag column in the BOM, we simply remove the no-tag
183   parameter.
184 :  #+BEGIN: bom
185 : | Section | Tag                | Component | Quantity |
186 : |---------+--------------------+-----------+----------|
187 : | Friend  | Dinosaurs pictures | Keyboard  |        1 |
188 : | Me      | Matching colors    | Keyboard  |        2 |
189 :  #+END:  
190   
192   If two Tag columns are present for a single Component column, the
193   tags will be associated with this component, separated by a comma.
195 * Renaming BOM columns
196      
197      It is possible to rename the BOM columns with the following
198   parameters:
199   - col-name-component
200   - col-name-section
201   - col-name-quantity
202   - col-name-tag
203   - col-name-description
204   - col-name-price
206   This is how our renamed BOM would look like:
207      
208 :  #+BEGIN: bom :col-name-section For :col-name-tag Need :col-name-component Stuff :col-name-quantity Qty
209 : | For    | Need               | Stuff    | Qty |
210 : |--------+--------------------+----------+-----|
211 : | Friend | Dinosaurs pictures | Keyboard |   1 |
212 : | Me     | Matching colors    | Keyboard |   2 |
213 :  #+END:  
215 * Multiple component's column
217      There is two way to add components in a section. Either by adding
218   other rows with the same section's name, or by adding other
219   columns. Both have their uses and they should come to you quite
220   naturally. In our example, we want more stuff.
222 :  |   | For     | Material  | Personal | Gift | Need               | Stuff     | More stuff | Much more stuff | How many |
223 :  | ! | Section | Component |      Qty | Qty2 | Tag                | Component | Component  | Component       | Qty      |
224 :  |---+---------+-----------+----------+------+--------------------+-----------+------------+-----------------+----------|
225 :  |   | Me      | Keyboard  |        1 | 1    | Matching colors    | Mouse     | Headset    | USB flash drive | 23       |
226 :  |   | Friend  | Keyboard  |        1 |      | Dinosaurs pictures |           |            |                 |          |
227 :  |   | Friend  |           |          |      |                    |           |            | CDs             | 50       |
228 :  |   | Friend  | Mouse     |        1 |      |                    |           |            |                 |          |
229      
230   This is beginning to get interesting. Note that even if we can
231   name the additional columns 'Component2' or 'ComponentAAA',
232   there's no use to do it if no table-formula uses the column
233   names. 
235 * Precise section selection
236   Now suppose we want to get OUR to-buy list. Simply specify
237   the section's parameter *:section Me*:
239 :   #+BEGIN: bom :section Me
240 :  | Tag             | Component       | Quantity |
241 :  |-----------------+-----------------+----------|
242 :  |                 | Headset         |        1 |
243 :  | Matching colors | Keyboard        |        2 |
244 :  |                 | Mouse           |        1 |
245 :  |                 | USB flash drive |       23 |
246 :   #+END:  
247      
248   Wait, where's the section column?  Well we don't need it anymore,
249   as we specified one.
251   A '+' sign will specify we want more than a single section. *:section
252   Me+Friend* will select both section, and add the quantity and tags
253   for each component. 
255 :  #+BEGIN: bom :section Me+Friend
256 : | Tag                                 | Component       | Quantity |
257 : |-------------------------------------+-----------------+----------|
258 : |                                     | CDs             |       50 |
259 : |                                     | Headset         |        1 |
260 : | Dinosaurs pictures, Matching colors | Keyboard        |        3 |
261 : |                                     | Mouse           |        2 |
262 : |                                     | USB flash drive |       23 |
263 :  #+END:
265   *Do not* put a whitespace between the section name and the '+' sign.
266   Speaking of whitespace, if you need one in a section name, simply
267   put it in a string: 
268 : #+BEGIN: bom :section "Section with whitespace"
270   We can also return every section that matches at least what we
271   provide. To activate this, use *:part-match t*. With this, if we
272   write "fr", the Friend section is returned. If we had another
273   section named "Frosting", than Friend and Frosting would have been
274   merged and we would have a total for both section.
276 :  #+BEGIN: bom :section fr :part-match t
277 : | Tag                | Component | Quantity |
278 : |--------------------+-----------+----------|
279 : |                    | CDs       |       50 |
280 : | Dinosaurs pictures | Keyboard  |        1 |
281 : |                    | Mouse     |        1 |
282 :  #+END:
284   It is also possible to specify that we don't want any section
285   containing "fr". For this, use the parameter *:remove t*.
287 :  #+BEGIN: bom :section fr :part-match t :remove t
288 : | Tag             | Component       | Quantity |
289 : |-----------------+-----------------+----------|
290 : |                 | Headset         |        1 |
291 : | Matching colors | Keyboard        |        2 |
292 : |                 | Mouse           |        1 |
293 : |                 | USB flash drive |       23 |
294 :  #+END:
296   In this case, getting all sections not containing "fr" is the
297   equivalent of choosing the section "Me".
299   If you simply want the components from the current heading, use the
300   parameter *:local-only t*. This will return components with the
301   current heading as their section, which is the default of every
302   component if no section is provided. If a section has been provided to
303   a component (and is not exactly equal to the heading), the component
304   will not be returned.
306   Here, we don't have any component under this heading:
307 :  #+BEGIN: bom :local-only t
308 : | Tag | Component | Quantity |
309 : |-----+-----------+----------|
310 :  #+END:
312 * BOM total
313   This is all really interesting, but when we're in a shop, we want
314   to know how many of each item we have to buy, we need a *total*.
315   For this, simply add the *:total t* parameter. We will also remove
316   the tags once again by using *:no-tag t*.
318 :  #+BEGIN: bom :total t :no-tag t
319 : | Component       | Quantity |
320 : |-----------------+----------|
321 : | CDs             |       50 |
322 : | Headset         |        1 |
323 : | Keyboard        |        3 |
324 : | Mouse           |        2 |
325 : | USB flash drive |       23 |
326 :  #+END:
328   This is the equivalent of merging every sections together.
329 * Adding a component without a table
331   There is another option you might need. If you ever want to
332   add a component without a table, use the #+BOM commentary. As any
333   other org-mode commentary, this one won't appear when exported to
334   another document (pdf, html, docbook..). It will, however, enable
335   you to add a single component in the bill-of-materials. Here is an
336   example:
337 :  #+BOM: Keyboard :section Need :tag "Matching colors"
339   As with the table components, you can simply give a component name if
340   you desire. If no section is given, it will be inherited as an
341   ordinary component in a table: a section property or the current
342   heading.
344 * Adding details
345   There is two way to add details to a BOM. The first one is to setq
346   `org-bom-details' with a plist containing, depending on your
347   needs, :description, :datasheet-pdf and :price. You must, however, at
348   least have the component name in the :name property. Here is an
349   example on how to set this variable:
351 #+BEGIN_SRC emacs-lisp
352 (setq org-bom-details '((:name "Keyboard" :description
353                           "Something" :price "40") 
354                           (:name "CDs" :description "Not
355                           DVDs" :datasheet-pdf "CD.pdf")))
356 #+END_SRC
357   Please note that the price is a *string*.
359   The other method, valid for the current buffer only, is to give one
360   or more bom-details table. It is recognized when a table is named as
361   such:
362 :  #+TBLNAME: bom-details
364   Once again, the column names are used. Contrary to the normal BOM
365   keywords however, these are case-sensitive and must be written
366   exactly as their property name. For example, the column of the
367   property ':name' must be 'name'.
368 :  #+TBLNAME: bom-details
369 : | ! | name     | description  | price |
370 : |---+----------+--------------+-------|
371 : |   | Keyboard | Used to type |    40 |
372 : |   | CDs      |              |       |
373   
374   Any bom-details table will temporarily overshadow the
375   `org-bom-details' variable, but won't erase or modify it. This means
376   you can safely use a bom-details table if you need to change some
377   local buffer description, while using `org-bom-details' in multiple
378   buffer.
380   Look at the CDs description. When a field is empty, it is *not* used
381   and BOM falls back to the property in the `org-bom-details'
382   variable.
383   
384 ** Description
385    
386    You can add a description column in a BOM by adding the
387    *:description t* parameter. 
389 :   #+BEGIN: bom :total t :no-tag t :description t
390 :  | Component       | Quantity | Description  |
391 :  |-----------------+----------+--------------|
392 :  | CDs             |       50 | Not DVDs     |
393 :  | Headset         |        1 | N/A          |
394 :  | Keyboard        |        3 | Used to type |
395 :  | Mouse           |        2 | N/A          |
396 :  | USB flash drive |       23 | N/A          |
397 :   #+END:
399    See how the CDs' description wasn't the empty field from the
400    bom-details table.
402 ** Price
403    
404    You can add a price column in a BOM by adding the *:price t*
405    parameter.
407 :   #+BEGIN: bom :total t :no-tag t :description t :price t
408 :  | Component       | Quantity | Price | Description  |
409 :  |-----------------+----------+-------+--------------|
410 :  | CDs             |       50 |       | Not DVDs     |
411 :  | Headset         |        1 |       | N/A          |
412 :  | Keyboard        |        3 |   120 | Used to type |
413 :  | Mouse           |        2 |       | N/A          |
414 :  | USB flash drive |       23 |       | N/A          |
415 :  |-----------------+----------+-------+--------------|
416 :  | TOTAL:          |          |   120 |              |
417 :      #+TBLFM: @>$3=vsum(@I..@>>)
418 :   #+END:
419    The price is automatically multiplied by the quantity of each
420    component. In addition, a total row is added at the table's bottom
421    with a vertical sum formula.
422    
423 ** Datasheet
424    
425    This is a special property and must be used only if you intend to
426    export in a pdf document. See [[LaTeX mode and bom-datasheet]] for more details.
427    
428 * List of BOM parameters
429   Here is a list of all the parameters usable in a BOM dynamic block,
430   as seen throughout this tutorial:
432   - no-tag :: Remove the tags column
433   - section :: Select this section (or more if there's a + sign)
434   - part-match :: Select every section with at least the string
435                   provided for the section parameter
436   - remove :: Select every sections except the one(s) provided
437   - descripton :: Add the description column
438   - price :: Add the price column and a total row at the bottom of the
439              table
440   - col-name-*** :: Rename the associated column
441 * Advanced and elisp functions
442 ** Speed up updates
443    Each BOM dynamic block scans the entire buffer individually. While
444    it is necessary that each block be able to update itself, it
445    becomes a waste when the command `org-update-all-dblocks' is
446    used. (The components usually aren't changing from a dblock evaluation to
447    another.)
448    
449    In order to speed up updates, there's a variable that can be used
450    to stop each BOM dblock from doing a buffer-wide scan. To disable the
451    scans, set `org-bom-update-enable' to nil.
453    The author uses a function similar to this one to speed up updates:
454 #+BEGIN_SRC emacs-lisp :exports code
455 (defun reg-update-project (&optional latex-mode)
456   "Update every table and dynamic block in the buffer. If latex-mode
457 is non-nil, various latex commands will be inserted."
458   (interactive)
459   (org-table-iterate-buffer-tables)
460   (org-bom-total); manually update the BOM database
461   (let ((org-bom-update-enable nil)
462         (org-bom-latex-mode latex-mode)
463         (org-bom-details (copy-tree org-bom-details)));so we don't overwrite
464     (org-bom-check-for-details-table); manually update `org-bom-details'
465     (org-update-all-dblocks))
466   (message "Project updated"))
467 #+END_SRC
468      
469 ** LaTeX mode and bom-datasheet
470   This mode isn't fully integrated to org-mode and should be seen as a
471   hack. It is however useful to the author, which is why it is
472   explained here.
474   Set the `org-bom-latex-mode' variable to non-nil in order to
475   activate the latex-mode. If set, all BOM dynamic block will insert
476   some latex commands.
478   These commands targets:
479   - Tags :: When there is more tags than `org-bom-latex-max-tags' per
480             component, the remaining tags are put in a pdf comment.
481   - Component name :: If a datasheet exists for the component, its
482                       name will become a link to its datasheet.
484                      
485   If you ever activate the LaTeX mode, use the bom-datasheet dynamic
486   block at the end of your document. The optional parameter
487   *:description t* will add a summary of all the components used in
488   this buffer with their description, just before the datasheets.
490 :  #+BEGIN: bom-datasheet
491 :  
492 :  #+LaTeX: \includepdf[pages=-,landscape=true,addtotoc={1, subsection, 1, CDs,CD.pdf}]{\DATASHEETPATH/CD.pdf}
493 :  
494 :  #+END:
496   As you may have noticed, there's a LaTeX variable in this command:
497         \DATASHEETPATH. In order to work, you must set this variable
498         using:
500 :       #+LATEX_HEADER: \newcommand{\DATASHEETPATH}{Name-of-the-folder/}'
502         Name-of-the-folder is the folder where the datasheets' files
503         are located.