comparison Generic/base.py @ 1:2ac1551ad2ab version 0.0.0

add code
author Miguel Ángel Bárcena Rodríguez <miguelangel@obraencurso.es>
date Sun, 31 Oct 2010 20:07:33 +0100
parents
children a7b9f7e7dfa4
comparison
equal deleted inserted replaced
0:a1703c4f2990 1:2ac1551ad2ab
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 ## File base.py
4 ## This file is part of pyArq-Presupuestos.
5 ##
6 ## Copyright (C) 2010 Miguel Ángel Bárcena Rodríguez
7 ## <miguelangel@obraencurso.es>
8 ##
9 ## pyArq-Presupuestos is free software: you can redistribute it and/or modify
10 ## it under the terms of the GNU General Public License as published by
11 ## the Free Software Foundation, either version 3 of the License, or
12 ## (at your option) any later version.
13 ##
14 ## pyArq-Presupuestos is distributed in the hope that it will be useful,
15 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ## GNU General Public License for more details.
18 ##
19 ## You should have received a copy of the GNU General Public License
20 ## along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 """base module
23
24 In this module are defined the data structures in the
25 classes:
26 * Record: data of each record
27 * ParamentricRecord: data of each parametric record
28 * Decomposition: data of the decomposition of each record
29 * Measure: data of the measure of each record
30 * MeasureLine: each measure line data
31 * Decimals: data of the decimal places of all the numbers in a budget
32 * Sheet: data of the sheet of conditions of a budget
33 * Budget: all data of a budget
34 * Company: company data
35 * Office: company office data
36 * File: file data
37 * RecordType: Record type data
38
39 schema:
40 * Budget:
41 +-- __records: dictionary records { code : Record }
42 * Record:
43 +-- code: record code
44 +-- synonyms: list of synonym codes
45 +-- hierarchy: A integer number:
46 0 -> root
47 1 -> Chapter/Subchapter
48 2 -> Other
49 +-- unit: unit of measure of the record
50 +-- summary: Short description of the record
51 +-- prices: List of Prices/Dates
52 +-- type
53 +-- subtype
54 "type" and "subtype":
55 0 Without classifying
56 EA Auxiliary element
57 EU Unitary element
58 EC Complex element
59 EF Functional element
60 OB Construction site
61 PA Cost overrun
62 PU Unitary budget
63 1 Labourforce
64 H Labourforce
65 2 Machinery and auxiliary equipment
66 Q Machinery
67 % Auxiliary equipment
68 3 Building materials
69 MC Cement
70 MCr Ceramic
71 MM Wood
72 MS Iron and steel
73 ME Energy
74 MCu Copper
75 MAl Aluminium
76 ML Bonding agents
77 M Others materials
78 Hierarchy type subtype
79 0->root -> 0 -> None,OB
80 1->[sub]chapter -> 0 -> None,PU
81 2->Other -> 0 -> None,EA,EU,EC,EF,PA
82 1 -> None,H
83 2 -> None,Q,%
84 3 -> None,MC,MCr,MM,MS,ME,MCu,Mal,ML,M
85 +-- parents: List of parent codes
86 +-- children: list of Decomposition
87 * Decomposition:
88 +-- position: Position of the child in the parent descomposition
89 TODO: change this: the position of the record in the budget
90 +-- code: child record code
91 +-- budget: list of budget and amended budget measures
92 * Measure:
93 +-- measure: Total result of measure
94 +-- lines: List of measure lines
95 * MeasureLine:
96 +-- type: Line type:
97 empty string -> Normal
98 1 -> Parcial Subtotal
99 2 -> Accumulated Subtotal
100 3 -> Formula, the comment is a formula.
101 +-- comment: Can be a descriptive text or a formula
102 Valid Operator: '(', ')', '+', '-', '*', '/' and
103 '^'
104 Valid variable: 'a', 'b', 'c','d' y 'p'
105 (Pi=3.1415926)
106 +-- units: Number of Units (a)
107 +-- length: length (b)
108 +-- width: width (c)
109 +-- height: height (d)
110 +-- label: Record Identifiers that are used by some measure
111 programs
112 +-- factor: Factor
113 +-- yield_: Yield
114 +-- certification: list of certifications for months measures
115 * Measure
116 +-- real_cost: list of real cost of construction for months
117 measures
118 * Measure
119 +-- cost_goals: list of cost goals of construction for months
120 measures
121 * Measure
122 +-- cost_planned: list of costs planned and amended cost planned
123 measures
124 * Measure
125 +-- text: Long Description of the record
126 +-- sheet: Sheet of conditions object
127 * Sheet:
128 +-- sheet_dict:
129 { <Field key> : { <Section key> : <Paragraph key>}}
130 +-- files: List of file object
131 +-- file
132 * Name
133 * Type
134 * Description
135 +-- __synonyms: synonyms dictionary. TODO
136 +-- __root: root record code
137 +-- __decimals: decimals dictionay = { int : Decimals }
138 * Decimals:
139 +-- DN: Number of decimal places of the field "equal-size parts" in the
140 measure lines.
141 Default: 2 decimal places.
142 +-- DD: Number of decimal places of the three dimensions in the
143 measure lines.
144 Default: 2 decimal places.
145 +-- DS: Number of decimal places of the total sum of a measure.
146 Default: 2 decimal places.
147 +-- DFP: Number of decimal places of the yield factor in a
148 decomposition of a budget record.
149 Default: 3 decimal places.
150 +-- DFC: Number of decimal places of the yield factor in a
151 decomposition of a chapter or subchapter, and in its measure lines.
152 Dafault: 3 decimal places.
153 +-- DFUO: Number of decimal places of the yield factor in a
154 decomposition of a unit of work.
155 Default: 3 decimal places.
156 +-- DFA: Number of decimal places of the yield factor in a
157 decomposition of a Auxiliary element.
158 Default: 3 decimal places.
159 +-- DRP: Number of decimal places of the yield in a decomposition
160 of a budget record.
161 Number of decumal places of the result of the multiplication of
162 the factor and the yield in a decompositon of a budget.
163 Default: 3 decimal places.
164 +-- DRC: Number of decimal places of the yield (or measure) in a
165 decomposition of a chapter or subchapter.
166 Number of decimal places of the result of the multiplictaion of
167 the yield (or measure) and the factor in a decomposition of a
168 chapter or subcharter.
169 Default: 3 decimal places.
170 +-- DRUO: Number of decimal places of the yield in a decomposition of a
171 unit of work.
172 Decimal places of the result of the multiplication of the yield
173 and the factor in a descomposition of a unit of work.
174 Default: 3 decimal places.
175 +-- DRA: Number of decimal places of the yield in a decompositon of a
176 auxiliar element.
177 Number of decimal places of the result of the multiplication of
178 the yield and the factor in a descomposition of a auxilar element.
179 Default: 3 decimal places.
180 +-- DP: Number of decimal places of the price of a budget.
181 Default: 2 decimal places.
182 +-- DC: Number of decimal places of the price of a chapter or
183 subchapter.
184 Default: 2 decimal places.
185 +-- DUO: Number of decimal places of the price of a unit of work.
186 Default: 2 decimal places.
187 +-- DEA: Number of decimal places of the price of a auxiliar element.
188 Default: 2 decimal places.
189 +-- DES: Number of decimal places of the price of the simple elements.
190 Default: 2 decimal places.
191 +-- DIR: Number of decimal places of the resulting amount to multiply
192 the total yield and the price of the elements of a unit of work.
193 (When there are not measures)
194 +-- DIM: Number of decimal places of the resulting amount to multiply
195 the total yield and the price of the elements of a unit of work.
196 (When there are measures)
197 +-- DIRC: Number of decimal places of the resulting amount to multiply
198 the total yield and the price of the elements of a budget, chapter
199 or a subchapter.(When there are not measures)
200 +-- DIMC: Number of decimal places of the resulting amount to multiply
201 the total yield and the price of the elements of a budget, chapter
202 or a subchapter. (When there are measures)
203 +-- DCD: Number of decimal places ot the resulting amount to sum the
204 direct costs of a unit of work (and auxiliar element).
205 Number of decimal places of the indirect costs.
206 Default: 2 decimal places.
207 +-- DIVISA: monetary unit.
208 +-- __percentages: percentages dictionary:
209 { "CI" : "",
210 "GG" : "",
211 "BI" : "",
212 "BAJA": "",
213 "IVA" : ""}
214 +-- __file_owner
215 +-- __title_list: titles list: [ "Header", ["Title1", "Title2", ... ] ]
216 +-- __title_index: A integer. The active group of Prices and Decimals.
217 +-- __sheet_sections: sheet sections dictionary { sheet_code : sheet_title }
218 +-- __sheet_fields: sheet fields dictionary { field_code : field_title }
219 +-- __sheet_paragraphs: sheet paragraphs dictionary
220 { paragraph_code : paragraph_text}
221 +-- __companys: Dictionary whith companys object
222 { company_code: company_object }
223 * Comapany:
224 +-- code: company code
225 +-- summary: short name
226 +-- name: long name
227 +-- offices: List of offices:
228 * Office:
229 +-- type: office type
230 "C" Central office.
231 "D" Local Office.
232 "R" Performer.
233 +-- subname: Office name
234 +-- address: Ofiice address
235 +-- postal_code: postal code
236 +-- town: town
237 +-- province: province/state
238 +-- country: country
239 +-- phone: list of phone numbers
240 +-- fax: list of fax numbers
241 +-- contact_person: Contact person in the office
242 +-- cif: CIF
243 +-- web: web page
244 +-- email: email
245 """
246
247 # Modules
248 import re
249 import datetime
250 import os
251
252 # pyArq-Presupuestos modules
253 from Generic import fiebdc
254 from Generic import utils
255
256 class Record(object):
257 """base.Record:
258
259 Description:
260 Record object
261 Constructor:
262 base.Record(code, synonyms, hierarchy, unit, summary, prices, type,
263 subtype, text="")
264 Ancestry:
265 +-- object
266 +-- Record
267 Atributes:
268 "code": Code string
269 "recordType": RecordType object
270 "synonyms": List of synonym codes.
271 "parents":List of parent codes
272 "children": Decomposition list,
273 list of "Decomposition" instances
274 "unit": measure unit of the record
275 "summary": Short description of the record
276 "prices": List of prices/dates
277 "text": Long Description of the record
278 "sheet": Sheet of conditions object
279 "files": List of file object
280 "labels": List of record labels
281 Methods:
282 __getstate__(self)
283 __setstate__(self, tuple)
284 __init__(self, filename=None, budget=None)
285 {get/set}Code
286 {get/set}Synonyms
287 {get/set}RecordType
288 {get/set}Unit
289 {get/set}Summary
290 {get/set}Prices
291 addPrice
292 _validate_price_date
293 getPrice
294 getAmount
295 getDate
296 {get/set}Parents
297 appendParent
298 {get/set}children
299 appendChild
300 {get/set}Text
301 {get/set}Sheet
302 {get/set}Files
303 addFile
304 {get/set}Labels
305 addLabel
306 """
307 __slots__ = ["_Record__code", "_Record__synonyms",
308 "_Record__recordType", "_Record__unit",
309 "_Record__summary", "_Record__prices",
310 "_Record__parents", "_Record__children",
311 "_Record__text", "_Record__sheet",
312 "_Record__files", "_Record__labels"]
313
314 def __getstate__(self):
315 return (self.__code, self.__synonyms, self.__recordType,
316 self.__unit, self.__summary, self.__prices,
317 self.__parents, self.__children, self.__text,
318 self.__sheet, self.__files, self.__labels)
319
320 def __setstate__(self, tuple):
321 self.__code = tuple[0]
322 self.__synonyms = tuple[1]
323 self.__recordType = tuple[2]
324 self.__unit = tuple[3]
325 self.__summary = tuple[4]
326 self.__prices = tuple[5]
327 self.__parents = tuple[6]
328 self.__children = tuple[7]
329 self.__text = tuple[8]
330 self.__sheet = tuple[9]
331 self.__files = tuple[10]
332 self.__labels = tuple[11]
333
334 def __init__(self, decimals, code, synonyms, hierarchy, unit, summary,
335 prices, type, subtype, parents=[], text=""):
336 self.code = code
337 self.synonyms = synonyms
338 self.recordType = (hierarchy, type, subtype)
339 self.unit = unit
340 self.summary = summary
341 self.setPrices(prices, decimals)
342 self.parents = parents
343 self.children = []
344 self.text = text
345 self.sheet = Sheet()
346 self.files = []
347 self.labels = []
348
349 def getCode(self):
350 return self.__code
351
352 def setCode(self, code):
353 """setCode(self,code)
354
355 Sets the code, must be a valid code
356 """
357 if not utils.is_valid_code(code)[0]:
358 raise ValueError, utils.mapping(_("Invalid code: $1"),(str(code),))
359 self.__code = code
360
361 def getSynonyms(self):
362 return self.__synonyms
363
364 def setSynonyms(self,synonyms):
365 """setSynonyms(self,synonyms)
366
367 Sets the synonyms codes of the record.
368 synonyms must fulfill:
369 - must be a list
370 - the items must be valid codes
371 """
372 if not isinstance(synonyms, list):
373 raise TypeError, utils.mapping(_("Synonyms ($1) must be a list, " \
374 "code: $2"), (str(synonyms), self.__code))
375 for code in synonyms:
376 if not utils.is_valid_code(code)[0]:
377 raise ValueError, utils.mapping(_("Invalid Code in synomyms "\
378 "list ($1) code: $2"), (str(code), self.__code))
379 self.__synonyms = synonyms
380
381 def getRecordType(self):
382 return self.__recordType
383
384 def setRecordType(self, recordType):
385 """setRecordType(self, recordType)
386
387 Set the record type.
388 recordType (hierarchy, type,subtype)
389
390 hierarchy must be -1, 0, 1 or 2
391 type must be 0, 1, 2, 3 or a empty string
392 subtype must be EA, EU, EC, EF, OB, PA, PU, H, Q, %, MC, MCr,
393 MM, MS, ME, MCu, MAl, ML, M, or a empty string
394 """
395 _recordType = RecordType(recordType[0],recordType[1],recordType[2])
396 self.__recordType = _recordType
397
398 def getUnit(self):
399 return self.__unit
400
401 def setUnit(self,unit):
402 """setUnit(self,unit)
403
404 Set the unit of measure
405 The unit must be a string.
406 """
407 if not isinstance(unit, str):
408 raise TypeError, utils.mapping(_("Unit ($1) must be a string: $2"),
409 (str(unit), self.__code))
410 self.__unit = unit
411
412 def getSummary(self):
413 return self.__summary
414
415 def setSummary(self,summary):
416 """setSummary(self,summary)
417
418 Set the summary of a record
419 The summary must be a string.
420 """
421 if not isinstance(summary, str):
422 raise TypeError, utils.mapping(_("Summary ($1) must be a string: "\
423 "$1"), (str(summary), self.__code))
424 self.__summary = summary
425
426 def getPrices(self):
427 return self.__prices
428
429 def setPrices(self, prices, decimals):
430 """setPrice(self, prices, decimals)
431
432 Set the price list of the record.
433 prices must fulfill:
434 - it must be a list
435 - the items must be a list with two items
436 - the first item: price must be a float
437 """
438 if not isinstance(prices, list):
439 raise TypeError, utils.mapping(_("Prices ($1) must be a list: $2"),
440 (str(prices), self.__code))
441 for index in range(len(prices)):
442 _price_date = prices[index]
443 _price_date = self._validate_price_date(_price_date, decimals)
444 prices[index] = _price_date
445 self.__prices = prices
446
447 def addPrice(self, price_date, decimals):
448 """addPrice(self, price_date, decimals)
449
450 Add a price to the price list of the record.
451 price must fulfill:
452 - must be a list with two items
453 - the first item: price must be a float
454 """
455 price_date = self._validate_price_date(price_date, decimals)
456 self.__prices.append(price_date)
457
458 def _validate_price_date(self, price_date, decimals):
459 if not isinstance(price_date, list) and len(price_date) == 2:
460 raise ValueError, utils.mapping(_("Price ($1) must be a list"\
461 " with two items: $2"), (str(price_date), self.__code))
462 _price = price_date[0]
463 _date = price_date[1]
464 if not isinstance(_price, float):
465 raise TypeError, utils.mapping(_("Price must be a float "\
466 "number: $1"), (str(_price),))
467 _D = decimals.getD(self.recordType)
468 _price = round(_price, _D)
469 price_date[0] = _price
470 # TODO: validate date
471 return price_date
472
473 def getPrice(self, index_price):
474 if len(self.__prices) <= index_price:
475 raise IndexError, _("The record do not have this Price. Code: %s"
476 % self.__code)
477 return self.__prices[index_price][0]
478
479 def getDate(self, index_price):
480 if len(self.__prices) <= index_price:
481 raise IndexError, _("The record do not have this Price")
482 return self.__prices[index_price][1]
483
484 def getParents(self):
485 return self.__parents
486
487 def setParents(self,parents):
488 """setParents(self,parents)
489
490 Sets the list of parents codes of the record.
491 parents must fulfill
492 - it must be a list
493 - the items must be valid codes
494 """
495 if not isinstance(parents, list):
496 raise TypeError, utils.mapping(_("Parents ($1) must be a list: $2"),
497 (str(parents), self.__code))
498 for parent in parents:
499 if not utils.is_valid_code(parent)[0]:
500 raise ValueError, utils.mapping(_("Invalid parent code ($1) " \
501 "in the record: $2"), (str(padre), self.__code))
502 self.__parents = parents
503
504 def appendParent(self, parent):
505 """appendParent(self, parent)
506
507 parent must be a valid code
508 Append a parent to the list of parents codes of the record.
509
510 """
511 if not utils.is_valid_code(parent)[0]:
512 raise ValueError, utils.mapping(_("Invalid parent code ($1) " \
513 "in the record: $2"), (str(parent), self.__code))
514 self.__parents.append(parent)
515
516 def getchildren(self):
517 return self.__children
518
519 def setchildren(self,children):
520 """setchildren(self,children)
521
522 Sets the list of children of a record
523 children must fulfill
524 - it must be a list
525 - the items must be instances of Decomposition class
526 """
527 if not isinstance(children, list):
528 raise TypeError, utils.mapping(_("children ($1) must be a list, "\
529 "record: $2"), (str(children), self.__code))
530 for _child in children:
531 if not isinstance(_child, Decomposition):
532 raise ValueError, utils.mapping(_("child ($1) must be a "\
533 "Decomposition object, record: $2"),
534 (str(_child), self.__code))
535 _record_code = self.code
536 for _measure_list in [_child.budgetMeasures, _child.certification,
537 _child.real_cost, _child.cost_goals,
538 _child.cost_planned]:
539 if isinstance(_measure_list, list):
540 for _measure in _measure_list:
541 _measurerecordCode = _record_code
542 self.__children = children
543
544 def appendChild(self, child_code, decimals, factor=0.0, yield_=0.0,
545 measure=0.0, measure_list=[], type ="", label=""):
546 """appendChildren(self, child_code, factor=0.0, yield_=0.0,
547 measure=0.0, measure_list=[], type ="", label=""))
548
549 position:
550 child_code:
551 factor:
552 yield_:
553 measure:
554 measure_list:
555 type:
556 label:
557
558 Append a child to the list of children
559 """
560 _measure = Measure(decimals, self.recordType,
561 measure, [], label, factor, yield_)
562 if len(measure_list) > 0:
563 measure.buildMeasure(_measure, measure_list, type, decimals,
564 self.recordType)
565 _position = len(self.__children)
566 _child = Decomposition(_position, child_code, [_measure])
567 self.__children.append(_child)
568 return _child
569
570 def getText(self):
571 return self.__text
572
573 def setText(self,text):
574 """setText(self,text)
575
576 Sets the text of the record
577 It must be a string
578 """
579 if not isinstance(text, str):
580 raise TypeError, utils.mapping(_("Text ($1) must be a string, "\
581 "record: $2"), (str(text), self.__code))
582 self.__text = text
583
584 def getSheet(self):
585 return self.__sheet
586
587 def setSheet(self, sheet):
588 """setSheet(self, sheet)
589
590 Sets the sheet of condition object
591 """
592 if not isinstance(sheet, Sheet):
593 raise ValueError, _("sheet must be a Sheet instance")
594 self.__sheet = sheet
595
596 def getFiles(self):
597 return self.__files
598
599 def setFiles(self, files):
600 """setFiles(self, files)
601
602 Sets the files list
603 """
604 # TODO: only sets files and File object format (durusdatabase)
605 if not isinstance(files, list):
606 raise ValueError, utils.mapping(_("files must be a list: $1"),
607 str(files))
608 _files = []
609 for file in files:
610 if isinstance(file, File):
611 _files.append(file)
612 elif isinstance(file, list):
613 _file_path = file[0]
614 _type = file[1]
615 _description = file[2]
616 if not os.path.exists(file[0]):
617 raise ValueError, _("Incorrect path")
618 _file = File(file_path, type, description)
619 _files.append(_file)
620 else:
621 raise ValueError, utils.mapping(_(
622 "file must be a list or a File object: $1"),str(file))
623 self.__files = _files
624
625
626 def addFile(self, file_path, type, description):
627 """addFile(self, file_path, type, description)
628
629 Add a file to a record instance
630 """
631 if not os.path.exists(file_path):
632 raise ValueError, _("Incorrect path")
633 _name = os.path.basename(file_path)
634 _isin = False
635 for _ofile in self.__files:
636 if _ofile.name == _name:
637 _isin = True
638 if not _isin:
639 _file = File(_name, type, description)
640 self.__files.append(_file)
641
642 def getLabels(self):
643 return self.__labels
644
645 def setLabels(self, labels):
646 """setLabels(self, labels)
647
648 Sets the labels list of a record
649 """
650 if not isinstance(labels, list):
651 raise ValueError, _("labels must be a list")
652 _labels = []
653 for _label in labels:
654 if isinstance(_label, str):
655 _labels.append(_label)
656 else:
657 raise ValueError, _("label must be a string")
658 self.__labels = _labels
659
660 def addLabel(self, label):
661 """addLabel(self, label)
662
663 Add a label to a record instance
664 """
665 if not isinstance(label, str):
666 raise ValueError, _("Label must be a string")
667 if not label in self.__labels:
668 self.__labels.append(label)
669
670 recordType = property(getRecordType, setRecordType, None,
671 """Record Type object
672 """)
673 code = property(getCode, setCode, None,
674 """Record code
675 """)
676 synonyms = property(getSynonyms, setSynonyms, None,
677 """List of codes synonyms of the code
678 """)
679 unit = property(getUnit,setUnit, None,
680 """Measure Unit of the record
681 """)
682 summary = property(getSummary, setSummary, None,
683 """Short description of the record
684 """)
685 prices = property(getPrices, None, None,
686 """List of Price/Date
687 """)
688 parents = property(getParents, setParents, None,
689 """List of codes of the records which the record is in
690 its decomposition
691 """)
692 children = property(getchildren, setchildren, None,
693 """List of Decompositon intances""")
694 text = property(getText, setText, None,
695 """Long description of the record""")
696 sheet = property(getSheet, setSheet, None,
697 """Sheet of conditions object""")
698 files = property(getFiles, setFiles, None,
699 """File list""")
700 labels = property(getLabels, setLabels, None,
701 """Label list""")
702
703 class ParametricRecord(Record):
704 """base.ParametricRecord:
705
706 Description:
707 Parametric Record object
708 Constructor:
709 base.ParametricRecord(code, synonyms, hierarchy, unit, summary, prices,
710 type, subtype, text="")
711 Ancestry:
712 +-- object
713 +-- Record
714 +-- ParametricRecord
715 Atributes:
716
717 Methods:
718
719 """
720
721 __slots__ = ["_ParametricRecord__budget",
722 "_ParametricRecord__code", "_ParametricRecord__synonyms",
723 "_ParametricRecord__hierarchy", "_ParametricRecord__unit",
724 "_ParametricRecord__summary", "_ParametricRecord__prices",
725 "_ParametricRecord__type", "_ParametricRecord__subtype",
726 "_ParametricRecord__parents", "_ParametricRecord__children",
727 "_ParametricRecord__text", "_ParametricRecord__sheet",
728 "_ParametricRecord__files", "_ParametricRecord__labels",
729 "_ParametricRecord__parameters",
730 "_ParametricRecord__select_comment",
731 "_ParametricRecord__vars",
732 "_ParametricRecord__parametric_summary",
733 "_ParametricRecord__parametric_text",]
734
735 def __getstate__(self):
736 return (self.__budget, self.__code, self.__synonyms, self.__hierarchy,
737 self.__unit, self.__summary, self.__prices, self.__type,
738 self.__subtype, self.__parents, self.__children, self.__text,
739 self.__sheet, self.__files, self.__labels, self.__parameters,
740 self.__select_comment, self.__vars,
741 self.__parametric_summary, self.__parametric_text)
742
743 def __setstate__(self, tuple):
744 self.__budget = tuple[0]
745 self.__code = tuple[1]
746 self.__synonyms = tuple[2]
747 self.__hierarchy = tuple[3]
748 self.__unit = tuple[4]
749 self.__summary = tuple[5]
750 self.__prices = tuple[6]
751 self.__type = tuple[7]
752 self.__subtype = tuple[8]
753 self.__parents = tuple[9]
754 self.__children = tuple[10]
755 self.__text = tuple[11]
756 self.__sheet = tuple[12]
757 self.__files = tuple[13]
758 self.__labels = tuple[14]
759 self.__parameters = tuple[15]
760 self.__select_comment = tuple[16]
761 self.__vars = tuple[17]
762 self.__parametric_summary = tuple[18]
763 self.__parametric_text = tuple[19]
764
765 def __init__(self, budget, code, synonyms, hierarchy, unit, summary,
766 prices, type, subtype, parents=[], text=""):
767 Record.__init__(self, budget, code, synonyms, hierarchy, unit, summary,
768 prices, type, subtype, parents=[], text="")
769 self.__parameters = {}
770 self.__select_comment = ""
771 self.__vars = {}
772 self.parametric_summary = ""
773 self.parametric_text = ""
774
775 def getParameter(self, parameter):
776 if parameter in self.__parameters:
777 return self.__parameters[parameter]
778 else:
779 return None
780
781 def setParameter(self, parameter, parameter_list):
782 self.__parameters[parameter] = parameter_list
783
784 def getSelectComment(self):
785 return self.__select_comment
786
787 def setSelectComment(self, select_comment):
788 self.__select_comment = select_comment
789 def getVar(self, var):
790 if var in self.__vars:
791 return self.__vars[var]
792 else:
793 return None
794
795 def setVar(self, var, var_list):
796 self.__vars[var] = var_list
797
798 def getParametricSummary(self):
799 return self.__parametric_summary
800
801 def setParametricSummary(self, parametric_summary):
802 self.__parametric_summary = parametric_summary
803
804 def getParametricText(self):
805 return self.__parametric_text
806
807 def setParametricText(self, parametric_text):
808 self.__parametric_text = parametric_text
809
810 parameter = property(getParameter, setParameter, None,
811 """Record parameter
812 """)
813 select_comment = property(getSelectComment, setSelectComment, None,
814 """Seclect comment
815 """)
816 var = property(getVar, setVar, None,
817 """Record var
818 """)
819 parametric_summary = property(getParametricSummary, setParametricSummary,
820 None,
821 """Parametric summary
822 """)
823 parametric_text = property(getParametricText, setParametricText, None,
824 """Seclect comment
825 """)
826
827 class Decomposition(object):
828 """base.Decomposition:
829
830 Description:
831 Decomposition object
832 Constructor:
833 base.Decomposition(position, code, budgetMeasures, certification=None,
834 real_cost=None, cost_goals=None, cost_planned=None)
835 Ancestry:
836 +-- object
837 +-- Decomposition
838 Atributes:
839 "position": the position of the child record in the parent record
840 "code": Record code.
841 Measures:
842 "budgetMeasures": list of budget and Amended budget measures
843 "certification": list of certifications for months measures
844 "real_cost": list of real cost of construction for months measures
845 "cost_goals": list of cost goals of construction for months measures
846 "cost_planned": list of costs planned and amended cost planned measures
847 Methods:
848 __getstate__(self)
849 __setstate__(self, tuple)
850 __init__( position, code, budgetMeasures, certification=None,
851 real_cost=None, cost_goals=None, cost_planned=None)
852 {get/set}position
853 {get/set}Code
854 {get/set}BudgetMeasures
855 {get/set}Certification
856 {get/set}RealCost
857 {get/set}CostGoals
858 {get/set}CostPlanned
859 """
860 __slots__ = ["_Decomposition__position",
861 "_Decomposition__code",
862 "_Decomposition__budgetMeasures",
863 "_Decomposition__certification",
864 "_Decomposition__real_cost",
865 "_Decomposition__cost_goals",
866 "_Decomposition__cost_planned",
867 ]
868 def __getstate__ (self):
869 return (self.__position, self.__code, self.__budgetMeasures,
870 self.__certification, self.__real_cost, self.__cost_goals,
871 self.__cost_planned)
872 def __setstate__(self,tuple):
873 self.__position = tuple[0]
874 self.__code = tuple[1]
875 self.__budgetMeasures = tuple[2]
876 self.__certification = tuple[3]
877 self.__real_cost = tuple[4]
878 self.__cost_goals = tuple[5]
879 self.__cost_planned = tuple[6]
880
881 def __init__(self, position, code, budgetMeasures, certification=None,
882 real_cost=None, cost_goals=None, cost_planned=None):
883 self.position = position
884 self.code = code
885 self.budgetMeasures = budgetMeasures
886 self.certification = certification
887 self.real_cost = real_cost
888 self.cost_goals = cost_goals
889 self.cost_planned = cost_planned
890 def getPosition(self):
891 return self.__position
892 def setPosition(self, position):
893 if not isinstance(position, int):
894 raise ValueError, _("Position must be a integer")
895 self.__position = position
896 def getCode(self):
897 return self.__code
898 def setCode(self, code):
899 self.__code = code
900 def getBudgetMeasures(self):
901 return self.__budgetMeasures
902 def setBudgetMeasures(self, budgetMeasures):
903 if not isinstance(budgetMeasures, list):
904 raise ValueError, _("BudgetMeasures atribute must be a list")
905 for _measure in budgetMeasures:
906 if not isinstance(_measure, Measure):
907 raise ValueError, _("BudgetMeasures item must be a Measure "/
908 "object")
909 self.__budgetMeasures = budgetMeasures
910 def getCertification(self):
911 return self.__certification
912 def setCertification(self, certification):
913 if not (certification is None or isinstance(certification, list)):
914 raise ValueError, _("Certification atribute must be a list or None")
915 self.__certification = certification
916 def getRealCost(self):
917 return self.__real_cost
918 def setRealCost(self, real_cost):
919 if not (real_cost is None or isinstance(real_cost, list)):
920 raise ValueError, _("Real cost atribute must be a list or None")
921 self.__real_cost = real_cost
922 def getCostGoals(self):
923 return self.__cost_goals
924 def setCostGoals(self, cost_goals):
925 if not (cost_goals is None or isinstance(cost_goals, list)):
926 raise ValueError, _("Cost goals atribute must be a list or None")
927 self.__cost_goals = cost_goals
928 def getCostPlanned(self):
929 return self.__cost_planned
930 def setCostPlanned(self, cost_planned):
931 if not (cost_planned is None or isinstance(cost_planned, list)):
932 raise ValueError, _("Cost Planned atribute must be a list or None")
933 self.__cost_planned = cost_planned
934 position = property(getPosition, setPosition, None,
935 """Postion of the record in the budget
936 """)
937 code = property(getCode, setCode, None,
938 """Record code
939 """)
940 budgetMeasures = property(getBudgetMeasures, setBudgetMeasures, None,
941 """list of budget and Amended budget measures
942 """)
943 certification = property(getCertification, setCertification,None,
944 """ list of certifications by months measures
945 """)
946 real_cost = property(getRealCost, setRealCost, None,
947 """ list of real cost of construction for months measures
948 """)
949 cost_goals = property(getCostGoals, setCostGoals, None,
950 """ list of cost goals of construction for months measures
951 """)
952 cost_planned = property(getCostPlanned, setCostPlanned, None,
953 """ list of costs planned and amended cost planned measures
954 """)
955
956
957 class Measure(object):
958 """base.Measure:
959
960 Description:
961 Measure object
962 Constructor:
963 base.Measure(decimals, recordType, measure, lines,
964 label, factor, yield_)
965 Ancestry:
966 +-- object
967 +-- Measure
968 Atributes:
969 "measure": Total result of measure.
970 "lines": List of measure lines, List of LineM instances.
971 "label": Record Identifiers that are used by some measure programs.
972 "factor":
973 "yield":
974 "fixed": If fixed is True the yield is not calculated from measure
975 Methods:
976 __getstate__()
977 __setstate__(tuple)
978 __init__(decimals, recordType, measure, lines,
979 label, factor, yield_)
980 getMeasure()
981 setMeasure(measure, decimals)
982 {get/set}Lines
983 {get/set}Label
984 getFactor()
985 setFactor(factor, decimals, recordType)
986 getYield()
987 setYield(yield_, decimals, recordType)
988 getFixed()
989 setFixed(decimals)
990 buildMeasure(list_lines, type, decimals)
991 calculateMeasure(decimals)
992 updateYield(decimals)
993 """
994 __slots__ = ["_Measure__measure",
995 "_Measure__lines",
996 "_Measure__label",
997 "_Measure__factor",
998 "_Measure__yield_",
999 "_Measure__fixed"]
1000 def __getstate__ (self):
1001 return (self.__measure, self.__lines, self.__label,
1002 self.__factor, self.__yield_, self.__fixed)
1003 def __setstate__(self,tuple):
1004 self.__measure = tuple[0]
1005 self.__lines = tuple[1]
1006 self.__label = tuple[2]
1007 self.__factor = tuple[3]
1008 self.__yield_ = tuple[4]
1009 self.__fixed = tuple[5]
1010 def __init__(self, decimals, recordType, measure, lines,
1011 label, factor, yield_):
1012 self.setMeasure(measure, decimals)
1013 self.lines = lines
1014 self.label = label
1015 self.setFactor(factor, decimals, recordType)
1016 self.setYield(yield_, decimals, recordType)
1017 self.__fixed = False
1018
1019 def getMeasure(self):
1020 return self.__measure
1021 def setMeasure(self, measure, decimals):
1022 if not isinstance(measure, float):
1023 raise ValueError, utils.mapping(_("Measure must be a float "\
1024 "number. Type: $1"), (type(measure),))
1025 # TODO: test after
1026 _DS = decimals.DS
1027 measure = round(measure, _DS)
1028 self.__measure = measure
1029
1030 def getLines(self):
1031 return self.__lines
1032 def setLines(self, lines):
1033 if not isinstance(lines, list):
1034 raise ValueError, _("Lines must be a list")
1035 for _line in lines:
1036 if not isinstance(_line, MeasureLine):
1037 raise ValueError, _("Line must be a MeasureLine objetc")
1038 self.__lines = lines
1039 def getLabel(self):
1040 return self.__label
1041 def setLabel(self, label):
1042 self.__label = label
1043 def setFactor(self, factor, decimals, recordType):
1044 if not isinstance(factor, float):
1045 raise ValueError, utils.mapping(_("Factor must be a float number "\
1046 "|$1|"), (factor,))
1047 # TODO: test after
1048 _DF = decimals.getDF(recordType)
1049 factor = round(factor, _DF)
1050 self.__factor = factor
1051
1052 def getFactor(self):
1053 return self.__factor
1054
1055 def setYield(self, yield_, decimals, recordType):
1056 if not isinstance(yield_, float):
1057 raise ValueError, _("Yield must be a float number")
1058 # TODO: test after
1059 _DR = decimals.getDR(recordType)
1060 yield_ = round(yield_, _DR)
1061 self.__yield_ = yield_
1062
1063 def getYield(self):
1064 return self.__yield_
1065
1066 def setFixed(self, fixed, decimals):
1067 if not isinstance(fixed, bool):
1068 raise ValueError, _("Fixed must be boolean object")
1069 self.__fixed = fixed
1070 self.updateYield(decimals)
1071
1072 def getFixed(self):
1073 return self.__fixed
1074
1075 measure = property(getMeasure, None, None,
1076 """Total result of the measure
1077 """)
1078 lines = property(getLines, setLines, None,
1079 """List of measure lines, List of "MeasureLine" instances
1080 """)
1081 label = property(getLabel, setLabel, None,
1082 """Record identifiers that are used in some measure programs
1083 """)
1084 factor = property(getFactor, None, None,
1085 """Factor
1086 """)
1087 yield_ = property(getYield, None, None,
1088 """Yield of a record
1089 """)
1090 fixed = property(getFixed, setFixed,None,
1091 """If fixed is True the yield is not calculated from measure
1092 """)
1093
1094 def buildMeasure(self, list_lines, type, decimals, recordType):
1095 """setMeasure(self, list_lines, type, decimals)
1096
1097 list_lines: list of measure lines
1098 [ [linetype, comment, units, length, width, height, formula], ... ]
1099 linetype:
1100 #-#empty string -> Normal
1101 0 -> Normal
1102 1 -> Parcial Subtotal
1103 2 -> Accumulated Subtotal
1104 3 -> Formula
1105 comment: comment string
1106 units: Number of Units (a)
1107 length: Length (b)
1108 width: Width (c)
1109 height: Height (d)
1110 formula: Can be a formula or a empty string
1111 Valid Operator: '(', ')', '+', '-', '*', '/' and '^'
1112 Valid variable: 'a', 'b', 'c','d' and 'p' (Pi=3.1415926)
1113 type: type of action
1114 M: Set measure
1115 A: Add measure
1116 decimal: budget decimals object
1117
1118 Sets the measurelines for a record
1119 """
1120 # TODO: calcutate measure from lines
1121 _parcial = 0
1122 _total = 0
1123 _lines = []
1124 for _line in list_lines:
1125 _type, _comment = _line[0], _line[1]
1126 _units, _length = _line[2], _line[3]
1127 _width, _height = _line[4], _line[5]
1128 _formula = _line[6]
1129 _measure_line = MeasureLine(decimals, _type, _comment, _units,
1130 _length, _width, _height, _formula)
1131 _lines.append(_measure_line)
1132 if type == "M":
1133 self.lines = _lines
1134 elif type == "A":
1135 self.lines.extend(_lines)
1136 else:
1137 raise ValueError, utils.mapping(_("Type must be M or A. Type: $1"),
1138 (type,))
1139 self.calculateMeasure(decimals, recordType)
1140
1141 def calculateMeasure(self, decimals, recordType):
1142 #TODO: round acumulated_subtotal and parcial_subtotal
1143 if len(self.lines) > 0:
1144 _acumulated_total = 0.0
1145 _parcial_total = 0.0
1146 for line in self.lines:
1147 _parcial = line.parcial
1148 _acumulated_total += _parcial
1149 if line.lineType == 2:
1150 line.setAcumulatedSubtotal(_acumulated_total, decimals)
1151 elif line.lineType == 1:
1152 _parcialSubtotal = _acumulated_total - _parcial_total
1153 line.setParcialSubtotal(_parcialSubtotal, decimals)
1154 _parcial_total = _acumulated_total
1155 self.setMeasure(_acumulated_total, decimals)
1156 _DR = decimals.getDR(recordType)
1157 self.updateYield(decimals, recordType)
1158 def updateYield(self, decimals, recordType):
1159 if not self.fixed:
1160 self.setYield(self.measure, decimals, recordType)
1161
1162 class MeasureLine(object):
1163 """base.MeasureLine:
1164
1165 Description:
1166 MeasureLine object
1167 Constructor:
1168 base.MeasureLine(budget, type, comment, units, length, width, height,
1169 formula)
1170 Ancestry:
1171 +-- object
1172 +-- MeasureLine
1173 Atributes:
1174 "lineType": Line type:
1175 #-#empty string -> Normal
1176 0 -> Normal
1177 1 -> Parcial Subtotal
1178 2 -> Accumulated Subtotal
1179 3 -> Formula, the comment is a formula.
1180 "comment": Descriptive text string
1181 "units": Number of Units (a)
1182 "length": length (b)
1183 "width": Width (c)
1184 "height": Height (d)
1185 "formula": can be a valid formula or a empty string
1186 Valid Operator: '(', ')', '+', '-', '*', '/' and '^'
1187 Valid variable: 'a', 'b', 'c','d'y 'p' (Pi=3.1415926)
1188 "partial" : result of measure line
1189 "parcial_subtotal"
1190 "acumulated_subtotal"
1191 Methods:
1192 __getstate__(self)
1193 __setstate__(self, tuple)
1194 __init__(self, decimals, type, comment, units, length, width, height,
1195 formula)
1196 {get/set}LineType
1197 {get/set}Comment
1198 {get/set}Units
1199 {get/set}Length
1200 {get/set}Width
1201 {get/set}Height
1202 {get/set}Formula
1203 getParcial
1204 {get/set}ParcialSubtotal
1205 {get/set}AcumulatedSubtotal
1206 calculateParcial
1207 eval_formula
1208 """
1209 __slots__ = ["_MeasureLine__lineType",
1210 "_MeasureLine__comment",
1211 "_MeasureLine__units",
1212 "_MeasureLine__length",
1213 "_MeasureLine__width",
1214 "_MeasureLine__height",
1215 "_MeasureLine__formula",
1216 "_MeasureLine__parcial",
1217 "_MeasureLine__parcial_subtotal",
1218 "_MeasureLine__acumulated_subtotal",
1219 ]
1220 def __getstate__ (self):
1221 return (self.__lineType, self.__comment, self.__units,
1222 self.__length, self.__width, self.__height, self.__formula,
1223 self.__parcial)
1224 def __setstate__(self,tuple):
1225 self.__lineType = tuple[0]
1226 self.__comment = tuple[1]
1227 self.__units = tuple[2]
1228 self.__length = tuple[3]
1229 self.__width = tuple[4]
1230 self.__height = tuple[5]
1231 self.__formula = tuple[6]
1232 self.__parcial = tuple[7]
1233 #self.calculateParcial()
1234 def __init__(self, decimals, type, comment, units, length, width, height,
1235 formula):
1236 self.__parcial = 0.0
1237 self.__parcial_subtotal = 0.0
1238 self.__acumulated_subtotal = 0.0
1239 self.lineType = type
1240 self.comment = comment
1241 self.setUnits(units, decimals)
1242 self.setLength(length, decimals)
1243 self.setWidth(width, decimals)
1244 self.setHeight(height, decimals)
1245 self.setFormula(formula, decimals)
1246 #self.calculateParcial()
1247 def getLineType(self):
1248 return self.__lineType
1249 def getComment(self):
1250 return self.__comment
1251 def getUnits(self):
1252 return self.__units
1253 def getLength(self):
1254 return self.__length
1255 def getWidth(self):
1256 return self.__width
1257 def getHeight(self):
1258 return self.__height
1259 def getFormula(self):
1260 return self.__formula
1261 def getParcial(self):
1262 return self.__parcial
1263 def getParcialSubtotal(self):
1264 return self.__parcial_subtotal
1265 def getAcumulatedSubtotal(self):
1266 return self.__acumulated_subtotal
1267 def setParcialSubtotal(self, parcial_subtotal, decimals):
1268 if not isinstance(parcial_subtotal, float):
1269 raise ValueError, utils.mapping(_(" Parcial Subtotal must be a "\
1270 "float number. Parcial: $1"), (str(parcial_subtotal),))
1271 _DS = decimals.DS
1272 parcial_subtotal = round(parcial_subtotal, _DS)
1273 self.__parcial_subtotal = parcial_subtotal
1274 def setAcumulatedSubtotal(self, acumulated_subtotal, decimals):
1275 if not isinstance(acumulated_subtotal, float):
1276 raise ValueError, utils.mapping(_(" Acumulated Subtotal must be "\
1277 "a float number. Parcial: $1"),
1278 (str(acumulated_subtotal),))
1279 _DS = decimals.DS
1280 acumulated_subtotal = round(acumulated_subtotal, _DS)
1281 self.__acumulated_subtotal = acumulated_subtotal
1282 def calculateParcial(self, decimals):
1283 _DS = decimals.DS
1284 if self.lineType == 1 or self.lineType == 2:
1285 _parcial = 0.0
1286 elif self.lineType == 0: # self.formula == "":
1287 if isinstance(self.units, float):
1288 _a = self.units
1289 else:
1290 _a = 0.0
1291 if isinstance(self.length, float):
1292 _b = self.length
1293 else:
1294 _b = 1.0
1295 if isinstance(self.width, float):
1296 _c = self.width
1297 else:
1298 _c = 1.0
1299 if isinstance(self.height, float):
1300 _d = self.height
1301 else:
1302 _d = 1.0
1303 _parcial = _a * _b * _c * _d
1304 else:
1305 _parcial = self.eval_formula()
1306 _parcial = round(_parcial, _DS)
1307 self.__parcial = _parcial
1308
1309 def setLineType(self, type):
1310 if not type in [0, 1, 2, 3]:
1311 raise ValueError, utils.mapping(_("Invalid measure line type ($1)"),
1312 (str(type),))
1313 self.__lineType = type
1314 def setComment(self, comment):
1315 if not isinstance(comment, str):
1316 raise ValueError, utils.mapping(_("Measure Comment must be a "\
1317 "string ($1)"), (str(comment),))
1318 self.__comment = comment
1319 def setUnits(self, units, decimals):
1320 if units != "":
1321 if not isinstance(units, float):
1322 raise ValueError, utils.mapping(_("Invalid Measure Units ($1)"),
1323 (str(units),))
1324 _DN = decimals.DN
1325 units = round(units, _DN)
1326 self.__units = units
1327 try:
1328 self.calculateParcial(decimals)
1329 except AttributeError:
1330 pass
1331 def setLength(self, length, decimals):
1332 if length != "":
1333 if not isinstance(length, float):
1334 raise ValueError, utils.mapping(_("Invalid Measure length ($1)"),
1335 (str(units),))
1336 _DD = decimals.DD
1337 length = round(length, _DD)
1338 self.__length = length
1339 try:
1340 self.calculateParcial(decimals)
1341 except AttributeError:
1342 pass
1343 def setWidth(self, width, decimals):
1344 if width != "":
1345 if not isinstance(width, float):
1346 raise ValueError, utils.mapping(_("Invalid Measure Width ($1)"),
1347 (str(units),))
1348 _DD = decimals.DD
1349 width = round(width, _DD)
1350 self.__width = width
1351 try:
1352 self.calculateParcial(decimals)
1353 except AttributeError:
1354 pass
1355 def setHeight(self, height, decimals):
1356 if height != "":
1357 if not isinstance(height, float):
1358 raise ValueError, utils.mapping(_("Invalid Measure Height ($1)"),
1359 (str(height),))
1360 _DD = decimals.DD
1361 height = round(height, _DD)
1362 self.__height = height
1363 try:
1364 self.calculateParcial(decimals)
1365 except AttributeError:
1366 pass
1367 def setFormula(self, formula, decimals):
1368 if not isinstance(formula, str):
1369 raise ValueError, utils.mapping(_("Formula must be a "\
1370 "string ($1)"), (str(formula),))
1371 if re.match(".*[^0123456789\.()\+\-\*/\^abcdp ].*", formula):
1372 raise ValueError, utils.mapping(_("There is invalid characters"\
1373 "in formula ($1)"), (str(formula),))
1374 self.__formula = formula
1375 try:
1376 self.calculateParcial(decimals)
1377 except AttributeError:
1378 pass
1379
1380 lineType = property(getLineType, setLineType, None,
1381 """Type of measure line
1382 """)
1383 comment = property(getComment, setComment, None,
1384 """Text
1385 """)
1386 units = property(getUnits, None, None,
1387 """Number of units
1388 """)
1389 length = property(getLength, None, None,
1390 """Length measure
1391 """)
1392 width = property(getWidth, None, None,
1393 """Width measure
1394 """)
1395 height = property(getHeight, None, None,
1396 """Height measure
1397 """)
1398 formula = property(getFormula, None, None,
1399 """Formula
1400 """)
1401 parcial = property(getParcial, None, None,
1402 """result of measure line
1403 """)
1404 acumulated_subtotal = property(getAcumulatedSubtotal,
1405 None, None,
1406 """Acumulated subtotal
1407 """)
1408 parcial_subtotal = property(getParcialSubtotal,
1409 None, None,
1410 """Parcial subtotal
1411 """)
1412 def eval_formula(self):
1413 """eval_formula()
1414
1415 formula:
1416 Valid Operator: '(', ')', '+', '-', '*', '/' and '^'
1417 Valid variable: 'a', 'b', 'c','d'y 'p' (Pi=3.1415926)
1418 units: Number of Units (a)
1419 length: Length (b)
1420 width: Width (c)
1421 height: Height (d)
1422
1423 Evals the formula and return the result
1424 """
1425 formula = self.formula
1426 a = self.units
1427 b = self.length
1428 c = self.width
1429 d = self.height
1430 if a == "": a = 0.0
1431 if b == "": b = 0.0
1432 if c == "": c = 0.0
1433 if d == "": d = 0.0
1434 try:
1435 a = float(a)
1436 except:
1437 raise ValueError, _("'a' value must be a float number")
1438 try:
1439 b = float(b)
1440 except:
1441 raise ValueError, _("'b' value must be a float number")
1442 try:
1443 c = float(c)
1444 except:
1445 raise ValueError, _("'c' value must be a float number")
1446 try:
1447 d = float(d)
1448 except:
1449 raise ValueError, _("'d' value must be a float number")
1450 # spaces are erased
1451 formula.replace(" ","")
1452 # operators and varibles are replaced
1453 formula = formula.replace("+", " + ")
1454 formula = formula.replace("-", " - ")
1455 formula = formula.replace("*", " * ")
1456 formula = formula.replace("/", " / ")
1457 formula = formula.replace("^", " ** ")
1458 formula = formula.replace("(", " ( ")
1459 formula = formula.replace(")", " ) ")
1460 formula = formula.replace("a", str(a))
1461 formula = formula.replace("b", str(b))
1462 formula = formula.replace("c", str(c))
1463 formula = formula.replace("d", str(d))
1464 formula = formula.replace("p", "3.1415926")
1465 _list_formula = formula.split(" ")
1466 _formula2 = ""
1467 for oper in _list_formula:
1468 try:
1469 _float_oper= str(float(oper))
1470 _formula2 = _formula2 + _float_oper
1471 except ValueError:
1472 _formula2 = _formula2 + oper
1473 _g ={"__builtins__":{}}
1474 try:
1475 return eval(_formula2, _g)
1476 except:
1477 raise ValueError, _("Invalid formula")
1478
1479 class Decimals(object):
1480 """base.Decimals:
1481
1482 Description:
1483 Decimals object
1484 Constructor:
1485 base.Decimals(DN=2, DD=2, DSP=2, DS=2,
1486 DFC=3, DFPU=3, DFUO=3, DFA=3,
1487 DRP=3, DRC=3, DRUO=3, DRA=3,
1488 DP=2, DC=2, DPU=2, DUO=2, DEA=2, DES=2,
1489 DIR=2, DIM=2, DIRC=2, DIMC=2, DCD=2,
1490 DIVISA="EUR")
1491 Ancestry:
1492 +-- object
1493 +-- Decimals
1494 Atributes:
1495 "DN": Number of decimal places of the field "equal-size parts" in the
1496 measure lines.
1497 Default: 2 decimal places.
1498 "DD": Number of decimal places of the three dimensions in the
1499 measure lines.
1500 Default: 2 decimal places.
1501 "DSP": Number of decimal places of the subtotal of a measure.
1502 Default: 2 decimal places.
1503 "DS": Number of decimal places of the total sum of a measure.
1504 Default: 2 decimal places.
1505 "DFC": Number of decimal places of the yield factor in a decomposition
1506 of a chapter or subchapter.
1507 Dafault: 3 decimal places.
1508 "DFPU": Number of decimal places of the yield factor in a decomposition
1509 of a unitary budget.
1510 Default: 3 decimal places.
1511 "DFUO": Number of decimal places of the yield factor in a decomposition
1512 of a unit of work.
1513 Default: 3 decimal places.
1514 "DFA": Number of decimal places of the yield factor in a decomposition
1515 of a Auxiliary element.
1516 Default: 3 decimal places.
1517 "DRC": Number of decimal places of the yield in a
1518 decomposition of a chapter or subchapter.
1519 Number of decimal places of the result of the multiplictaion of
1520 the yield (or measure) and the factor in a decomposition of a
1521 chapter or subcharter.
1522 Default: 3 decimal places.
1523 "DRPU": Number of decimal places of the yield in a decomposition
1524 of a unitary budget record.
1525 Number of decumal places of the result of the multiplication of
1526 the factor and the yield in a decompositon of a untitary budget.
1527 Default: 3 decimal places.
1528 "DRUO": Number of decimal places of the yield in a decomposition of a
1529 unit of work.
1530 Decimal places of the result of the multiplication of the yield
1531 and the factor in a descomposition of a unit of work.
1532 Default: 3 decimal places.
1533 "DRA": Number of decimal places of the yield in a decompositon of a
1534 auxiliar element.
1535 Number of decimal places of the result of the multiplication of
1536 the yield and the factor in a descomposition of a auxilar element.Decimales
1537 Default: 3 decimal places.
1538 "DP": Number of decimal places of the price of a budget.
1539 Default: 2 decimal places.
1540 "DC": Number of decimal places of the price of a chapter or subchapter.
1541 Default: 2 decimal places.
1542 "DPU": Number of decimal places of the price of a unitary budget.
1543 Default: 2 decimal places.
1544 "DUO": Number of decimal places of the price of a unit of work.
1545 Default: 2 decimal places.
1546 "DEA": Number of decimal places of the price of a auxiliar element.
1547 Default: 2 decimal places.
1548 "DES": Number of decimal places of the price of the simple elements.
1549 Default: 2 decimal places.
1550 "DIR": Number of decimal places of the resulting amount to multiply
1551 the total yield and the price of the elements of a unit of work or
1552 a auxiliar element.
1553 "DIRC": Number of decimal places of the resulting amount to multiply
1554 the total yield and the price of the elements of a budget, chapter
1555 or a subchapter.
1556 "DCD": Number of decimal places ot the resulting amount to sum the
1557 direct costs of a unit of work (and auxiliar element).
1558 Number of decimal places of the indirect costs.
1559 Default: 2 decimal places.
1560 "DIVISA": monetary unit.
1561 Methods:
1562 __init__(DN=2, DD=2, DSP=2, DS=2,
1563 DFC=3, DFPU=3, DFUO=3, DFA=3,
1564 DRC=3, DRPU=3, DRUO=3, DRA=3,
1565 DP=2, DC=2, DPU=2, DUO=2, DEA=2, DES=2,
1566 DIR=2, DIRC=2, DCD=2,
1567 DIVISA="EUR")
1568 __getitem__(key)
1569 haskey(key)
1570 getD(recordtype)
1571 getDF(recordType)
1572 getDR(recordType)
1573 getDI(recordType)
1574 """
1575 # TODO: get/set methods
1576 def __init__(self,
1577 DN=2, DD=2, DSP=2, DS=2,
1578 DFC=3, DFPU=3, DFUO=3, DFA=3,
1579 DRC=3, DRPU=3, DRUO=3, DRA=3,
1580 DP=2, DC=2, DPU=2, DUO=2, DEA=2, DES=2,
1581 DIR=2, DIRC=2, DCD=2,
1582 DIVISA="EUR" ):
1583 self.DN = DN
1584 self.DD = DD
1585 self.DSP = DSP
1586 self.DS = DS
1587 self.DFP = 3
1588 self.DFC = DFC
1589 self.DFPU = DFPU
1590 self.DFUO = DFUO
1591 self.DFA = DFA
1592 self.DRP = 3
1593 self.DRC = DRC
1594 self.DRPU = DRPU
1595 self.DRUO = DRUO
1596 self.DRA = DRA
1597 self.DP = DP
1598 self.DC = DC
1599 self.DPU = DPU
1600 self.DUO = DUO
1601 self.DEA = DEA
1602 self.DES = DES
1603 self.DIR = DIR
1604 self.DIRC = DIRC
1605 self.DCD = DCD
1606 self.DIVISA = DIVISA
1607 def __getitem__(self, key):
1608 return self.__dict__[key]
1609 def haskey(self, key):
1610 return key in self.__dict__
1611 def getD(self, recordType):
1612 # DP: budget.
1613 # DC: chapter and subcharter.
1614 # DUO: unit.
1615 # DEA: auxiliar element.
1616 # DES: simple element.
1617 _hierarchy = recordType.hierarchy
1618 if _hierarchy == 0: #budget, type 0, subtipe "OB"
1619 _decimal = self.DP
1620 elif _hierarchy == 1: #chapter/subcharter, type 0, subtipe ""
1621 _decimal = self.DC
1622 else: # other
1623 _type = recordType.type
1624 _subtype = recordType.subtype
1625 if _subtype == "EA": # auxiliar element type 0 subitype "EA"
1626 _decimal = self.DEA
1627 if _subtype == "PU": # unitary budget type 0 subitype "PU"
1628 _decimal = self.DPU
1629 elif (_type in [1, 2, 3] or
1630 _subtype in ["H", "Q", "%", "MC", "MCr", "MM", "MS", "ME",
1631 "MCu", "Mal","ML", "M"]
1632 ): # simple element
1633 _decimal = self.DES
1634 else: # unit type 0, subtipe ["EU", "EC", "EF", "PA"]
1635 _decimal = self.DUO
1636 return _decimal
1637 def getDF(self, recordType):
1638 # Factor: DF
1639 # ->DFP: Budget
1640 # ->DFC: Chapter/Subchapter
1641 # ->DFUO: Unit
1642 # ->DFA: Auxiliar
1643 # ->DFPU: Unitary budget
1644 if recordType.hierarchy == 0: #budget
1645 _decimal = self.DFP
1646 elif recordType.hierarchy == 1: #chapter/subcharter
1647 _decimal = self.DFC
1648 else: # other
1649 if recordType.subtype == "EA": # auxiliar element
1650 _decimal = self.DFA
1651 if recordType.subtype == "PU": # unitary budget element
1652 _decimal = self.DFPU
1653 else: # unit EU EC EF PA
1654 _decimal = self.DFUO
1655 return _decimal
1656 def getDR(self, recordType):
1657 # Yield: DR
1658 # ->DRP: Budget
1659 # ->DRC: Chapter/Subchapter
1660 # ->DRUO: Unit
1661 # ->DRA: Auxiliar
1662 # ->DRPU: Unitary budget
1663 if recordType.hierarchy == 0: #budget
1664 _decimal = self.DRP
1665 elif recordType.hierarchy == 1: #chapter/subcharter
1666 _decimal = self.DRC
1667 else: # other
1668 if recordType.subtype == "EA": # auxiliar element
1669 _decimal = self.DRA
1670 if recordType.subtype == "PU": # unitary budget element
1671 _decimal = self.DRPU
1672 else: # unit
1673 _decimal = self.DRUO
1674 return _decimal
1675 def getDI(self, recordType):
1676 # DIRC: budget, chapter and subcharter.
1677 # DIR: unit, auxiliar element.
1678 _hierarchy = recordType.hierarchy
1679 _subtype = recordType.subtype
1680 if _hierarchy == 0 or _hierarchy == 1 or _subtype == "PU":
1681 #budget, type 0, subtipe "OB"
1682 #chapter/subcharter, type 0, subtipe ""
1683 #unitary budget, type 2, subtype "PU"
1684 _decimal = self.DIRC
1685 else: # other
1686 # auxiliar element type 0 subitype "EA"
1687 # unit type 0, subtipe ["EU", "EC", "EF", "PA", "PU"]
1688 _decimal = self.DIR
1689 return _decimal
1690
1691 class Sheet(object):
1692 """base.Sheet:
1693 Description:
1694 Sheet of conditions object
1695 Constructor:
1696 base.Sheet(sheet_dict)
1697 Ancestry:
1698 +-- object
1699 +-- Sheet
1700 Atributes:
1701 "sheet_dict": { <Field key> : { <Section key> : <Paragraph key>}
1702 <Field key>: must be in Budget.SheetFields
1703 <Section key>: must be in Budget.SheetSections
1704 <Paragraph key>: must be in Budget.SheetParagraph
1705 Methods:
1706 __getstate__(self)
1707 __setstate__(self, tuple)
1708 __init__(self, sheet_dict={})
1709 {get/set}Sheet_dict
1710 getFields
1711 getSections
1712 getParagraph
1713 addField
1714 addSection
1715 """
1716 __slots__ = ["_Sheet__sheet_dict"]
1717 def __getstate__ (self):
1718 return (self.__sheet_dict,)
1719 def __setstate__(self,tuple):
1720 self.__sheet_dict = tuple[0]
1721 def __init__(self):
1722 self.__sheet_dict = {}
1723 def getSheet_dict(self):
1724 return self.__sheet_dict
1725 def setSheet_dict(self, sheet_dict):
1726 if not isinstance(sheet_dict, dict):
1727 raise ValueError, _("sheet_dict must be a dictionay")
1728 self.__sheet_dict = sheet_dict
1729 def getFields(self):
1730 return self.sheet_dict.keys()
1731 def getSections(self, field):
1732 if field in self.__sheet_dict:
1733 return self.__sheet_dict[field].keys()
1734 else:
1735 return None
1736 def getParagraph(self, field, section):
1737 if (field in self.__sheet_dict and
1738 section in self.__sheet_dict[field]):
1739 return self.__sheet_dict[field][section]
1740 else:
1741 return None
1742 def addField(self, field, section_dict):
1743 if not isinstance(field, str):
1744 raise ValueError, _("sheet field must be a string")
1745 if not isinstance(section_dict, dict):
1746 raise ValueError, _("section_dict must be a dictionary")
1747 self.__sheet_dict[field] = section_dict
1748 def addSection(self, field, section, paragraph):
1749 if not isinstance(field, str):
1750 raise ValueError, _("sheet field must be a string")
1751 if not isinstance(section, str):
1752 raise ValueError, _("sheet section must be a string")
1753 if not isinstance(paragraph, str):
1754 raise ValueError, _("sheet paragraph must be a string")
1755 if not field in self.__sheet_dict:
1756 self.addField(field, { })
1757 _field = self.__sheet_dict[field]
1758 _field[section] = paragraph
1759 sheet_dict = property(getSheet_dict, setSheet_dict, None,
1760 """Sheet dictionary { <Field key> : { <Section key> : <Paragraph key>}""")
1761
1762 class Budget(object):
1763 """base.Budget:
1764
1765 Description:
1766 Budget objetc
1767 Constructor:
1768 base.Budget()
1769 Ancestry:
1770 +-- object
1771 +-- Budget
1772 Atributes:
1773 "filename": file name of the budget file (FIEBDC)
1774 "__records": Dictionary with the budget records.
1775 { "code" : Record object, }
1776 "__synonyms": Dictionary with the records synonums.
1777 { "code" : ["synonym",],}
1778 Each record code can have synonym codes.
1779 "__root": The root record code.
1780 "__title_list": List with the Headers and list of Titles for prices and
1781 decimal places.
1782 [ "Header", ["Title1", "Title2", ... ] ]
1783 The records can have diferent prices for diferent ages, geografical
1784 places, ...
1785 The Headers is the type of hierarchy of the prices
1786 Each Title have a group of Prices and a Decimals definition
1787 "__decimals": List with the decimal places used to round the
1788 result of the calculations with prices and measures
1789 The values are Decimals objects
1790 The <0> objets is the default Decimals (seted in FIEBDC-3),
1791 The others keys are for the diferent groups of Prices
1792 "__percentages": Dictionary with the percentages
1793 keys:
1794 "CI" Indirect Cost
1795 "GG" General expenses
1796 "BI" Industrial benefit
1797 "BAJA" Low (what this do here?)
1798 "IVA" Tax
1799 "__file_owner"
1800 "__comment"
1801 "__date"
1802 "__budgetType" A integer. Type of data in budget
1803 0 -> Undefined
1804 1 -> Base data.
1805 2 -> Budget.
1806 3 -> Certificate.
1807 4 -> Base date update.
1808 "__budgetCerficateOrder" Only valid if budgetType is 3.
1809 "__budgetCerficateDate" Only valid if budgetType is 3
1810 "__title_index": A integer. The active group of Prices and Decimals.
1811 "__sheet_sections": Dictionary whith de sheet sections
1812 "__sheet_fields": Dictionary whith sheet fields
1813 "__sheet_paragraphs": Dictionary whith sheet paragraphs
1814 "__companys": Dictionary whith companys object
1815 { company_code: company_object }
1816 "__tec_info": Dictionary whith tecnical information
1817 {ti_code : ["desciption text", "unit"]}
1818 "__labels": Label dictionary { "label": [ "code", ], }
1819 Methods:
1820 iter
1821 iterPreOrder
1822 iterPostOrder
1823 getRoot(self)
1824 hasPath(self, path)
1825 getchildren(self, code)
1826 setOwner(self, owner)
1827 setDate(self, date)
1828 setComment(self, comment)
1829 setBudgetType(self, type)
1830 setCertificateOrder(self, order)
1831 setCertificateDate(self, date)
1832 setTitleList(self, title)
1833 getTitleList(self)
1834 getActiveTitle(self)
1835 setDecimals(self, dictionary)
1836 getDecimals(self, decimal="All", N=None)
1837 setPercentages(self, dictionary)
1838 getPercentages(self, percentage="All")
1839 getAllParents(self, code)
1840 getAllchildren(self, code)
1841 getNDecomposition(self, code, N)
1842 getDecomposition(self,code)
1843 getMeasure(self, path)
1844 getStrYield
1845 getStrFactor
1846 setTree(sef, code, child_code, position, factor, yield_, total,
1847 list_lines, label, type)
1848 eval_formula(self, formula, a, b, c, d)
1849 getText(self, code)
1850 setText(self, code, text)
1851 setRecord(self, code, synonyms, hierarchy, unit, sumary, ...
1852 hasRecord(self, code)
1853 getRecord
1854 addPriceToRecord
1855 getStrPriceFromRecord
1856 getCode(self, path)
1857 getAmount
1858 getStrAmount
1859 setSheetSection(self, sheet_code, sheet_title)
1860 hasSheetSection(self, section)
1861 setSheetSections(self,dictionary)
1862 setSheetField(self, field_code, field_title)
1863 hasSheetField(self, field)
1864 getSheetField(self, field)
1865 setSheetFields(self, field_dict)
1866 setSheetParagraph(self, paragraph_code, paragraph_text)
1867 hasSheetParagraph(self, paragraph)
1868 getSheetParagraph(self, paragraph)
1869 setSheetParagraphs(self, paragraph_dict)
1870 setSheetRecord(self, record_code,field, section_dict)
1871 addFile(self, record_code, filename)
1872 setCompany(self, code, summary, name, offices, cif, web, email )
1873 getCompany
1874 getCompanyKeys
1875 addTecInfo(self, ti_code, text, unit)
1876 hasTecInfo(self, ti_code)
1877 getTecInfo(self, ti_code)
1878 setTecnicalInformation(self, _record_code, _ti_dict)
1879 changeCode(self, record_code, new_rocord_code)
1880 addLabel
1881 setParametricSelectComment
1882 setParametricSummary
1883 setParametricText
1884 """
1885
1886
1887 def __init__(self):
1888 """__init__(self)
1889
1890 Initialize the budget atributes
1891 """
1892 self.__title_index = 0
1893 self.__decimals = [Decimals(), Decimals()]
1894 self.__percentages = { "CI" : "" ,"GG": "", "BI": "",
1895 "BAJA": "", "IVA" : ""}
1896 self.__title_list = [ "", [ ] ]
1897 self.__root = None
1898 self.__file_owner = ""
1899 self.__comment = ""
1900 self.__budgetCerficateOrder = None
1901 self.__budgetCerficateDate = None
1902 self.__date = (0,0,0)
1903 self.__budgetType = 0
1904 self.__records = { }
1905 self.__synonyms = { }
1906 self.__sheet_sections = { }
1907 self.__sheet_fields = { }
1908 self.__sheet_paragraphs = { }
1909 self.__companys = { }
1910 self.__tec_info = { }
1911 self.__labels = { }
1912
1913 def __getstate__(self):
1914 return (self.__title_index, self.__decimals, self.__percentages,
1915 self.__title_list, self.__root, self.__file_owner,
1916 self.__records, self.__synonyms, self.__sheet_sections,
1917 self.__sheet_fields, self.__sheet_paragraphs,self.__companys,
1918 self.__tec_info, self.__labels)
1919
1920 def __setstate__(self, tuple):
1921 self.__title_index = tuple[0]
1922 self.__decimals = tuple[1]
1923 self.__percentages = tuple[3]
1924 self.__title_list = tuple[4]
1925 self.__root = tuple[4]
1926 self.__file_owner = tuple[5]
1927 self.__records = tuple[6]
1928 self.__synonyms = tuple[7]
1929 self.__sheet_sections = tuple[8]
1930 self.__sheet_fields = tuple[9]
1931 self.__sheet_paragraphs = tuple[10]
1932 self.__companys = tuple[11]
1933 self.__tec_info = tuple[12]
1934 self.__labels = tuple[13]
1935
1936 def iter(self):
1937 for record in self.__records:
1938 yield record
1939 def iterPreOrder(self, recordCode, codes=[]):
1940 _children = self.getchildren(recordCode)
1941 for _child in _children:
1942 if not _child in codes:
1943 codes.append(_child)
1944 self.iterPreOrder(_child, codes)
1945 return codes
1946 def iterPostOrder(self, recordCode, codes=[]):
1947 _children = self.getchildren(recordCode)
1948 for _child in _children:
1949 if not _child in codes:
1950 self.iterPreOrder(_child, codes)
1951 codes.append(_child)
1952 return codes
1953
1954 def getRoot(self):
1955 """getRoot(self)
1956
1957 Returns the root record code
1958 """
1959 return self.__root
1960
1961 def hasPath(self, path):
1962 """hasPath(self, path)
1963
1964 path: The path of the record in the budget, It is a tuple.
1965 Tests if the path is valid in the budget
1966 """
1967 try:
1968 self.getCode(path)
1969 return True
1970 except ValueError:
1971 return False
1972
1973 def getchildren(self, code):
1974 """getchildren(self, code)
1975
1976 code: a record code.
1977 Return a list whith the child codes of a record
1978 """
1979 _record = self.__records[code]
1980 _children = _record.children
1981 _child_code = [ _child.code for _child in _children ]
1982 return _child_code
1983 def setOwner(self, owner):
1984 """setOwner(self, owner)
1985
1986 owner: data owner
1987 Set the data owner.
1988 """
1989 if isinstance(owner, basestring):
1990 self.__file_owner = owner
1991 else:
1992 raise TypeError, _("Owner must be a string")
1993
1994 def setDate(self, date):
1995 """setOwner(self, date)
1996
1997 date (_y, _m, _d)
1998 Set the date when de file was generated
1999 """
2000 if isinstance(date, tuple) and len(date) == 3 and \
2001 isinstance(date[0], int) and isinstance(date[1], int) and \
2002 isinstance(date[2], int) and date[1] in range(13) and \
2003 date[2] in range(32):
2004 if date[1] != 0 and date[2] != 0:
2005 datetime.date(*date)
2006 self.__date = date
2007 else:
2008 raise TypeError, _("Invalid Date: %s" % str(date))
2009
2010 def setComment(self, comment):
2011 """setOwner(self, comment)
2012
2013 comment: text to comment the budged
2014 Set the comment.
2015 """
2016 if isinstance(comment, basestring):
2017 self.__comment = comment
2018 else:
2019 raise TypeError, _("Comment must be a string")
2020
2021 def setBudgeType(self, budget_type):
2022 """setOwner(self, budget_type)
2023
2024 budget_type: type of data in budget
2025 0 -> Undefined
2026 1 -> Base data.
2027 2 -> Budget.
2028 3 -> Budget certificate.
2029 4 -> Base date update.
2030 Set the budget type.
2031 """
2032 if budget_type in [1, 2, 3, 4]:
2033 self.__budgetType = budget_type
2034 else:
2035 raise ValueError, _("Budget type must be 1, 2, 3 or 4.")
2036
2037 def setCertificateOrder(self, certificate_order, certificate_date):
2038 """setOwner(self, budget_type)
2039
2040 certificate_order: certificate number
2041 certificate_date: certificate date
2042 Set the certificate order and date.
2043 """
2044 if isinstance(certificate_order, int):
2045 self.__budgetCerficateOrder = certificate_order
2046 else:
2047 raise ValueError, _("Certificate order must be a integer.")
2048
2049 def setCertificateDater(self, certificate_date):
2050 """setCertidicateDate(self, certificate_date)
2051
2052 Set the certificate date.
2053 """
2054 if isinstance(certificate_date, tuple) and \
2055 len(certificate_date) == 3 and \
2056 isinstance(certificate_date[0], int) and \
2057 isinstance(certificate_date[1], int) and \
2058 isinstance(certificate_date[2], int):
2059 datetime.date(*certificate_date)
2060 self.__budgetCerficateDate = certificate_date
2061 else:
2062 raise ValueError, _("Budget certificate Date must be a valid Date.")
2063
2064 def setTitleList(self, title_list):
2065 """setTitleList(self, title_list)
2066
2067 title_list: [ "Header", ["Title1", "Title2", ... ] ]
2068 Set the header and titles for the price groups and decimals.
2069 """
2070 title_list[0] = str(title_list[0])
2071 if isinstance(title_list, list) and isinstance(title_list[1], list):
2072 for i in range(len(title_list[1])):
2073 title_list[1][i] = str(title_list[1][i])
2074 self.__title_list = title_list
2075 else:
2076 raise TypeError, _("Invalid title list format")
2077
2078 def getTitleList(self):
2079 """ getTitleList(self)
2080
2081 Returns the header and titles for the price groups and decimals.
2082 """
2083 return self.__title_list
2084
2085 def getActiveTitle(self):
2086 """getActiveTitle(self)
2087
2088 Returns the active Title of price group
2089 """
2090 return self.__title_index
2091
2092 def setDecimals(self, dictionary, N):
2093 """setDecimals(self, dictionary, N)
2094
2095 dictionay: the decimal dictionary
2096 N: the price group
2097 Sets the Decimals for a price group.
2098 """
2099 if N == -1 or N == len(self.__decimals):
2100 _default_decimals = self.__decimals[0]
2101 self.__decimals.append(_default_decimals)
2102 elif N < len(self.__decimals):
2103 _default_decimals = self.__decimals[N]
2104 else:
2105 raise IndexError, _("Invalid Index Title")
2106 for _decimal in dictionary:
2107 if dictionary[_decimal] == "":
2108 dictionary[_decimal] = eval("_default_decimals." + _decimal)
2109 decimals = Decimals(dictionary["DN"], dictionary["DD"],
2110 dictionary["DSP"], dictionary["DS"],
2111 dictionary["DFC"],
2112 dictionary["DFPU"], dictionary["DFUO"],
2113 dictionary["DFA"], dictionary["DRC"],
2114 dictionary["DRPU"], dictionary["DRUO"],
2115 dictionary["DRA"], dictionary["DP"],
2116 dictionary["DC"], dictionary["DPU"],
2117 dictionary["DUO"], dictionary["DEA"],
2118 dictionary["DES"], dictionary["DIR"],
2119 dictionary["DIRC"], dictionary["DCD"],
2120 dictionary["DIVISA"])
2121 self.__decimals[N] = decimals
2122 def getDecimals(self, decimal="All", N=None):
2123 """getDecimals(self,decimal="All",N=None)
2124
2125 decimal:
2126 "All": Return a Decimals objet for a price group
2127 "keys": Return the keys of a Decimal object
2128 key: Return a Decimal value for a price group
2129 N: the price group None,1,2,..
2130 None: Return the active price group
2131 """
2132 if N is None: N = self.getActiveTitle()
2133 if decimal == "All":
2134 return self.__decimals[N+1]
2135 elif decimal == "keys":
2136 return self.__decimals[N+1].keys
2137 elif self.__decimals[N+1].haskey(decimal):
2138 return self.__decimals[N+1][decimal]
2139 else:
2140 raise KeyError, _("Decimal Key error")
2141
2142 def setPercentages(self, dictionary):
2143 """setPercentages(self, dictionary):
2144
2145 dictionary: the percentage dictionary
2146 Sets the percentage dictionary.
2147 """
2148 _default_percentages = self.__percentages
2149 for percentage in dictionary:
2150 if dictionary[percentage] == 0:
2151 dictionary[percentage] = ""
2152 elif dictionary[percentage] == "":
2153 dictionary[percentage] = _default_percentages[percentage]
2154 _percentages = { "CI": dictionary["CI"],
2155 "GG": dictionary["GG"],
2156 "BI": dictionary["BI"],
2157 "BAJA": dictionary["BAJA"],
2158 "IVA" : dictionary["IVA"]}
2159 self.__percentages = _percentages
2160
2161 def getPercentages(self, key="All"):
2162 """getPercentages(self, percentage="All")
2163
2164 key:
2165 "All": Return the Percentages dictionary
2166 "keys": Return the keys of a Percentages object
2167 key: Return a Percentages value for the key
2168 """
2169 if key == "All":
2170 return self.__percentages
2171 elif key == "keys":
2172 return self.__percentages.keys
2173 elif key in self.__percentages:
2174 return self.__percentages[key]
2175 else:
2176 raise KeyError, _("Invalid Percentage key")
2177
2178 def getAllParents(self,code):
2179 """getAllParents(self,code)
2180
2181 code: a record code.
2182 Returns a list with all the parents of a record
2183 All record which the record is in its descomposition list,
2184 including the parents of the parents
2185 """
2186 if code in self.__records:
2187 _parents = self.__records[code].parents
2188 if len(_parents) == 0: return [ ]
2189 for _antecesor in _parents[:]:
2190 _parents = _parents + self.getAllParents(_antecesor)
2191 return _parents
2192 else:
2193 return [ ]
2194
2195 def getAllchildren(self,code):
2196 """getAllchildren(self,code
2197
2198 code: a record code.
2199 Returns a list with all the children of a record, including
2200 the children of the children
2201 """
2202 if code in self.__records:
2203 _children = self.__records[code].children
2204 _children = [ _child.code for _child in _children ]
2205 for _child in _children[:]:
2206 _children = _children + self.getAllchildren(_child)
2207 return _children
2208 else:
2209 return [ ]
2210
2211 def getNDecomposition(self, code, N):
2212 """getDecomposition(self,path)
2213
2214 path: the path for a record
2215 Returns the Decomposition object of a record
2216 """
2217 _record = self.getRecord(code)
2218 _decomposition_list = _record.children
2219 _decomposition = _decomposition_list[N]
2220 return _decomposition
2221
2222 def getDecomposition(self, path):
2223 """getDecomposition(self,path)
2224
2225 path: the path for a record
2226 Returns the Decomposition object of a record
2227 """
2228 if path == (0,):
2229 _type = self.getRecord(self.__root).recordType
2230 return Decomposition( 0, self.__root,
2231 [Measure(self.getDecimals(), _type,
2232 0.0, [], "", 1.0, 1.0)])
2233 else:
2234 return self.getNDecomposition(self.getCode(path[:-1]), path[-1])
2235
2236 def getMeasure(self, path):
2237 """getMeasure(self, path)
2238
2239 path: the path for a record
2240 Return the measute object of a record
2241 """
2242 _decomposition = self.getDecomposition(path)
2243 _measure = _decomposition.budgetMeasures[0]
2244 return _measure
2245
2246 def getStrYield(self, measure, recordType):
2247 #_DR = measure.getDR(self.getDecimals())
2248 _DR = self.getDecimals().getDR(recordType)
2249 _yield = ("%." + str(_DR) + "f" ) % measure.yield_
2250 return _yield
2251
2252 def getStrFactor(self, measure, recorType):
2253 _DF = self.getDecimals().getDF(recordType)
2254 #_DF = measure.getDF(self.getDecimals())
2255 _factor = ("%." + str(_DF) + "f" ) % measure.factor
2256 return _factor
2257
2258 def setTree(self, code, child_code, position, factor, yield_, total,
2259 list_lines, label, type):
2260 """setTree(self, code, child_code, position, factor,yield_, total,
2261 list_lines, label, type)
2262
2263 code: the parent record code
2264 child_code: child record code
2265 position: position of child record in record parent record
2266 decomposition. Position == -1 -> new child
2267 factor:
2268 yield_:
2269 total: total measure (float)
2270 list_lines: list of measure lines
2271 [ [linetype, comment, units, length, width, height], ... ]
2272 linetype:
2273 empty string -> Normal
2274 1 -> Parcial Subtotal
2275 2 -> Accumulated Subtotal
2276 3 -> Formula, the comment is a formula.
2277 comment: Can be a descriptive text or a formula
2278 Valid Operator: '(', ')', '+', '-', '*', '/' and '^'
2279 Valid variable: 'a', 'b', 'c','d'y 'p' (Pi=3.1415926)
2280 units: Number of Units (a)
2281 length: Length (b)
2282 width: Width (c)
2283 height: Height (d)
2284 label: Record Identifiers that are used by some measure programs.
2285 type: type of action
2286 M: Set measure
2287 A: Add measure
2288 Sets the decomposition of a record in a child record
2289 """
2290 if not utils.is_valid_code(code)[0]:
2291 raise ValueError, utils.mapping(_("Invalid parent code: $1"),
2292 (code,))
2293 if not utils.is_valid_code(child_code)[0]:
2294 raise ValueError, utils.mapping(_("Invalid child code: $1"),
2295 (code,))
2296 if not isinstance(position, int):
2297 raise ValueError, utils.mapping(_("Invalid position in measure "\
2298 "$1, in code $2"), (parent_code, position))
2299 # Test circular references
2300 _all_parent_list = self.getAllParents(code) + [ code ]
2301 _all_child_list = self.getAllchildren(child_code) + [ child_code ]
2302 for _parent_code in _all_parent_list:
2303 if _parent_code in _all_child_list:
2304 # TODO: change return to except
2305 print utils.mapping(_("Circular Decomposition, parent code: "\
2306 "$1, child code: $2, repeated code: $3"),
2307 (code, child_code, _parent_code))
2308 return
2309 # Creating reference to parent code in child record
2310 if child_code in self.__records:
2311 _child_record = self.__records[child_code]
2312 else:
2313 _child_record = self.setRecord(child_code, [], -1, "", "", [], [],
2314 "", "")
2315 if code in self.__records:
2316 code = self.__records[code].code
2317 _child_record.appendParent(code)
2318 child_code = self.__records[child_code].code
2319 if code in self.__records:
2320 # if the code exits retake previous values.
2321 _record = self.__records[code]
2322 _child_number = len(_record.children)
2323 if position == -1:
2324 position = _child_number
2325 if position == _child_number:
2326 # The record do not have the child
2327 if not isinstance(factor, float): factor = 1.0
2328 if not isinstance(yield_, float): yield_ = 1.0
2329 if not isinstance(total, float): total = 0.0
2330 if not isinstance(list_lines, list): list_lines = []
2331 _child = _record.appendChild(child_code, self.getDecimals(),
2332 factor, yield_, total, list_lines, type, label)
2333 elif position < _child_number:
2334 # The record have the child
2335 _child = _record.children[position]
2336 if child_code != "" and child_code != _child.code:
2337 _child.code = child_code
2338 if factor != "" :
2339 if not isinstance(factor, float):
2340 factor == 1.0
2341 _child.budgetMeasures[0].setFactor(factor,
2342 self.getDecimals(), _record.recordType)
2343 if yield_ != "":
2344 if not isinstance(yield_, float):
2345 yield_ = 1.0
2346 _child.budgetMeasures[0].setYield(yield_,
2347 self.getDecimals(), _record.recordType)
2348 _measure = _child.budgetMeasures[0]
2349 if total != "":
2350 if not isinstance(total, float):
2351 yield_ = 0.0
2352 _measure.setMeasure(total, self.getDecimals())
2353 if isinstance(list_lines, list) and len(list_lines) > 0:
2354 _measure.buildMeasure(list_lines, type, self.getDecimals(),
2355 _record.recordType)
2356 if isinstance(label, str) and label != "" :
2357 _measure.label = label
2358 else:
2359 # TODO: change return for except
2360 print utils.mapping(_("Error: Invalid child position in "
2361 "decomposition. Parent code: $1 Child code: $2 "\
2362 "Position: $3"), (code, child_code, position))
2363 return
2364 else:
2365 if child_code == "" :
2366 print utils.mapping(_("Error: Empty child code. Parent code: "\
2367 "$1 Position: $2"), (code, position))
2368 return
2369 if position == -1:
2370 position = 0
2371 elif position != 0:
2372 print utils.mapping(_("Error: Invalid child position in "\
2373 "decomposition. Parent code: $1 Child code: $2 "\
2374 "Position: $3"), (code, child_code, position))
2375 return
2376 if not isinstance(factor, float):
2377 factor == 1.0
2378 if not isinstance(yield_, float):
2379 yield_ = 1.0
2380 _record = self.setRecord(code, [], "", "", "", [], [],
2381 "", "")
2382 _child = _record.appendChild(child_code, self.getDecimals(),
2383 factor, yield_, total, list_lines, type, label)
2384 _child.budgetMeasures[0] = measure
2385
2386 def eval_formula(self, formula, a, b, c, d):
2387 """eval_formula(self, formula, a, b, c, d)
2388
2389 formula:
2390 Valid Operator: '(', ')', '+', '-', '*', '/' and '^'
2391 Valid variable: 'a', 'b', 'c','d'y 'p' (Pi=3.1415926)
2392 units: Number of Units (a)
2393 length: Length (b)
2394 width: Width (c)
2395 height: Height (d)
2396
2397 Evals the formula and return the result
2398 """
2399 if a == "": a = 0.0
2400 if b == "": b = 0.0
2401 if c == "": c = 0.0
2402 if d == "": d = 0.0
2403 try:
2404 a = float(a)
2405 except:
2406 raise ValueError, _("'a' value must be a float number")
2407 try:
2408 b = float(b)
2409 except:
2410 raise ValueError, _("'b' value must be a float number")
2411 try:
2412 c = float(c)
2413 except:
2414 raise ValueError, _("'c' value must be a float number")
2415 try:
2416 d = float(d)
2417 except:
2418 raise ValueError, _("'d' value must be a float number")
2419 # spaces are erased
2420 sre.sub("[ ]","",formula)
2421 # operators and varibles are replaced
2422 formula = formula.replace("+", " + ")
2423 formula = formula.replace("-", " - ")
2424 formula = formula.replace("*", " * ")
2425 formula = formula.replace("/", " / ")
2426 formula = formula.replace("^", " ** ")
2427 formula = formula.replace("(", " ( ")
2428 formula = formula.replace(")", " ) ")
2429 formula = formula.replace("a", str(a))
2430 formula = formula.replace("b", str(b))
2431 formula = formula.replace("c", str(c))
2432 formula = formula.replace("d", str(d))
2433 formula = formula.replace("p", "3.1415926")
2434 _list_formula = formula.split(" ")
2435 _formula2 = ""
2436 for oper in _list_formula:
2437 try:
2438 _float_oper= str(float(oper))
2439 _formula2 = _formula2 + _float_oper
2440 except ValueError:
2441 _formula2 = _formula2 + oper
2442 _g = {"__builtins__":{}}
2443 try:
2444 return eval(_formula2, _g)
2445 except:
2446 raise ValueError, _("Invalid formula")
2447
2448 def getText(self,code):
2449 """getText(self,code)
2450
2451 code: the record code
2452 Returns the description text of a record
2453 """
2454 if code in self.__records:
2455 return self.__records[code].text
2456 else:
2457 raise IndexError, _("Invalid code")
2458
2459 def setText(self,code,text):
2460 """setText(self,code,text)
2461
2462 code: the parent record code
2463 text: the descripion text
2464 Sests the description text of a record
2465 """
2466 if not utils.is_valid_code(code)[0]:
2467 raise ValueError, utils.mapping(_("Invalid record: $1"), (code,))
2468 if not code in self.__records:
2469 _record = self.setRecord(code, [], "", "", "", [], [],
2470 "", "")
2471 _record.text = text
2472 else:
2473 _record = self.__records[code]
2474 _record.text = text
2475
2476 def setRecord(self, code, synonyms, hierarchy, unit, summary, price, date,
2477 type, subtype):
2478 """setRecord(self, code, synonyms, hierarchy, unit, summary, price,
2479 date, type, subtype)
2480
2481 code: Code string
2482 synonyms: List of synonym codes of the record
2483 hierarchy:
2484 0 -> root
2485 1 -> Chapter/Subchapter
2486 2 -> Other
2487 unit: unit of measure record
2488 summary: Short description of a record
2489 price: List of prices
2490 date: List of dates
2491 "type" and "subtype":
2492 0 Without classifying
2493 EA Auxiliary element
2494 EU Unitary element
2495 EC Complex element
2496 EF Functional element
2497 OB Construction site
2498 PA Cost overrun
2499 PU Unitary budget
2500 1 Labourforce
2501 H Labourforce
2502 2 Machinery and auxiliary equipment
2503 Q Machinery
2504 % Auxiliary equipment
2505 3 Building materials
2506 MC Cement
2507 MCr Ceramic
2508 MM Wood
2509 MS Iron and steel
2510 ME Energy
2511 MCu Copper
2512 MAl Aluminium
2513 ML Bonding agents
2514 M Others materials
2515 Hierarchy type subtype
2516 0->root -> 0 -> None,OB
2517 1->[sub]chapter -> 0 -> None,PU
2518 2->Other -> 0 -> None,EA,EU,EC,EF,PA
2519 1 -> None,H
2520 2 -> None,Q,%
2521 3 -> None,MC,MCr,MM,MS,ME,MCu,Mal,ML,M
2522 Adds a record in the budget
2523 """
2524 # hierarchy
2525 if hierarchy == 0 :
2526 # is the root record
2527 if self.__root is None:
2528 self.__root = code
2529 else:
2530 print _("Only can be one root record")
2531 return
2532 # retake previous values.
2533 # TODO: test synonyms
2534 _budget = self
2535 if not code in self.__records:
2536 if code[-1] == "$":
2537 _record = ParametricRecord(_budget.getDecimals(), code,
2538 synonyms, hierarchy,
2539 unit, summary, [], type, subtype,
2540 [], "")
2541 else:
2542 _record = Record(_budget.getDecimals(), code, synonyms,
2543 hierarchy, unit,
2544 summary, [], type, subtype,[], "")
2545 self.__records[code] = _record
2546 _prices = [[price[i], date[i]] for i in range(len(price))]
2547 _record.setPrices(_prices, self.getDecimals())
2548 else:
2549 _record = self.__records[code]
2550 code = _record.code
2551 if len(synonyms) != 0 and synonyms[0] == "":
2552 synonyms = _record.synonyms
2553 if unit == "":
2554 unit = _record.unit
2555 if summary == "":
2556 summary = _record.summary
2557 #TODO: test empty price list
2558 if len(price) == 0 or price[0] == "":
2559 _prices = _record.prices
2560 else:
2561 _prices = [ [price[i], date[i]] for i in range(len(price))]
2562 if type == "":
2563 type = _record.recordType.type
2564 _record.synonyms = synonyms
2565 _record.unit = unit
2566 _record.summary = summary
2567 _record.setPrices(_prices, self.getDecimals())
2568 _record.recordType.hierarchy = hierarchy
2569 _record.recordType.type = type
2570 _record.recordType.subtype = subtype
2571 return _record
2572
2573 def hasRecord(self,code):
2574 """hasRecord(self,code)
2575
2576 code: Code record
2577 Return True if the budget have this record code.
2578 """
2579 if code in self.__records:
2580 return True
2581 else:
2582 return False
2583
2584 def getRecord(self, code):
2585 """getRecord(self, code)
2586
2587 code: Code record
2588 Return the Record object
2589 """
2590 return self.__records[code]
2591
2592 def addPriceToRecord(self, price_date, record):
2593 """addPriceToRecord(self, price, record)
2594
2595 Add a price to the price list of the record.
2596 price must fulfill:
2597 - must be a list with two items
2598 - the first item: price must be a float
2599 """
2600 record.addPrice(price_date, self.getDecimals())
2601
2602 def getStrPriceFromRecord(self, index_price, record):
2603 _price = record.getPrice(index_price)
2604 _D = self.getDecimals().getD(record.recordType)
2605 _price = ("%." + str(_D) + "f" ) % _price
2606 return _price
2607
2608 def getCode(self, path):
2609 """getCode(self, path)
2610
2611 path: path record in the budget.
2612 Return the code record
2613 """
2614 if isinstance(path, tuple) and len(path)>= 1:
2615 if path[0] == 0:
2616 _code = self.__root
2617 for i in path[1:]:
2618 if isinstance(i, int):
2619 _record = self.__records[_code]
2620 _children_list = _record.children
2621 try:
2622 _child = _children_list[i]
2623 except:
2624 raise ValueError, _("This record does not exits")
2625 _code = _child.code
2626 else:
2627 raise ValueError, _("Path item must be a integer")
2628 return _code
2629 else:
2630 raise ValueError, _("This record does not exits")
2631 else:
2632 raise ValueError, utils.mapping(_("Path must be a not empty "\
2633 "tuple: $1"), (str(path),))
2634
2635 def getAmount(self, path):
2636 """def getAmount(self,path)
2637
2638 path: record path
2639 Calculate the record amount
2640 """
2641 if len(path) == 1:
2642 # root: amount is the root price
2643 _root = self.getRecord(self.getRoot())
2644 _amount = _root.getPrice(self.__title_index)
2645 return _amount
2646 else:
2647 _parent_code = self.getCode(path[:-1])
2648 _parent_record = self.getRecord(_parent_code)
2649 _child_number = path[-1]
2650
2651 _decomposition = _parent_record.children[_child_number]
2652 _factor = _decomposition.budgetMeasures[0].factor
2653 _yield = _decomposition.budgetMeasures[0].yield_
2654 _child_code = _decomposition.code
2655 _child_record = self.getRecord(_child_code)
2656 _price = _child_record.getPrice(self.getActiveTitle())
2657 _DR = self.getDecimals().getDR(_parent_record.recordType)
2658 _total_yield = round(_factor * _yield, _DR)
2659 _DI = self.getDecimals().getDI(_parent_record.recordType)
2660 _amount = round(_total_yield * _price, _DI)
2661 return _amount
2662
2663 def getStrAmount(self, path):
2664 """def getStrAmount(self, path)
2665
2666 path: record path
2667 Calculate the string record amount
2668 """
2669 if len(path) == 1: #root
2670 _root = self.getRecord(self.getRoot())
2671 _amount = self.getStrPriceFromRecord(self.__title_index, _root)
2672 return _amount
2673 else:
2674 _parent_code = self.getCode(path[:-1])
2675 _parent_record = self.getRecord(_parent_code)
2676 _amount = self.getAmount(path)
2677 _DI = self.getDecimals().getDI(_parent_record.recordType)
2678 _amount = ("%." + str(_DI) + "f") % _amount
2679 return _amount
2680
2681 def setSheetSection(self,sheet_code,sheet_title):
2682 if not isinstance(sheet_code, str):
2683 raise ValueError, _("The sheet code must be a string")
2684 if not isinstance(sheet_title, str):
2685 raise ValueError, _("The sheet title must be a string")
2686 self.__sheet_sections[sheet_code] = sheet_title
2687 def hasSheetSection(self, section):
2688 return section in self.__sheet_sections
2689 def getSheetSection(self, section):
2690 return self.__sheet_sections[section]
2691 def setSheetSections(self,dictionary):
2692 if not isinstance(dictionary, dict):
2693 raise ValueError, _("The sheet sections must be a dictionary")
2694 for sheet_code in dictionary.keys():
2695 self.setSheetSection(sheet_code, dictionary[sheet_code])
2696 def setSheetField(self, field_code, field_title):
2697 if not isinstance(field_code, str):
2698 raise ValueError, _("The field code must be a string")
2699 if not isinstance(field_title, str):
2700 raise ValueError, _("The field title must be a string")
2701 self.__sheet_fields[field_code] = field_title
2702 def hasSheetField(self, field):
2703 return field in self.__sheet_fields
2704 def getSheetField(self, field):
2705 return self.__sheet_fields[field]
2706 def setSheetFields(self, field_dict):
2707 if not isinstance(field_dict, dict):
2708 raise ValueError, _("The sheet field must be a dictionary")
2709 for field_code in field_dict.keys():
2710 self.setSheetField( field_code, field_dict[field_code])
2711 def setSheetParagraph(self, paragraph_code, paragraph_text):
2712 if not isinstance(paragraph_code, str):
2713 raise ValueError, _("The paragraph code must be a string")
2714 if not isinstance(paragraph_text, str):
2715 raise ValueError, _("The paragraph text must be a string")
2716 self.__sheet_paragraphs[paragraph_code] = paragraph_text
2717 def hasSheetParagraph(self, paragraph):
2718 return paragraph in self.__sheet_paragraphs
2719 def getSheetParagraph(self, paragraph):
2720 return self.__sheet_paragraphs[paragraph]
2721 def setSheetParagraphs(self, paragraph_dict):
2722 if not isinstance(paragraph_dict, dict):
2723 raise ValueError, _("The paragraph dict must be a dictionary")
2724 for paragraph_code in paragraph_dict.keys():
2725 self.setSheetParagraph( paragraph_code, paragraph_dict[paragraph_code])
2726 def setSheetRecord(self, record_code, field, section_dict):
2727 if not isinstance(record_code, str):
2728 raise ValueError, _("The record_code code must be a string")
2729 if not isinstance(field, str):
2730 raise ValueError, _("The field must be a string")
2731 if not isinstance(section_dict, dict):
2732 raise ValueError, _("The section dict must be a dictionary")
2733 #-#
2734 # TODO: Add a empty record?
2735 if not self.hasRecord(record_code):
2736 print utils.mapping(_("Error: The budget do not have this record "\
2737 "code and can not be added the sheet text in the field $1. "\
2738 "Record Code: $2"), ( field, record_code))
2739 return
2740 #-#
2741 if not self.hasSheetField(field):
2742 self.setSheetField(field, "")
2743 for section, paragraph in section_dict.iteritems():
2744 if not self.hasSheetParagraph(paragraph):
2745 self.setSheetParagraph(paragraph,"")
2746 if not self.hasSheetSection(section):
2747 self.setSheetSection(section, "")
2748 _sheet = self.getRecord(record_code).getSheet()
2749 _sheet.addSection(field, section, paragraph)
2750 def addFile(self, record_code, filepath, type, description):
2751 if not isinstance(record_code, str):
2752 raise ValueError, _("The record_code code must be a string")
2753 if not isinstance(filepath, str):
2754 raise ValueError, _("The filename must be a string")
2755 #-#
2756 # TODO: Add a empty record?
2757 if not self.hasRecord(record_code):
2758 print utils.mapping(_("Error: The budget do not have the record "\
2759 "code $1 and can not be added the file: $2"),
2760 (record_code, filepath))
2761 return
2762 #-#
2763 _record = self.getRecord(record_code)
2764 _record.addFile(filepath, type, description)
2765 def setCompany(self, company_code, sumamary, name, offices,
2766 cif, web, email):
2767 if not isinstance(company_code, str):
2768 raise ValueError, _("The company code must be a string")
2769 if not isinstance(sumamary, str):
2770 raise ValueError, _("The summary must be a string")
2771 if not isinstance(name, str):
2772 raise ValueError, _("The name must be a string")
2773 if not isinstance(offices, list):
2774 raise ValueError, _("The name must be a list")
2775 _offices = []
2776 for _office in offices:
2777 if not isinstance(_office, list):
2778 raise ValueError, _("The office must be a list")
2779 if not len(_office) == 10:
2780 raise ValueError, _("The office must be a 10 items list")
2781 for _item in _office[:7] + _office[9:10]:
2782 if not isinstance(_item, str):
2783 raise ValueError, _("This office item must be a "\
2784 "string")
2785 for _item in _office[7:8]:
2786 if not isinstance(_item, list):
2787 raise ValueError, _("This office item must be a "\
2788 "list")
2789 _offices.append(Office(_office[0],
2790 _office[1],
2791 _office[2],
2792 _office[3],
2793 _office[4],
2794 _office[5],
2795 _office[6],
2796 _office[7],
2797 _office[8],
2798 _office[9]))
2799 if not isinstance(cif, str):
2800 raise ValueError, _("The name must be a string")
2801 if not isinstance(web, str):
2802 raise ValueError, _("The web must be a string")
2803 if not isinstance(email, str):
2804 raise ValueError, _("The email must be a string")
2805
2806 self.__companys[company_code] = Company(company_code, sumamary, name,
2807 _offices, cif, web, email)
2808 def getCompany(self, company_code):
2809 return self.__companys[company_code]
2810 def getCompanyKeys(self):
2811 return self.__companys.keys()
2812 def addTecInfo(self, ti_code, text, unit):
2813 if not isinstance(ti_code, str):
2814 raise ValueError, _("The tecnical info code must be a string")
2815 if not isinstance(text, str):
2816 raise ValueError, _("The tecnical info description must be a "\
2817 "string")
2818 if not isinstance(unit, str):
2819 raise ValueError, _("The tecnical info unit must be a string")
2820 self.__tec_info[ti_code] = [text, unit]
2821 def hasTecInfo(self, ti_code):
2822 return ti_code in self.__tec_info
2823 def getTecInfo(self, ti_code):
2824 return self.__tec_info[ti_code]
2825 def setTecnicalInformation(self, record_code, ti_dict):
2826 """setTecnicalInformation(record_code, ti_dict)
2827
2828 Sets the tecnical information to a record
2829 record_code: the record code
2830 ti_dict: {ti_code : ti_value}
2831 """
2832 # TODO: setTecnicalInformation
2833 pass
2834 def changeCode(self, record_code, new_record_code):
2835 """changeCode(self, record_code, new_record_code):
2836
2837 Change the record code for a new recor code.
2838 """
2839 if self.hasRecord(record_code) and not self.hasRecord(new_record_code):
2840 _record = self.__records[code]
2841 _record.code = new_record_code
2842 _parents = _record.parents
2843 for _parent in _parents:
2844 _decomposition_list = self.__records[_parent].children
2845 for _decomposition in _decomposition_list:
2846 if _decomposition.code == record_code:
2847 _decomposition.code = new_record_code
2848 break
2849 _children = self.getchildren(record_code)
2850 for _child in _children:
2851 _parents_list = self.__records[_child].parents
2852 for index in range(len(_parents_list)):
2853 if _parents_list[index] == record_code:
2854 _parents_list[index] = new_record_code
2855 break
2856 self.__records[new_record_code] = _record
2857 del self.__records[record_code]
2858 # TODO: attachment files
2859
2860 def addLabel(self, record_code, label):
2861 """addLabel(self, record_code, label)
2862
2863 Add a label to a record
2864 """
2865 if not isinstance(label,str):
2866 raise ValueError, _("The label must be a string")
2867 if self.hasRecord(record_code):
2868 _record = self.__records[record_code]
2869 _record.addLabel(label)
2870 if not label in self.__labels:
2871 self.__labels[label] = [record_code]
2872 else:
2873 _codes = self.__labels[label]
2874 if not record_code in _codes:
2875 _codes.append(record_code)
2876 def setParametricSelectComment(self, record_code, comment):
2877 """setParametricSelectComment(self, record_code, comment)
2878
2879 Sets Paramtric Record Select Comment
2880 """
2881 if not isinstance(record_code, str):
2882 raise ValueError, _("The record_code code must be a string")
2883 if not isinstance(comment, str):
2884 raise ValueError, _("The parametric select comment must be a "\
2885 "string")
2886 if not self.hasRecord(record_code):
2887 print utils.mapping(_("Error: The budget do not have the record "\
2888 "code $1 and can not be added the Parametric select comment: "\
2889 "$2"),
2890 (record_code, comment))
2891 return
2892 _record = self.getRecord(record_code)
2893 if not isinstance(_record, ParametricRecord):
2894 print utils.mapping(_("Error: The Record $1 is not a "\
2895 "Parametric Record and can not have Parametric comment"),
2896 (record_code,))
2897 else:
2898 _record.select_comment = comment
2899
2900 def setParametricSummary(self, record_code, summary):
2901 """setParametricSummary(self, record_code, summary)
2902
2903 Sets parametric record summary
2904 """
2905 if not isinstance(record_code, str):
2906 raise ValueError, _("The record_code code must be a string")
2907 if not isinstance(summary, str):
2908 raise ValueError, _("The summary record must be a string")
2909 if not self.hasRecord(record_code):
2910 print utils.mapping(_("Error: The budget do not have the record "\
2911 "code $1 and can not be seted the summary: $2"),
2912 (record_code, summary))
2913 return
2914 _record = self.getRecord(record_code)
2915 if not isinstance(_record, ParametricRecord):
2916 print utils.mapping(_("Error: The Record $1 is not a "\
2917 "Parametric Record and can not have Parametric summary"),
2918 (record_code,))
2919 else:
2920 self.getRecord(record_code).parametric_summary = summary
2921
2922 def setParametricText(self, record_code, text):
2923 """setParametricText(self, record_code, text)
2924
2925 Sets parametric record text
2926 """
2927 if not isinstance(record_code, str):
2928 raise ValueError, _("The record_code code must be a string")
2929 if not isinstance(text, str):
2930 raise ValueError, _("The text record must be a string")
2931 if not self.hasRecord(record_code):
2932 print utils.mapping(_("Error: The budget do not have the record "\
2933 "code $1 and can not be seted the text: $2"),
2934 (record_code, text))
2935 return
2936 _record = self.getRecord(record_code)
2937 if not isinstance(_record, ParametricRecord):
2938 print utils.mapping(_("Error: The Record $1 is not a "\
2939 "Parametric Record and can not have Parametric text"),
2940 (record_code,))
2941 else:
2942 self.getRecord(record_code).parametric_text = text
2943
2944 class Office(object):
2945 """base.Office:
2946
2947 Description:
2948 Office of a company
2949 Constructor:
2950 base.Office(type, subname, address, postal_code, town, province,
2951 country, phone, fax, contact_person)
2952 Ancestry:
2953 +-- object
2954 +-- Office
2955 Atributes:
2956 "officeType" : type of Office
2957 are defined:
2958 "C" Central.
2959 "D" Local Office.
2960 "R" performer.
2961 "subname" : name of Office or Performer
2962 "address" :
2963 "postal_code" :
2964 "town" :
2965 "province" :
2966 "country" :
2967 "phone" : list of phone numbers
2968 "fax" : list of fax numbers
2969 "contact_person" : name of contact person
2970 "values":
2971 Methods:
2972 __getstate__(self)
2973 __setstate__(self, tuple)
2974 __init__(self, measure, lines, label)
2975 {get/set}OfficeType
2976 {get/set}Subname
2977 {get/set}Address
2978 {get/set}PostalCode
2979 {get/set}Town
2980 {get/set}Province
2981 {get/set}Country
2982 {get/set}Phone
2983 {get/set}Fax
2984 {get/set}ContactPerson
2985 getValues
2986 """
2987 __slots__ = ["_Office__officeType",
2988 "_Office__subname",
2989 "_Office__address",
2990 "_Office__postal_code",
2991 "_Office__town",
2992 "_Office__province",
2993 "_Office__country",
2994 "_Office__phone",
2995 "_Office__fax",
2996 "_Office__contact_person",
2997 ]
2998 def __getstate__ (self):
2999 return ( self.__officeType,
3000 self.__subname,
3001 self.__address,
3002 self.__postal_code,
3003 self.__town,
3004 self.__province,
3005 self.__country,
3006 self.__phone,
3007 self.__fax,
3008 self.__contact_person)
3009 def __setstate__(self,tuple):
3010 self.__officeType = tuple[0]
3011 self.__subname = tuple[1]
3012 self.__address = tuple[2]
3013 self.__postal_code = tuple[3]
3014 self.__town = tuple[4]
3015 self.__province = tuple[5]
3016 self.__country = tuple[6]
3017 self.__phone = tuple[7]
3018 self.__fax = tuple[8]
3019 self.__contact_person = tuple[9]
3020
3021 def __init__(self, type, subname, address, postal_code, town, province,
3022 country, phone, fax, contact_person):
3023 self.officeType = type
3024 self.subname = subname
3025 self.address = address
3026 self.postal_code = postal_code
3027 self.town = town
3028 self.province = province
3029 self.country = country
3030 self.phone = phone
3031 self.fax = fax
3032 self.contact_person = contact_person
3033 def getOfficeType(self):
3034 return self.__officeType
3035 def setOfficeType(self, type):
3036 self.__officeType = type
3037 def getSubname(self):
3038 return self.__subname
3039 def setSubname(self, subname):
3040 self.__subname = subname
3041 def getAddress(self):
3042 return self.__address
3043 def setAddress(self, address):
3044 self.__address = address
3045 def getPostalCode(self):
3046 return self.__postal_code
3047 def setPostalCode(self, postal_code):
3048 self.__postal_code = postal_code
3049 def getTown(self):
3050 return self.__town
3051 def setTown(self, town):
3052 self.__town = town
3053 def getProvince(self):
3054 return self.__province
3055 def setProvince(self, province):
3056 self.__province = province
3057 def getCountry(self):
3058 return self.__country
3059 def setCountry(self, country):
3060 self.__country = country
3061 def getPhone(self):
3062 return self.__phone
3063 def setPhone(self, phone):
3064 self.__phone = phone
3065 def getFax(self):
3066 return self.__fax
3067 def setFax(self, fax):
3068 self.__fax = fax
3069 def getContactPerson(self):
3070 return self.__contact_person
3071 def setContactPerson(self, contact_person):
3072 self.__contact_person = contact_person
3073 def getValues(self):
3074 return {"officeType": self.officeType,
3075 "subname": self.subname,
3076 "address": self.address,
3077 "postal code": self.postal_code,
3078 "town": self.town,
3079 "province": self.province,
3080 "country": self.country,
3081 "phone": self.phone,
3082 "fax": self.fax,
3083 "contact person": self.contact_person,
3084 }
3085 officeType = property(getOfficeType, setOfficeType, None,
3086 """Type of office
3087 """)
3088 subname = property(getSubname, setSubname, None,
3089 """Name of office
3090 """)
3091 address = property(getAddress, setAddress, None,
3092 """Adress
3093 """)
3094 postal_code = property(getPostalCode, setPostalCode, None,
3095 """Postal code
3096 """)
3097 town = property(getTown, setTown, None,
3098 """Town
3099 """)
3100 province = property(getProvince, setProvince, None,
3101 """Province
3102 """)
3103 country = property(getCountry, setCountry, None,
3104 """Country
3105 """)
3106 phone = property(getPhone, setPhone, None,
3107 """Phone numbers
3108 """)
3109 fax = property(getFax, setFax, None,
3110 """Fax numbers
3111 """)
3112 contact_person = property(getContactPerson, setContactPerson, None,
3113 """Contact Person
3114 """)
3115 values = property(getValues, None, None,
3116 """Dictionary with comapany values
3117 """)
3118
3119 class Company(object):
3120 """base.Company:
3121
3122 Description:
3123 Company object
3124 __slots__ attribute, __getstate__ and __setstate__ method are defined
3125 to use less ram memory.
3126 Constructor:
3127 base.Company(code, summary, name, offices, cif, web, email)
3128 Ancestry:
3129 +-- object
3130 +-- Company
3131 Atributes:
3132 "code": code to indentifie the company in the buget
3133 "summary": short name
3134 "name": long name
3135 "offices": List of Offices
3136 "cif": CIF
3137 "web": web page
3138 "email": email
3139 "values":
3140 Methods:
3141 __getstate__(self)
3142 __setstate__(self, tuple)
3143 __init__(self, measure, lines, label)
3144 {get/set}Code
3145 {get/set}Summary
3146 {get/set}Name
3147 {get/set}Offices
3148 {get/set}Cif
3149 {get/set}Web
3150 {get/set}Email
3151 getValues
3152 """
3153 __slots__ = ["_Company__code",
3154 "_Company__summary",
3155 "_Company__name",
3156 "_Company__offices",
3157 "_Company__cif",
3158 "_Company__web",
3159 "_Company__email",
3160 ]
3161 def __getstate__ (self):
3162 return ( self.__code,
3163 self.__summary,
3164 self.__name,
3165 self.__offices,
3166 self.__cif,
3167 self.__web,
3168 self.__email)
3169 def __setstate__(self,tuple):
3170 self.__code = tuple[0]
3171 self.__summary = tuple[1]
3172 self.__name = tuple[2]
3173 self.__offices = tuple[3]
3174 self.__cif = tuple[4]
3175 self.__web = tuple[5]
3176 self.__email = tuple[6]
3177
3178 def __init__(self, code, summary, name, offices, cif, web, email):
3179 self.code = code
3180 self.summary = summary
3181 self.name = name
3182 self.offices = offices
3183 self.cif = cif
3184 self.web = web
3185 self.email = email
3186 def getCode(self):
3187 return self.__code
3188 def setCode(self, code):
3189 self.__code = code
3190 def getSummary(self):
3191 return self.__summary
3192 def setSummary(self, summary):
3193 self.__summary = summary
3194 def getName(self):
3195 return self.__name
3196 def setName(self, name):
3197 self.__name = name
3198 def getOffices(self):
3199 return self.__offices
3200 def setOffices(self, offices):
3201 self.__offices = offices
3202 def getCif(self):
3203 return self.__cif
3204 def setCif(self, cif):
3205 self.__cif = cif
3206 def getWeb(self):
3207 return self.__web
3208 def setWeb(self, web):
3209 self.__web = web
3210 def getEmail(self):
3211 return self.__email
3212 def setEmail(self, email):
3213 self.__email = email
3214 def getValues(self):
3215 return {"code": self.code,
3216 "summary": self.summary,
3217 "name": self.name,
3218 "cif": self.cif,
3219 "web": self.web,
3220 "email": self.email}
3221 code = property(getCode, setCode, None,
3222 """Company code
3223 """)
3224 summary = property(getSummary, setSummary, None,
3225 """Company summary
3226 """)
3227 name = property(getName, setName, None,
3228 """Company name
3229 """)
3230 offices = property(getOffices, setOffices, None,
3231 """List of Offices
3232 """)
3233 cif = property(getCif, setCif, None,
3234 """CIF
3235 """)
3236 web = property(getWeb, setWeb, None,
3237 """Web page
3238 """)
3239 email = property(getEmail, setEmail, None,
3240 """Email
3241 """)
3242 values = property(getValues, None, None,
3243 """Dictionary with comapany values
3244 """)
3245
3246 class File(object):
3247 """base.Company:
3248
3249 Description:
3250 File object
3251 Constructor:
3252 base.File(name, type, description)
3253 Ancestry:
3254 +-- object
3255 +-- File
3256 Atributes:
3257 "name": name
3258 "fileType": type of file
3259 "description": description file
3260 Methods:
3261 __getstate__(self)
3262 __setstate__(self, tuple)
3263 __init__(self, path,type, description)
3264 {get/set}Name
3265 {get/set}FileType
3266 {get/set}Description
3267 getValues
3268 """
3269 __slots__ = ["_File__name",
3270 "_File__fileType",
3271 "_File__description",
3272
3273 ]
3274 def __getstate__ (self):
3275 return (self.__name,
3276 self.__description,
3277 self.__fileType,
3278 )
3279 def __setstate__(self,tuple):
3280 self.__name = tuple[0]
3281 self.__fileType = tuple[1]
3282 self.__description = tuple[2]
3283 def __init__(self, name, type, description):
3284 self.name = name
3285 self.fileType = type
3286 self.description = description
3287 def getName(self):
3288 return self.__name
3289 def setName(self, name):
3290 self.__name = name
3291 def getFileType(self):
3292 return self.__fileType
3293 def setFileType(self, type):
3294 self.__fileType = type
3295 def getDescription(self):
3296 return self.__description
3297 def setDescription(self, description):
3298 self.__description = description
3299 def getValues(self):
3300 return {"name": self.name,
3301 "fileType": self.fileType,
3302 "description": self.description,
3303 }
3304 name = property(getName, setName, None,
3305 """File name
3306 """)
3307 fileType = property(getFileType, setFileType, None,
3308 """FileType
3309 """)
3310 description = property(getDescription, setDescription, None,
3311 """File description
3312 """)
3313 values = property(getValues, None, None,
3314 """Dictionary with file values
3315 """)
3316
3317 class RecordType(object):
3318 """base.RecordType:
3319
3320 Description:
3321 Record Type object
3322 "hierarchy":
3323 -1 -> temporarily unfixed
3324 0 -> root
3325 1 -> Chapter/Subchapter
3326 2 -> Other
3327 "type" and "subtype":
3328 0 Without classifying
3329 EA Auxiliary element
3330 EU Unitary element
3331 EC Complex element
3332 EF Functional element
3333 OB Construction site
3334 PA Cost overrun
3335 PU Unitary budget
3336 1 Labourforce
3337 H Labourforce
3338 2 Machinery and auxiliary equipment
3339 Q Machinery
3340 % Auxiliary equipment
3341 3 Building materials
3342 MC Cement
3343 MCr Ceramic
3344 MM Wood
3345 MS Iron and steel
3346 ME Energy
3347 MCu Copper
3348 MAl Aluminium
3349 ML Bonding agents
3350 M Others materials
3351 Hierarchy type subtype
3352 0->root -> 0 -> None,OB
3353 1->[sub]chapter -> 0 -> None,PU
3354 2->Other -> 0 -> None,EA,EU,EC,EF,PA
3355 1 -> None,H
3356 2 -> None,Q,%
3357 3 -> None,MC,MCr,MM,MS,ME,MCu,Mal,ML,M
3358 Constructor:
3359 base.File(hierarchy,type,subtype)
3360 Ancestry:
3361 +-- object
3362 +-- RecordType
3363 Atributes:
3364 "hierarchy": hierarchy
3365 "type": type
3366 "subtype": subtype
3367 Methods:
3368 __getstate__(self)
3369 __setstate__(self, tuple)
3370 __init__(self, hierarchy, type, subtype)
3371 {get/set}Hierarchy
3372 {get/set}Type
3373 {get/set}Subtype
3374 """
3375 __slots__ = ["_RecordType__hierarchy",
3376 "_RecordType__type",
3377 "_RecordType__subtype",
3378 ]
3379 def __getstate__ (self):
3380 return (self.__hierarchy,
3381 self.__type,
3382 self.__subtype,
3383 )
3384 def __setstate__(self,tuple):
3385 self.__hierarchy = tuple[0]
3386 self.__type = tuple[1]
3387 self.__subtype = tuple[2]
3388 def __init__(self, hierarchy, type, subtype):
3389 self.hierarchy = hierarchy
3390 self.type = type
3391 self.subtype = subtype
3392 def getHierarchy(self):
3393 return self.__hierarchy
3394 def setHierarchy(self, hierarchy):
3395 if not hierarchy in [-1, 0 , 1 ,2]:
3396 raise ValueError, utils.mapping(_("Invalid Hierarchy ($1) "\
3397 "The hierarchy must be -1, 0, 1 or 2"), (str(hierarchy)))
3398 self.__hierarchy = hierarchy
3399 def getType(self):
3400 return self.__type
3401 def setType(self, type):
3402 if not type in ["", 0, 1, 2, 3] :
3403 raise ValueError, utils.mapping(_("Invalid type ($1),"\
3404 "the type must be (empty string,0,1,2,3)"),(str(type)))
3405 self.__type = type
3406 def getSubtype(self):
3407 return self.__subtype
3408 def setSubtype(self, subtype):
3409 if not subtype in ["", "OB", "PU", "EA", "EU", "EC", "EF", "PA", "H",
3410 "Q", "%", "MC", "MCr", "MM", "MS", "ME", "MCu",
3411 "Mal","ML","M"]:
3412 raise ValueError, utils.mapping(_("Invalid subtype ($1), The "\
3413 "subtype must one in (empty string, EA, "\
3414 "EU, EC, EF, OB, PA, PU, H, Q, %, MC, MCr, "\
3415 "MM, MS, ME, MCu, MAl, ML, M)"), (str(subtype)))
3416 self.__subtype = subtype
3417 hierarchy = property(getHierarchy, setHierarchy, None,
3418 """Record Hierarchy
3419 -1 -> temporarily unfixed
3420 0 -> root
3421 1 -> Chapter/Subchapter
3422 2 -> Other
3423 """)
3424 type = property(getType, setType, None,
3425 """Record Type
3426 0 Without classifying
3427 1 Labourforce
3428 2 Machinery and auxiliary equipment
3429 3 Building materials
3430 """)
3431 subtype = property(getSubtype, setSubtype, None,
3432 """Record Subtype
3433 None
3434 EA Auxiliary element
3435 EU Unitary element
3436 EC Complex element
3437 EF Functional element
3438 OB Construction site
3439 PA Cost overrun
3440 PU Unitary budget
3441 H Labourforce
3442 Q Machinery
3443 % Auxiliary equipment
3444 MC Cement
3445 MCr Ceramic
3446 MM Wood
3447 MS Iron and steel
3448 ME Energy
3449 MCu Copper
3450 MAl Aluminium
3451 ML Bonding agents
3452 M Others materials
3453 """)