def __init__( self, id=None, title=None, comment=None, quantity=None, quantity_format=None, quantity_b=None, quantity_b_format=None, tax=None, hour_rate=None, wage_add=None, wage_add_explain=None ): """Initialize the class.""" # values of the BaseEntry class super(MultiplyEntry, self).__init__( id=id, title=title, comment=comment, quantity=quantity, quantity_format=quantity_format, quantity_b=quantity_b, quantity_b_format=quantity_b_format, tax=tax ) # new values for this class self._hour_rate = QuantityTime(hour_rate) self._wage_add = QuantityTime(wage_add) self.wage_add_explain = '' if wage_add_explain is None else str(wage_add_explain)
def get_time(self, entry_list=None, *args, **kwargs): """ Get time according to entry_list or zero. entry_list is the global list holding all entry-objects. This function calculates the time respecting the entries from the entry_list. The ConnectEntry class is an entry for multiplying entries times or only prices (depenging on self.is_time()) - e.g. licences can cost x-times multiplied the original working time of a task. This class can calculate it. """ # if is_time() == False or entry_list not a list, return 0 if not self.get_is_time() or type(entry_list) is not list: return QuantityTime('0:00') # is_time() == True, calculate time respecting other entires else: # otherwise iterate through entry_list and find # entries which ids exist in the self._connected list out = QuantityTime('0:00') for entry in entry_list: if entry.get_id() in self._connected: # if its in the list, multiply its time and add it out += (self.get_multiplicator() * entry.get_time(entry_list=entry_list)) # return the result return out * self._quantity * self._quantity_b
def test_offer_data_structure(): """Test the data structure for offer and appended entries.""" myoffer = TestOffer().out # first check for title of second entry assert myoffer.get_entry_list()[1].title == 'Multiply title' # check time of third entry t = myoffer.get_entry_list()[2].get_time(myoffer.get_entry_list()) assert t == QuantityTime(0) # connect connected entry to base entry (3rd entry to 1st) myoffer.get_entry_list()[2].connect_entry( entry_list=myoffer.get_entry_list(), entry_id=myoffer.get_entry_list()[0].get_id()) # now time of third entry is 2 * 3 * 2.5 hours t = myoffer.get_entry_list()[2].get_time(myoffer.get_entry_list()) multi = 2 * 3 * QuantityTime(2.5) assert t == multi
def get_time_total(self): """Get times of entries summerized.""" # init output variable out = QuantityTime('0:00') # iterate through the entries and get its time for e in self._entry_list: out += e.get_time(entry_list=self._entry_list) # return it return out
def update_entry(entry=None, quantity=None): """Try to return new entry with updated quantity etc.""" is_entry = check_objects.is_entry(entry) quantity = str(quantity) if not is_entry: return entry # it's no MultiplyEntry if type(entry) is not MultiplyEntry: entry.quantity_format = quantity return entry # it's a multiply entry: try to convert given quantity to QuantityTime and string # first split the given quantity s = quantity.split(' ') # quantity string given as well if len(s) > 1: # set new quantity format entry.quantity_format = '{s} ' + ' '.join(s[1:]) # only one thign entered else: # set new quantity format entry.quantity_format = '{s}' # get the quantity number quantity_number = QuantityTime(s[0]) # first given thing is a number > 0 if quantity_number > 0: # calculate the new hour rate hour_rate = entry.get_quantity() / quantity_number # set new hour rate entry.set_hour_rate(hour_rate) # set new quantity entry.set_quantity(quantity_number) # it's something else, set quantity_format from argument and leave quantity else: entry.quantity_format = quantity return entry
def __init__( self, id=None, title=None, comment=None, quantity=None, quantity_format=None, quantity_b=None, quantity_b_format=None, tax=None, time=None, price=None, connected=None ): """Init the class.""" # gen ID if not set, otherwise get it from argument self._id = str(uuid.uuid1()) if id is None else str(id) # get other variables from arguments self.title = '' if title is None else str(title) self.comment = '' if comment is None else str(comment) self._quantity = QuantityTime(quantity) self.quantity_format = '' if quantity_format is None else str(quantity_format) if quantity_b is None: self._quantity_b = QuantityTime(1) else: self._quantity_b = QuantityTime(quantity_b) self.quantity_b_format = ( '' if quantity_b_format is None else str(quantity_b_format) ) self._tax = Decimal(0) # set default self.set_tax(tax) # try to set arguments value self._time = QuantityTime(time) self._price = Decimal(0) # set default self.set_price(price) # try to set arguments value # get the connected list (for ConnectEntry only) if type(connected) is set: self._connected = connected else: self._connected = set()
class Default(object): """Settings class.""" def __init__( self, data_path=None, language=None, offer_title=None, offer_comment=None, offer_comment_b=None, offer_filename=None, offer_round_price=None, offer_templates=None, invoice_title=None, invoice_id=None, invoice_comment=None, invoice_comment_b=None, invoice_filename=None, invoice_round_price=None, invoice_templates=None, invoice_due_days=None, invoice_delivery=None, invoice_ledger_comment=None, date_fmt=None, commodity=None, client_id=None, client_company=None, client_company_b=None, client_attention=None, client_salutation=None, client_name=None, client_family_name=None, client_street=None, client_post_code=None, client_city=None, client_country=None, client_tax_id=None, client_language=None, project_title=None, project_hours_per_day=None, project_work_days=None, project_minimum_days=None, project_wage=None, baseentry_title=None, baseentry_comment=None, baseentry_quantity=None, baseentry_quantity_format=None, baseentry_quantity_b=None, baseentry_quantity_b_format=None, baseentry_time=None, baseentry_price=None, multiplyentry_title=None, multiplyentry_comment=None, multiplyentry_quantity=None, multiplyentry_quantity_format=None, multiplyentry_quantity_b=None, multiplyentry_quantity_b_format=None, multiplyentry_hour_rate=None, connectentry_title=None, connectentry_comment=None, connectentry_quantity=None, connectentry_quantity_format=None, connectentry_quantity_b=None, connectentry_quantity_b_format=None, connectentry_is_time=None, connectentry_multiplicator=None, ledger_time_def_quantity=None ): """Initialize the class and hard code defaults, if no file is given.""" self.language = 'NEW' if language is None else language self.offer_title = '' if offer_title is None else offer_title self.offer_comment = '' if offer_comment is None else offer_comment self.offer_comment_b = '' if offer_comment_b is None else offer_comment_b self.offer_filename = '' if offer_filename is None else offer_filename self.set_offer_round_price( False if offer_round_price is None else offer_round_price ) self._offer_templates = {} # set default self.set_offer_templates(offer_templates) # try to set arguments value self.invoice_title = '' if invoice_title is None else invoice_title self.invoice_id = '' if invoice_id is None else invoice_id self.invoice_comment = '' if invoice_comment is None else invoice_comment self.invoice_comment_b = '' if invoice_comment_b is None else invoice_comment_b self.invoice_filename = '' if invoice_filename is None else invoice_filename self.set_invoice_round_price( False if invoice_round_price is None else invoice_round_price ) self._invoice_templates = {} # set default self.set_invoice_templates(invoice_templates) # try to set arguments value self._invoice_due_days = 14 # set default self.set_invoice_due_days(invoice_due_days) # try to set arguments value self.invoice_delivery = '' if invoice_delivery is None else invoice_delivery self.invoice_ledger_comment = ( '' if invoice_ledger_comment is None else invoice_ledger_comment ) self.date_fmt = '' if date_fmt is None else date_fmt self.commodity = '' if commodity is None else commodity # client default values self.client_id = '{CLIENT_COUNT}' if client_id is None else client_id self.client_company = '' if client_company is None else client_company self.client_company_b = '' if client_company_b is None else client_company_b self.client_attention = 'Attn.' if client_attention is None else client_attention self.client_salutation = '' if client_salutation is None else client_salutation self.client_name = '' if client_name is None else client_name self.client_family_name = '' if client_family_name is None else client_family_name self.client_street = '' if client_street is None else client_street self.client_post_code = '' if client_post_code is None else client_post_code self.client_city = '' if client_city is None else client_city self.client_country = '' if client_country is None else client_country self.client_tax_id = '' if client_tax_id is None else client_tax_id self.client_language = 'en' if client_language is None else client_language # project default values self.project_title = '{PROJECT_COUNT}' if project_title is None else project_title self._project_hours_per_day = 0 self.set_project_hours_per_day(project_hours_per_day) self._project_work_days = [0, 1, 2, 3, 4] self.set_project_work_days(project_work_days) self._project_minimum_days = 2 self.set_project_minimum_days(project_minimum_days) self._project_wage = Decimal(0) self.set_project_wage(project_wage) # baseentry default values self.baseentry_title = '' if baseentry_title is None else baseentry_title self.baseentry_comment = '' if baseentry_comment is None else baseentry_comment self._baseentry_quantity = QuantityTime(baseentry_quantity) self.baseentry_quantity_format = ( '' if baseentry_quantity_format is None else baseentry_quantity_format ) if baseentry_quantity_b is None: self._baseentry_quantity_b = QuantityTime(1) else: self._baseentry_quantity_b = QuantityTime(baseentry_quantity_b) self.baseentry_quantity_b_format = ( '' if baseentry_quantity_b_format is None else baseentry_quantity_b_format ) self._baseentry_time = QuantityTime(baseentry_time) self._baseentry_price = Decimal(0) self.set_baseentry_price(baseentry_price) # multiplyentry default values self.multiplyentry_title = ( '' if multiplyentry_title is None else multiplyentry_title ) self.multiplyentry_comment = ( '' if multiplyentry_comment is None else multiplyentry_comment ) self._multiplyentry_quantity = QuantityTime(multiplyentry_quantity) self.multiplyentry_quantity_format = ( '' if multiplyentry_quantity_format is None else multiplyentry_quantity_format ) if multiplyentry_quantity_b is None: self._multiplyentry_quantity_b = QuantityTime(1) else: self._multiplyentry_quantity_b = QuantityTime(multiplyentry_quantity_b) self.multiplyentry_quantity_b_format = ( '' if multiplyentry_quantity_b_format is None else multiplyentry_quantity_b_format ) self._multiplyentry_hour_rate = QuantityTime(multiplyentry_hour_rate) # connectentry default values self.connectentry_title = ( '' if connectentry_title is None else connectentry_title ) self.connectentry_comment = ( '' if connectentry_comment is None else connectentry_comment ) self._connectentry_quantity = QuantityTime(connectentry_quantity) self.connectentry_quantity_format = ( '' if connectentry_quantity_format is None else connectentry_quantity_format ) if connectentry_quantity_b is None: self._connectentry_quantity_b = QuantityTime(1) else: self._connectentry_quantity_b = QuantityTime(connectentry_quantity_b) self.connectentry_quantity_b_format = ( '' if connectentry_quantity_b_format is None else connectentry_quantity_b_format ) self.set_connectentry_is_time( True if connectentry_is_time is None else connectentry_is_time ) self._connectentry_multiplicator = Decimal(0) self.set_connectentry_multiplicator(connectentry_multiplicator) # ledger time self.ledger_time_def_quantity = ( '1' if ledger_time_def_quantity is None else ledger_time_def_quantity ) # try to load default automatically if data_path is not None: self.load_settings_from_file(data_path) def set_offer_round_price(self, value): """Set offer_round_price.""" self._offer_round_price = bool(value) def get_offer_round_price(self): """Get offer_round_price.""" return self._offer_round_price def set_offer_templates(self, value): """Set offer_templates.""" if type(value) is dict: self._offer_templates = value elif type(value) is list: self._offer_templates = {} for x in value: self.add_offer_template(x[0], x[1]) def get_offer_templates_as_list(self): """Get offer_templates as list with tuples of key+value.""" return [(key, self._offer_templates[key]) for key in self._offer_templates] def get_offer_templates(self): """Get offer_templates as dict.""" return self._offer_templates def add_offer_template(self, key, value): """Add to offer_templates.""" self._offer_templates[key] = value def del_offer_template(self, key): """Try to delete offer_templates entry.""" if key in self._offer_templates: del self._offer_templates[key] def set_invoice_round_price(self, value): """Set invoice_round_price.""" self._invoice_round_price = bool(value) def get_invoice_round_price(self): """Get invoice_round_price.""" return self._invoice_round_price def set_invoice_templates(self, value): """Set invoice_templates.""" if type(value) is dict: self._invoice_templates = value elif type(value) is list: self._invoice_templates = {} for x in value: self.add_invoice_template(x[0], x[1]) def get_invoice_templates_as_list(self): """Get invoice_templates as list with tuples of key+value.""" return [(key, self._invoice_templates[key]) for key in self._invoice_templates] def get_invoice_templates(self): """Get invoice_templates as dict.""" return self._invoice_templates def add_invoice_template(self, key, value): """Add to invoice_templates.""" self._invoice_templates[key] = value def del_invoice_template(self, key): """Try to delete invoice_templates entry.""" if key in self._invoice_templates: del self._invoice_templates[key] def set_invoice_due_days(self, value): """Set invoice_due_days.""" try: self._invoice_due_days = int(value) except Exception: pass def get_invoice_due_days(self): """Get invoice_due_days.""" return self._invoice_due_days def set_project_hours_per_day(self, value): """Set project_hours_per_day.""" try: self._project_hours_per_day = int(value) except Exception: pass def get_project_hours_per_day(self): """Get project_hours_per_day.""" return self._project_hours_per_day def set_project_work_days(self, value): """Set project_work_days.""" if type(value) is list: self._project_work_days = value def get_project_work_days(self): """Get project_work_days.""" return self._project_work_days def set_project_minimum_days(self, value): """Set project_minimum_days.""" try: self._project_minimum_days = int(value) except Exception: pass def get_project_minimum_days(self): """Get project_minimum_days.""" return self._project_minimum_days def set_project_wage(self, value): """Set project_wage.""" try: self._project_wage = Decimal(str(value)) except Exception: pass def get_project_wage(self): """Get project_wage.""" return self._project_wage def set_baseentry_quantity(self, value): """Set baseentry_quantity.""" self._baseentry_quantity.set(value) def get_baseentry_quantity(self): """Get baseentry_quantity.""" return self._baseentry_quantity def set_baseentry_quantity_b(self, value): """Set baseentry_quantity_b.""" self._baseentry_quantity_b.set(value) def get_baseentry_quantity_b(self): """Get baseentry_quantity_b.""" return self._baseentry_quantity_b def set_baseentry_time(self, value): """Set baseentry_time.""" self._baseentry_time.set(value) def get_baseentry_time(self): """Get baseentry_time.""" self._baseentry_time.type('time') return self._baseentry_time def set_baseentry_price(self, value): """Set baseentry_price.""" try: self._baseentry_price = Decimal(str(value)) except Exception: pass def get_baseentry_price(self): """Get baseentry_price.""" return self._baseentry_price def set_multiplyentry_quantity(self, value): """Set multiplyentry_quantity.""" self._multiplyentry_quantity.set(value) def get_multiplyentry_quantity(self): """Get multiplyentry_quantity.""" return self._multiplyentry_quantity def set_multiplyentry_quantity_b(self, value): """Set multiplyentry_quantity_b.""" self._multiplyentry_quantity_b.set(value) def get_multiplyentry_quantity_b(self): """Get multiplyentry_quantity_b.""" return self._multiplyentry_quantity_b def set_multiplyentry_hour_rate(self, value): """Set multiplyentry_hour_rate.""" self._multiplyentry_hour_rate.set(value) def get_multiplyentry_hour_rate(self): """Get multiplyentry_hour_rate.""" self._multiplyentry_hour_rate.type('time') return self._multiplyentry_hour_rate def set_connectentry_quantity(self, value): """Set connectentry_quantity.""" self._connectentry_quantity.set(value) def get_connectentry_quantity(self): """Get connectentry_quantity.""" return self._connectentry_quantity def set_connectentry_quantity_b(self, value): """Set connectentry_quantity_b.""" self._connectentry_quantity_b.set(value) def get_connectentry_quantity_b(self): """Get connectentry_quantity_b.""" return self._connectentry_quantity_b def set_connectentry_is_time(self, value): """Set connectentry_is_time.""" self._connectentry_is_time = bool(value) def get_connectentry_is_time(self): """Get connectentry_is_time.""" return self._connectentry_is_time def set_connectentry_multiplicator(self, value): """Set connectentry_multiplicator.""" try: self._connectentry_multiplicator = Decimal(str(value)) except Exception: pass def get_connectentry_multiplicator(self): """Get connectentry_multiplicator.""" return self._connectentry_multiplicator def to_json(self, indent=2): """Convert settings data to json format.""" out = {} # fetch all setting variables out['language'] = self.language out['offer_title'] = self.offer_title out['offer_comment'] = self.offer_comment out['offer_comment_b'] = self.offer_comment_b out['offer_filename'] = self.offer_filename out['offer_round_price'] = self._offer_round_price out['offer_templates'] = self._offer_templates out['invoice_title'] = self.invoice_title out['invoice_id'] = self.invoice_id out['invoice_comment'] = self.invoice_comment out['invoice_comment_b'] = self.invoice_comment_b out['invoice_filename'] = self.invoice_filename out['invoice_round_price'] = self._invoice_round_price out['invoice_templates'] = self._invoice_templates out['invoice_due_days'] = self._invoice_due_days out['invoice_delivery'] = self.invoice_delivery out['invoice_ledger_comment'] = self.invoice_ledger_comment out['date_fmt'] = self.date_fmt out['commodity'] = self.commodity out['client_id'] = self.client_id out['client_company'] = self.client_company out['client_company_b'] = self.client_company_b out['client_attention'] = self.client_attention out['client_salutation'] = self.client_salutation out['client_name'] = self.client_name out['client_family_name'] = self.client_family_name out['client_street'] = self.client_street out['client_post_code'] = self.client_post_code out['client_city'] = self.client_city out['client_country'] = self.client_country out['client_tax_id'] = self.client_tax_id out['client_language'] = self.client_language out['project_title'] = self.project_title out['project_hours_per_day'] = self._project_hours_per_day out['project_work_days'] = self._project_work_days out['project_minimum_days'] = self._project_minimum_days out['project_wage'] = float(self._project_wage) out['baseentry_title'] = self.baseentry_title out['baseentry_comment'] = self.baseentry_comment out['baseentry_quantity'] = str(self._baseentry_quantity) out['baseentry_quantity_format'] = self.baseentry_quantity_format out['baseentry_quantity_b'] = str(self._baseentry_quantity_b) out['baseentry_quantity_b_format'] = self.baseentry_quantity_b_format out['baseentry_time'] = str(self._baseentry_time) out['baseentry_price'] = float(self._baseentry_price) out['multiplyentry_title'] = self.multiplyentry_title out['multiplyentry_comment'] = self.multiplyentry_comment out['multiplyentry_quantity'] = str(self._multiplyentry_quantity) out['multiplyentry_quantity_format'] = self.multiplyentry_quantity_format out['multiplyentry_quantity_b'] = str(self._multiplyentry_quantity_b) out['multiplyentry_quantity_b_format'] = self.multiplyentry_quantity_b_format out['multiplyentry_hour_rate'] = str(self._multiplyentry_hour_rate) out['connectentry_title'] = self.connectentry_title out['connectentry_comment'] = self.connectentry_comment out['connectentry_quantity'] = str(self._connectentry_quantity) out['connectentry_quantity_format'] = self.connectentry_quantity_format out['connectentry_quantity_b'] = str(self._connectentry_quantity_b) out['connectentry_quantity_b_format'] = self.connectentry_quantity_b_format out['connectentry_is_time'] = self._connectentry_is_time out['connectentry_multiplicator'] = float(self._connectentry_multiplicator) out['ledger_time_def_quantity'] = self.ledger_time_def_quantity # return the json return json.dumps(out, indent=indent, sort_keys=True) def feed_json(self, js=None): """Feed settings variables from json string.""" if js is None: return # get js as dict try: js = json.loads(js) except Exception: # do not load it return # feed settings variables if 'language' in js.keys(): self.language = js['language'] if 'offer_title' in js.keys(): self.offer_title = js['offer_title'] if 'offer_comment' in js.keys(): self.offer_comment = js['offer_comment'] if 'offer_comment_b' in js.keys(): self.offer_comment_b = js['offer_comment_b'] if 'offer_filename' in js.keys(): self.offer_filename = js['offer_filename'] if 'offer_round_price' in js.keys(): self.set_offer_round_price(js['offer_round_price']) if 'offer_templates' in js.keys(): self._offer_templates = js['offer_templates'] if 'invoice_title' in js.keys(): self.invoice_title = js['invoice_title'] if 'invoice_id' in js.keys(): self.invoice_id = js['invoice_id'] if 'invoice_comment' in js.keys(): self.invoice_comment = js['invoice_comment'] if 'invoice_comment_b' in js.keys(): self.invoice_comment_b = js['invoice_comment_b'] if 'invoice_filename' in js.keys(): self.invoice_filename = js['invoice_filename'] if 'invoice_round_price' in js.keys(): self.set_invoice_round_price(js['invoice_round_price']) if 'invoice_templates' in js.keys(): self._invoice_templates = js['invoice_templates'] if 'invoice_due_days' in js.keys(): self.set_invoice_due_days(js['invoice_due_days']) if 'invoice_delivery' in js.keys(): self.invoice_delivery = js['invoice_delivery'] if 'invoice_ledger_comment' in js.keys(): self.invoice_ledger_comment = js['invoice_ledger_comment'] if 'date_fmt' in js.keys(): self.date_fmt = js['date_fmt'] if 'commodity' in js.keys(): self.commodity = js['commodity'] if 'client_id' in js.keys(): self.client_id = js['client_id'] if 'client_company' in js.keys(): self.client_company = js['client_company'] if 'client_company_b' in js.keys(): self.client_company_b = js['client_company_b'] if 'client_attention' in js.keys(): self.client_attention = js['client_attention'] if 'client_salutation' in js.keys(): self.client_salutation = js['client_salutation'] if 'client_name' in js.keys(): self.client_name = js['client_name'] if 'client_family_name' in js.keys(): self.client_family_name = js['client_family_name'] if 'client_street' in js.keys(): self.client_street = js['client_street'] if 'client_post_code' in js.keys(): self.client_post_code = js['client_post_code'] if 'client_city' in js.keys(): self.client_city = js['client_city'] if 'client_country' in js.keys(): self.client_country = js['client_country'] if 'client_tax_id' in js.keys(): self.client_tax_id = js['client_tax_id'] if 'client_language' in js.keys(): self.client_language = js['client_language'] if 'project_title' in js.keys(): self.project_title = js['project_title'] if 'project_hours_per_day' in js.keys(): self.set_project_hours_per_day(js['project_hours_per_day']) if 'project_work_days' in js.keys(): self.set_project_work_days(js['project_work_days']) if 'project_minimum_days' in js.keys(): self.set_project_minimum_days(js['project_minimum_days']) if 'project_wage' in js.keys(): self.set_project_wage(js['project_wage']) if 'baseentry_title' in js.keys(): self.baseentry_title = js['baseentry_title'] if 'baseentry_comment' in js.keys(): self.baseentry_comment = js['baseentry_comment'] if 'baseentry_quantity' in js.keys(): self.set_baseentry_quantity(js['baseentry_quantity']) if 'baseentry_quantity_format' in js.keys(): self.baseentry_quantity_format = js['baseentry_quantity_format'] if 'baseentry_quantity_b' in js.keys(): self.set_baseentry_quantity_b(js['baseentry_quantity_b']) if 'baseentry_quantity_b_format' in js.keys(): self.baseentry_quantity_b_format = js['baseentry_quantity_b_format'] if 'baseentry_time' in js.keys(): self.set_baseentry_time(js['baseentry_time']) if 'baseentry_price' in js.keys(): self.set_baseentry_price(js['baseentry_price']) if 'multiplyentry_title' in js.keys(): self.multiplyentry_title = js['multiplyentry_title'] if 'multiplyentry_comment' in js.keys(): self.multiplyentry_comment = js['multiplyentry_comment'] if 'multiplyentry_quantity' in js.keys(): self.set_multiplyentry_quantity(js['multiplyentry_quantity']) if 'multiplyentry_quantity_format' in js.keys(): self.multiplyentry_quantity_format = js['multiplyentry_quantity_format'] if 'multiplyentry_quantity_b' in js.keys(): self.set_multiplyentry_quantity_b(js['multiplyentry_quantity_b']) if 'multiplyentry_quantity_b_format' in js.keys(): self.multiplyentry_quantity_b_format = js['multiplyentry_quantity_b_format'] if 'multiplyentry_hour_rate' in js.keys(): self.set_multiplyentry_hour_rate(js['multiplyentry_hour_rate']) if 'connectentry_title' in js.keys(): self.connectentry_title = js['connectentry_title'] if 'connectentry_comment' in js.keys(): self.connectentry_comment = js['connectentry_comment'] if 'connectentry_quantity' in js.keys(): self.set_connectentry_quantity(js['connectentry_quantity']) if 'connectentry_quantity_format' in js.keys(): self.connectentry_quantity_format = js['connectentry_quantity_format'] if 'connectentry_quantity_b' in js.keys(): self.set_connectentry_quantity_b(js['connectentry_quantity_b']) if 'connectentry_quantity_b_format' in js.keys(): self.connectentry_quantity_b_format = js['connectentry_quantity_b_format'] if 'connectentry_is_time' in js.keys(): self.set_connectentry_is_time(js['connectentry_is_time']) if 'connectentry_multiplicator' in js.keys(): self.set_connectentry_multiplicator(js['connectentry_multiplicator']) if 'ledger_time_def_quantity' in js.keys(): self.ledger_time_def_quantity = js['ledger_time_def_quantity'] def gen_abs_path_to_default_file(self, data_path, lang=None): """Generate the absolut path to the settings file.""" lang_set = type(lang) is str if not lang_set: return data_path + '/defaults_' + self.language + '.settings' else: return data_path + '/defaults_' + lang + '.settings' def delete_default_file(self, data_path, lang=None): """Delete the default file in data_path.""" if os.path.isfile(self.gen_abs_path_to_default_file(data_path, lang)): os.remove(self.gen_abs_path_to_default_file(data_path, lang)) def save_defaults_to_file(self, data_path): """Save the default to file in data_path.""" f = open(self.gen_abs_path_to_default_file(data_path), 'w') f.write(self.to_json()) f.close() def load_settings_from_file(self, data_path): """Load the settings from file in data_path.""" # check if the file exists if os.path.isfile(self.gen_abs_path_to_default_file(data_path)): # load content from file f = open(self.gen_abs_path_to_default_file(data_path), 'r') loaded = f.read().strip() f.close() # and feed own variables with it self.feed_json(loaded) def copy(self): """Return copy of own object.""" return Default( language=self.language, offer_title=self.offer_title, offer_comment=self.offer_comment, offer_comment_b=self.offer_comment_b, offer_filename=self.offer_filename, offer_round_price=self._offer_round_price, offer_templates=self._offer_templates, invoice_title=self.invoice_title, invoice_id=self.invoice_id, invoice_comment=self.invoice_comment, invoice_comment_b=self.invoice_comment_b, invoice_filename=self.invoice_filename, invoice_round_price=self._invoice_round_price, invoice_templates=self._invoice_templates, invoice_due_days=self._invoice_due_days, invoice_delivery=self.invoice_delivery, invoice_ledger_comment=self.invoice_ledger_comment, date_fmt=self.date_fmt, commodity=self.commodity, client_id=self.client_id, client_company=self.client_company, client_company_b=self.client_company_b, client_attention=self.client_attention, client_salutation=self.client_salutation, client_name=self.client_name, client_family_name=self.client_family_name, client_street=self.client_street, client_post_code=self.client_post_code, client_city=self.client_city, client_country=self.client_country, client_tax_id=self.client_tax_id, client_language=self.client_language, project_title=self.project_title, project_hours_per_day=self._project_hours_per_day, project_work_days=self._project_work_days, project_minimum_days=self._project_minimum_days, project_wage=self._project_wage, baseentry_title=self.baseentry_title, baseentry_comment=self.baseentry_comment, baseentry_quantity=self._baseentry_quantity, baseentry_quantity_format=self.baseentry_quantity_format, baseentry_quantity_b=self._baseentry_quantity_b, baseentry_quantity_b_format=self.baseentry_quantity_b_format, baseentry_time=self._baseentry_time, baseentry_price=self._baseentry_price, multiplyentry_title=self.multiplyentry_title, multiplyentry_comment=self.multiplyentry_comment, multiplyentry_quantity=self._multiplyentry_quantity, multiplyentry_quantity_format=self.multiplyentry_quantity_format, multiplyentry_quantity_b=self._multiplyentry_quantity_b, multiplyentry_quantity_b_format=self.multiplyentry_quantity_b_format, multiplyentry_hour_rate=self._multiplyentry_hour_rate, connectentry_title=self.connectentry_title, connectentry_comment=self.connectentry_comment, connectentry_quantity=self._connectentry_quantity, connectentry_quantity_format=self.connectentry_quantity_format, connectentry_quantity_b=self._connectentry_quantity_b, connectentry_quantity_b_format=self.connectentry_quantity_b_format, connectentry_is_time=self._connectentry_is_time, connectentry_multiplicator=self._connectentry_multiplicator, ledger_time_def_quantity=self.ledger_time_def_quantity )
def __init__( self, data_path=None, language=None, offer_title=None, offer_comment=None, offer_comment_b=None, offer_filename=None, offer_round_price=None, offer_templates=None, invoice_title=None, invoice_id=None, invoice_comment=None, invoice_comment_b=None, invoice_filename=None, invoice_round_price=None, invoice_templates=None, invoice_due_days=None, invoice_delivery=None, invoice_ledger_comment=None, date_fmt=None, commodity=None, client_id=None, client_company=None, client_company_b=None, client_attention=None, client_salutation=None, client_name=None, client_family_name=None, client_street=None, client_post_code=None, client_city=None, client_country=None, client_tax_id=None, client_language=None, project_title=None, project_hours_per_day=None, project_work_days=None, project_minimum_days=None, project_wage=None, baseentry_title=None, baseentry_comment=None, baseentry_quantity=None, baseentry_quantity_format=None, baseentry_quantity_b=None, baseentry_quantity_b_format=None, baseentry_time=None, baseentry_price=None, multiplyentry_title=None, multiplyentry_comment=None, multiplyentry_quantity=None, multiplyentry_quantity_format=None, multiplyentry_quantity_b=None, multiplyentry_quantity_b_format=None, multiplyentry_hour_rate=None, connectentry_title=None, connectentry_comment=None, connectentry_quantity=None, connectentry_quantity_format=None, connectentry_quantity_b=None, connectentry_quantity_b_format=None, connectentry_is_time=None, connectentry_multiplicator=None, ledger_time_def_quantity=None ): """Initialize the class and hard code defaults, if no file is given.""" self.language = 'NEW' if language is None else language self.offer_title = '' if offer_title is None else offer_title self.offer_comment = '' if offer_comment is None else offer_comment self.offer_comment_b = '' if offer_comment_b is None else offer_comment_b self.offer_filename = '' if offer_filename is None else offer_filename self.set_offer_round_price( False if offer_round_price is None else offer_round_price ) self._offer_templates = {} # set default self.set_offer_templates(offer_templates) # try to set arguments value self.invoice_title = '' if invoice_title is None else invoice_title self.invoice_id = '' if invoice_id is None else invoice_id self.invoice_comment = '' if invoice_comment is None else invoice_comment self.invoice_comment_b = '' if invoice_comment_b is None else invoice_comment_b self.invoice_filename = '' if invoice_filename is None else invoice_filename self.set_invoice_round_price( False if invoice_round_price is None else invoice_round_price ) self._invoice_templates = {} # set default self.set_invoice_templates(invoice_templates) # try to set arguments value self._invoice_due_days = 14 # set default self.set_invoice_due_days(invoice_due_days) # try to set arguments value self.invoice_delivery = '' if invoice_delivery is None else invoice_delivery self.invoice_ledger_comment = ( '' if invoice_ledger_comment is None else invoice_ledger_comment ) self.date_fmt = '' if date_fmt is None else date_fmt self.commodity = '' if commodity is None else commodity # client default values self.client_id = '{CLIENT_COUNT}' if client_id is None else client_id self.client_company = '' if client_company is None else client_company self.client_company_b = '' if client_company_b is None else client_company_b self.client_attention = 'Attn.' if client_attention is None else client_attention self.client_salutation = '' if client_salutation is None else client_salutation self.client_name = '' if client_name is None else client_name self.client_family_name = '' if client_family_name is None else client_family_name self.client_street = '' if client_street is None else client_street self.client_post_code = '' if client_post_code is None else client_post_code self.client_city = '' if client_city is None else client_city self.client_country = '' if client_country is None else client_country self.client_tax_id = '' if client_tax_id is None else client_tax_id self.client_language = 'en' if client_language is None else client_language # project default values self.project_title = '{PROJECT_COUNT}' if project_title is None else project_title self._project_hours_per_day = 0 self.set_project_hours_per_day(project_hours_per_day) self._project_work_days = [0, 1, 2, 3, 4] self.set_project_work_days(project_work_days) self._project_minimum_days = 2 self.set_project_minimum_days(project_minimum_days) self._project_wage = Decimal(0) self.set_project_wage(project_wage) # baseentry default values self.baseentry_title = '' if baseentry_title is None else baseentry_title self.baseentry_comment = '' if baseentry_comment is None else baseentry_comment self._baseentry_quantity = QuantityTime(baseentry_quantity) self.baseentry_quantity_format = ( '' if baseentry_quantity_format is None else baseentry_quantity_format ) if baseentry_quantity_b is None: self._baseentry_quantity_b = QuantityTime(1) else: self._baseentry_quantity_b = QuantityTime(baseentry_quantity_b) self.baseentry_quantity_b_format = ( '' if baseentry_quantity_b_format is None else baseentry_quantity_b_format ) self._baseentry_time = QuantityTime(baseentry_time) self._baseentry_price = Decimal(0) self.set_baseentry_price(baseentry_price) # multiplyentry default values self.multiplyentry_title = ( '' if multiplyentry_title is None else multiplyentry_title ) self.multiplyentry_comment = ( '' if multiplyentry_comment is None else multiplyentry_comment ) self._multiplyentry_quantity = QuantityTime(multiplyentry_quantity) self.multiplyentry_quantity_format = ( '' if multiplyentry_quantity_format is None else multiplyentry_quantity_format ) if multiplyentry_quantity_b is None: self._multiplyentry_quantity_b = QuantityTime(1) else: self._multiplyentry_quantity_b = QuantityTime(multiplyentry_quantity_b) self.multiplyentry_quantity_b_format = ( '' if multiplyentry_quantity_b_format is None else multiplyentry_quantity_b_format ) self._multiplyentry_hour_rate = QuantityTime(multiplyentry_hour_rate) # connectentry default values self.connectentry_title = ( '' if connectentry_title is None else connectentry_title ) self.connectentry_comment = ( '' if connectentry_comment is None else connectentry_comment ) self._connectentry_quantity = QuantityTime(connectentry_quantity) self.connectentry_quantity_format = ( '' if connectentry_quantity_format is None else connectentry_quantity_format ) if connectentry_quantity_b is None: self._connectentry_quantity_b = QuantityTime(1) else: self._connectentry_quantity_b = QuantityTime(connectentry_quantity_b) self.connectentry_quantity_b_format = ( '' if connectentry_quantity_b_format is None else connectentry_quantity_b_format ) self.set_connectentry_is_time( True if connectentry_is_time is None else connectentry_is_time ) self._connectentry_multiplicator = Decimal(0) self.set_connectentry_multiplicator(connectentry_multiplicator) # ledger time self.ledger_time_def_quantity = ( '1' if ledger_time_def_quantity is None else ledger_time_def_quantity ) # try to load default automatically if data_path is not None: self.load_settings_from_file(data_path)
class MultiplyEntry(BaseEntry): """ A multiplying entry. This entry type is similar to the BaseEntry, except that it calculates the time according to a given hour_rate value. The class has a new value "hour_rate" which will be multiplicated by the quantity and thus calculates the time. """ def __init__( self, id=None, title=None, comment=None, quantity=None, quantity_format=None, quantity_b=None, quantity_b_format=None, tax=None, hour_rate=None, wage_add=None, wage_add_explain=None ): """Initialize the class.""" # values of the BaseEntry class super(MultiplyEntry, self).__init__( id=id, title=title, comment=comment, quantity=quantity, quantity_format=quantity_format, quantity_b=quantity_b, quantity_b_format=quantity_b_format, tax=tax ) # new values for this class self._hour_rate = QuantityTime(hour_rate) self._wage_add = QuantityTime(wage_add) self.wage_add_explain = '' if wage_add_explain is None else str(wage_add_explain) def set_time(self, value): """Disable the function.""" pass def get_time(self, *args, **kwargs): """Get own quantity * own hour as time.""" out = self._quantity * self._quantity_b * self._hour_rate out.type('time') return out def set_price(self, value): """Disable function.""" pass def get_price(self, wage=Decimal('0.00'), round_price=False, *args, **kwargs): """Get own time * wage as price.""" if round_price: rounder = 0 else: rounder = 2 return round( self.get_time(*args, **kwargs).get() * (wage + self._wage_add.get()), rounder ) def set_hour_rate(self, value): """Set hour_rate.""" self._hour_rate.set(value) def get_hour_rate(self): """Get hour_rate.""" return self._hour_rate def set_wage_add(self, value): """Set wage_add.""" self._wage_add.set(value) def get_wage_add(self): """Get wage_add.""" return self._wage_add def to_dict(self): """Convert object to dict.""" out = {} # fetch all important data for this entry type out['type'] = self.__class__.__name__ out['id'] = self.get_id() out['title'] = self.title out['comment'] = self.comment out['quantity'] = str(self._quantity) out['quantity_format'] = self.quantity_format out['quantity_b'] = str(self._quantity_b) out['quantity_b_format'] = self.quantity_b_format out['tax'] = float(self._tax) out['hour_rate'] = str(self._hour_rate) out['wage_add'] = str(self._wage_add) out['wage_add_explain'] = self.wage_add_explain return out def to_json(self, indent=2, ensure_ascii=False): """Convert all data to json format.""" return json.dumps( self.to_dict(), indent=indent, ensure_ascii=ensure_ascii, sort_keys=True ) @classmethod def from_json(cls, js=None, keep_id=True): """Convert all data from json format.""" if js is None: return cls() # get js as dict if type(js) is not dict: try: js = json.loads(js) except Exception: # return default object return cls() # create new entry object from json # get ID if it's no preset_loading if not keep_id: id = None elif keep_id is True: if 'id' in js.keys(): id = js['id'] else: id = None else: id = str(keep_id) # get other values if 'title' in js.keys(): title = js['title'] else: title = None if 'comment' in js.keys(): comment = js['comment'] else: comment = None if 'quantity' in js.keys(): quantity = js['quantity'] else: quantity = None if 'quantity_format' in js.keys(): quantity_format = js['quantity_format'] else: quantity_format = None if 'quantity_b' in js.keys(): quantity_b = js['quantity_b'] else: quantity_b = None if 'quantity_b_format' in js.keys(): quantity_b_format = js['quantity_b_format'] else: quantity_b_format = None if 'tax' in js.keys(): tax = js['tax'] else: tax = None if 'hour_rate' in js.keys(): hour_rate = js['hour_rate'] else: hour_rate = None if 'wage_add' in js.keys(): wage_add = js['wage_add'] else: wage_add = None if 'wage_add_explain' in js.keys(): wage_add_explain = js['wage_add_explain'] else: wage_add_explain = None return cls( id=id, title=title, comment=comment, quantity=quantity, quantity_format=quantity_format, quantity_b=quantity_b, quantity_b_format=quantity_b_format, tax=tax, hour_rate=hour_rate, wage_add=wage_add, wage_add_explain=wage_add_explain ) def copy(self, keep_id=True): """Return a copy of this object.""" return MultiplyEntry().from_json(js=self.to_json(), keep_id=keep_id)
def get_time_zero(self, *args, **kwargs): """Get time as '-' if time is 0, else str of time.""" if self.get_time(*args, **kwargs) == QuantityTime(0): return '-' else: return str(self.get_time(*args, **kwargs))
class BaseEntry(object): """A very simple entry with basic options and FIXED values.""" def __init__( self, id=None, title=None, comment=None, quantity=None, quantity_format=None, quantity_b=None, quantity_b_format=None, tax=None, time=None, price=None, connected=None ): """Init the class.""" # gen ID if not set, otherwise get it from argument self._id = str(uuid.uuid1()) if id is None else str(id) # get other variables from arguments self.title = '' if title is None else str(title) self.comment = '' if comment is None else str(comment) self._quantity = QuantityTime(quantity) self.quantity_format = '' if quantity_format is None else str(quantity_format) if quantity_b is None: self._quantity_b = QuantityTime(1) else: self._quantity_b = QuantityTime(quantity_b) self.quantity_b_format = ( '' if quantity_b_format is None else str(quantity_b_format) ) self._tax = Decimal(0) # set default self.set_tax(tax) # try to set arguments value self._time = QuantityTime(time) self._price = Decimal(0) # set default self.set_price(price) # try to set arguments value # get the connected list (for ConnectEntry only) if type(connected) is set: self._connected = connected else: self._connected = set() def get_id(self): """Get id.""" return self._id def set_quantity(self, value): """Set quantity.""" self._quantity.set(value) def get_quantity(self): """Get quantity.""" return self._quantity def get_quantity_str(self, fmt=None): """Get self._quantity as string.""" return self.get_quantity_universal_str( fmt=fmt, quantity=self._quantity, quantity_fmt=self.quantity_format ) def set_quantity_b(self, value): """Set quantity_b.""" self._quantity_b.set(value) def get_quantity_b(self): """Get quantity_b.""" return self._quantity_b def get_quantity_b_str(self, fmt=None): """Get self._quantity_b as string.""" return self.get_quantity_universal_str( fmt=fmt, quantity=self._quantity_b, quantity_fmt=self.quantity_b_format ) def get_quantity_universal_str(self, fmt=None, quantity=None, quantity_fmt=None): """ Get quantity as string with possible formatting. In case the offer is for music production for example, it would be good if the quantity of the offer posting would not be listed as a decimal rather than a readable time format. So instead of "1.5 min" -> "1:30 min" or similar. With the following format options you can achieve this - also with leading zeros: {s}: standard automatic quantity {d}: quantity in decimal {F}: quantity converted to time, show full {R}: quantity converted to time, show remaining Means that 1.5 with fmt == "{F}:{R}" would output 0:01, while fmt == "{F}:{R}" would output 1:30. 61.75 with """ if type(quantity) is not QuantityTime: return str(fmt) # get self.quantity_format if no argument is given if fmt is None: fmt = quantity_fmt # is this also is empty, get '{s}' as default output # (so that it shows the default at least) if fmt == '': fmt = '{s}' # init formating output variable format_me = {} # get format_me format_me['s'] = quantity format_me['d'] = quantity.get() format_me['F'] = quantity.full() format_me['R'] = quantity.remain() # {F} exists if '{F}' in fmt: # correct leading zeros fmt = fmt.replace('{R}', '{R:02}') # output the stuff try: return fmt.format(**format_me) except Exception: # if any wrong {...} are given return fmt def set_tax(self, value): """Set tax.""" # check if value is decimal try: is_percent = True if float(value) > 1.0 else False except Exception: is_percent = False # try to set a new tax try: # only works, if input is integer, float or string if is_percent: self._tax = Decimal(str(value)) / 100 else: self._tax = Decimal(str(value)) except Exception: # otherwise don't do anything pass def get_tax(self, *args, **kwargs): """Get tax.""" return self._tax def get_tax_percent(self, *args, **kwargs): """Get tax.""" return self._tax * 100 def set_time(self, value): """Set time.""" self._time.set(value) def get_time(self, *args, **kwargs): """Get time.""" self._time.type('time') return self._time * self._quantity * self._quantity_b def get_time_raw(self, *args, **kwargs): """Get raw time value.""" self._time.type('time') return self._time def get_time_zero(self, *args, **kwargs): """Get time as '-' if time is 0, else str of time.""" if self.get_time(*args, **kwargs) == QuantityTime(0): return '-' else: return str(self.get_time(*args, **kwargs)) def set_price(self, value): """Set price.""" # try to set a new price try: # only works, if input is integer, float or string self._price = round(Decimal(str(value)), 2) except Exception: # otherwise don't do anything pass def get_price(self, round_price=False, *args, **kwargs): """Get price.""" if round_price: rounder = 0 else: rounder = 2 return round(self._price * self._quantity.get() * self._quantity_b.get(), rounder) def get_unit_price(self, round_price=False, *args, **kwargs): """Get price / quantity.""" quantities = self._quantity.get() # decomment next line for getting unit price divided by quantity b as well! # quantities = self._quantity.get() * self._quantity_b.get() # divide with quantity, if its > 0 if quantities > 0: return round( self.get_price( round_price=round_price, *args, **kwargs ) / quantities, 2 ) # fallback output: simple get_price else: return round( self.get_price( round_price=round_price, *args, **kwargs ), 2 ) def get_price_raw(self): """Get raw price value.""" return self._price def get_price_tax(self, *args, **kwargs): """Get tax of the price.""" return round( self._tax * self.get_price( *args, **kwargs ), 2 ) def get_unit_price_tax(self, *args, **kwargs): """Get price_tax / quantity.""" quantities = self._quantity.get() # decomment next line for getting unit price divided by quantity b as well! # quantities = self._quantity.get() * self._quantity_b.get() # divide with quantity, if its > 0 if quantities > 0: return round( self.get_price_tax( *args, **kwargs ) / quantities, 2 ) # fallback output: simple get_price_tax else: return round( self.get_price_tax( *args, **kwargs ), 2 ) def get_connected(self): """Get connected set.""" return self._connected def to_dict(self): """Convert all data to a dict.""" out = {} # fetch all important data for this entry type out['type'] = self.__class__.__name__ out['id'] = self.get_id() out['title'] = self.title out['comment'] = self.comment out['quantity'] = str(self._quantity) out['quantity_format'] = self.quantity_format out['quantity_b'] = str(self._quantity_b) out['quantity_b_format'] = self.quantity_b_format out['tax'] = float(self._tax) out['time'] = str(self._time) out['price'] = float(self._price) return out def to_json(self, indent=2, ensure_ascii=False): """Convert all data to json format.""" return json.dumps( self.to_dict(), indent=indent, ensure_ascii=ensure_ascii, sort_keys=True ) @classmethod def from_json(cls, js=None, keep_id=True): """Convert all data from json format.""" if js is None: return cls() # get js as dict if type(js) is not dict: try: js = json.loads(js) except Exception: # return default object return cls() # create new entry object from json # get ID if it's no preset_loading if not keep_id: id = None elif keep_id is True: if 'id' in js.keys(): id = js['id'] else: id = None else: id = str(keep_id) # get other values if 'title' in js.keys(): title = js['title'] else: title = None if 'comment' in js.keys(): comment = js['comment'] else: comment = None if 'quantity' in js.keys(): quantity = js['quantity'] else: quantity = None if 'quantity_format' in js.keys(): quantity_format = js['quantity_format'] else: quantity_format = None if 'quantity_b' in js.keys(): quantity_b = js['quantity_b'] else: quantity_b = None if 'quantity_b_format' in js.keys(): quantity_b_format = js['quantity_b_format'] else: quantity_b_format = None if 'tax' in js.keys(): tax = js['tax'] else: tax = None if 'time' in js.keys(): time = js['time'] else: time = None if 'price' in js.keys(): price = js['price'] else: price = None return cls( id=id, title=title, comment=comment, quantity=quantity, quantity_format=quantity_format, quantity_b=quantity_b, quantity_b_format=quantity_b_format, tax=tax, time=time, price=price ) def copy(self, keep_id=True): """Return a copy of this object.""" return BaseEntry().from_json(js=self.to_json(), keep_id=keep_id) def is_project(self, project=None): """ Check if given argument is project object. This is some kind of workaround, since I canot import the Project class into Offer module due to circular dependencies. Do I really still have a that bad programm manufacture? )= """ try: return project.i_am_project() except Exception: return False def return_changed_type( self, into='BaseEntry', entry_list=None, wage=None, project=None, round_price=None ): """Return the own entry object into other entry object.""" # return changed into MultiplyEntry if into == 'MultiplyEntry': new_entry = MultiplyEntry( id=self.get_id(), title=self.title, comment=self.comment, quantity=self.get_quantity(), quantity_format=self.quantity_format, quantity_b=self.get_quantity_b(), quantity_b_format=self.quantity_b_format, tax=self.get_tax() ) return new_entry # return changed into ConnectEntry elif into == 'ConnectEntry': new_entry = ConnectEntry( id=self.get_id(), title=self.title, comment=self.comment, quantity=self.get_quantity(), quantity_format=self.quantity_format, quantity_b=self.get_quantity_b(), quantity_b_format=self.quantity_b_format, tax=self.get_tax() ) return new_entry # return changed into BaseEntry (also as fallback if into argument is invalid) else: new_entry = BaseEntry( id=self.get_id(), title=self.title, comment=self.comment, quantity=self.get_quantity(), quantity_format=self.quantity_format, quantity_b=self.get_quantity_b(), quantity_b_format=self.quantity_b_format, tax=self.get_tax(), price=self.get_price( entry_list=entry_list, wage=wage, round_price=round_price ), time=self.get_time( entry_list=entry_list ) ) return new_entry
def test_integrety_entry(): """Test if BaseEntry, ConnectEntry and MultiplyEntry work as they should.""" a = BaseEntry(title='Title A', comment='Comment A', quantity=1.0, time=1.0, price=50.00) b = MultiplyEntry(title='Title B', comment='Comment B', quantity=2.0, hour_rate=0.5) c = ConnectEntry(title='Title C', comment='Comment C', quantity=2.5, is_time=False, multiplicator=0.5) d = ConnectEntry(title='Title D', comment='Comment D', quantity=3.0, is_time=True, multiplicator=0.75) # init entries in list entries = [] entries.append(a) entries.append(b) entries.append(c) entries.append(d) # connect first two entries two the first ConnectEntry entries[2].connect_entry(entry_list=entries, entry_id=entries[0].get_id()) entries[2].connect_entry(entry_list=entries, entry_id=entries[1].get_id()) # connect first ConnectEntry to the second ConnectEntry entries[3].connect_entry(entry_list=entries, entry_id=entries[2].get_id()) # connect second ConnectEntry to the first ConnectEntry # and it should not work anymore entries[2].connect_entry(entry_list=entries, entry_id=entries[3].get_id()) assert entries[3].get_id() not in entries[2].get_connected() # connect MultiplyEntry to the second ConnectEntry entries[3].connect_entry(entry_list=entries, entry_id=entries[1].get_id()) # set wage to work with wage = Decimal('50.00') # check values for BaseEntry assert entries[0].title == 'Title A' assert entries[0].comment == 'Comment A' assert entries[0].get_quantity() == Decimal('1.0') assert entries[0].get_time() == QuantityTime(1.0) assert entries[0].get_price() == Decimal('50.00') # check values for MultiplyEntry assert entries[1].title == 'Title B' assert entries[1].comment == 'Comment B' assert entries[1].get_quantity() == Decimal('2.0') assert entries[1].get_hour_rate() == QuantityTime(0.5) assert entries[1].get_time() == QuantityTime(1.0) assert entries[1].get_price(wage=wage) == Decimal('50.00') # check values for first ConnectEntry assert entries[2].title == 'Title C' assert entries[2].comment == 'Comment C' assert entries[2].get_quantity() == Decimal('2.5') assert entries[2].get_is_time() is False assert entries[2].get_time(entry_list=entries) == QuantityTime(0) assert entries[2].get_price(entry_list=entries, wage=wage) == Decimal('125.00') # check values for second ConnectEntry assert entries[3].title == 'Title D' assert entries[3].comment == 'Comment D' assert entries[3].get_quantity() == Decimal('3.0') assert entries[3].get_is_time() is True assert entries[3].get_time(entry_list=entries) == QuantityTime('2:15:00') assert entries[3].get_price(entry_list=entries, wage=wage) == Decimal('112.50')