def conv_last_usd_val_to_home_curr(asset_guid: str) -> int: """ Convert last known value to USD then project as TRY """ result = 0 assets = imp_asset.get_assets()["assets"] for asset in assets: if asset["guid"] != asset_guid: continue if "value_history" not in asset: break values = asset["value_history"] last_val = values[len(values) - 1] last_date = parse_json_date(last_val["date"]) historic_curr_conv = OldCurrencyConverter(last_date) today_curr_conv = CurrencyConverter() last_val_usd = \ historic_curr_conv.convert_to_foreign_currency( last_val["value"], foreign_currency=_FOREIGN_CURR) result = \ today_curr_conv.convert_to_local_currency( foreign_amount=last_val_usd, foreign_currency=_FOREIGN_CURR) break return int(result)
def get_plan_list() -> List: """ Plan values """ conv = CurrencyConverter() out = get_subject_list() fiscal = _get_latest_fiscal_file_content() for subject in out: subject["monthly_plan_amount"] = 0 subject["annual_plan_amount"] = 0 subject["currency"] = config.CONSTANTS["HOME_CURRENCY"] subject["currency_symbol"] = config.CONSTANTS["HOME_CURRENCY_SYMBOL"] if "plans" in fiscal: for plan in fiscal["plans"]: if subject["domain"] == plan["domain"] and subject[ "subject"] == plan["subject"]: json_amount = conv.convert_to_local_currency( plan["amount"], plan["currency"]) if plan["period"] == "month": monthly_amount = json_amount / plan["frequency"] annual_amount = json_amount * (12 / plan["frequency"]) elif plan["period"] == "year": monthly_amount = json_amount / (12 * plan["frequency"]) annual_amount = json_amount / plan["frequency"] else: raise Exception( f"Unknown budget period: {plan['period']}") subject["monthly_plan_amount"] = monthly_amount subject["annual_plan_amount"] = annual_amount break return out
def get_asset_type_resale_value_sum(only_liquid: bool = False, deduct_income_tax: bool = False, own_percentage_only: bool = False) -> List: """ Asset type resale value sum Used when calculating net worth """ result = [] assets = get_assets(deduct_income_tax=deduct_income_tax, own_percentage_only=own_percentage_only) currency_converter = CurrencyConverter() for asset in assets["assets"]: if only_liquid and not is_liquid(asset["type"]): continue asset_unit_value = currency_converter.convert_to_local_currency( asset["sales_value"], asset["currency"]) asset_value = asset_unit_value * asset["quantity"] found = False for res in result: if res["type"] == asset["type"]: res["sales_value"] = res["sales_value"] + asset_value found = True if not found: res = {"type": asset["type"], "sales_value": asset_value} result.append(res) return result
def get_current_account_balance_sum() -> float: """ Returns money in banks in home currency """ amount = 0 accounts = get_bank_accounts() currency_converter = CurrencyConverter() for account in accounts["bank_accounts"]: amount += currency_converter.convert_to_local_currency( account["balance"], account["currency"]) return amount
def __init__(self): self._tax_rates = [] self._default_tax_rate = 0 self._default_tax_rate_calculated = False self._tmp_tax_rate = 0 self._tmp_tax_rate_calculated = False self._forecast_tax_rate = 0 self._forecast_tax_rate_calculated = False self._converter = CurrencyConverter() self._read_tax_rates()
def open_amount(self) -> tuple: """ Open amount """ if self.cleared: return 0, self.currency open_amount, open_currency = self.amount currency_conv = CurrencyConverter() for coll in self.collections: coll_amount, coll_curr = coll.amount converted_coll_amount = currency_conv.convert_to_currency( coll_amount, coll_curr, open_currency) open_amount -= converted_coll_amount return open_amount, open_currency
def record_vat_payment(vat_guids: List, paid_amount: float, paid_curr: str): """ Records a new VAT payment """ paid_vats = [] all_vats = get_open_vat_payments() curr_conv = CurrencyConverter() vat_amount = 0 for pay in all_vats: if pay.guid in vat_guids: paid_vats.append(pay) for pay in paid_vats: pay.generate_very_long_term_recurrences() debt_amount, debt_curr = pay.open_amount debt_amount_conv = curr_conv.convert_to_currency( from_amount=debt_amount, from_currency=debt_curr, to_currency=paid_curr) vat_amount += debt_amount_conv sch = pay.scheme recs = sch.recurrences if len(recs) != 1: raise Exception("Unexpected VAT scheme") rec = recs[0] coll_dict = { "date": datetime.datetime.now().isoformat(), "description": "KDV ödemesi", "amount": paid_amount, "currency": paid_curr } coll = Collection(coll_dict) rec.add_collection(coll) rec.cleared = True sch.recurrences = recs pay.scheme = sch pay.cleared = True if vat_amount > paid_amount: investable_amount = vat_amount - paid_amount record_investment_payment(investable_amount, paid_curr, "VAT surplus") for pay in paid_vats: pay.save()
def record_investment_payment(investable_amount: float, paid_curr: str, description_prefix: str): """ Records a new investment payment into the most suitable account """ # Get investable amount investable_amount = CurrencyConverter().convert_to_local_currency( investable_amount, paid_curr) # Pay credit card debts if config.CONSTANTS["PAY_CREDIT_DEBT_BEFORE_INVESTMENT"]: credit_card_debts = get_credit_card_debts() for cc_debt in credit_card_debts.debts: if investable_amount < cc_debt.amount: payable_amount = investable_amount investable_amount = 0 else: payable_amount = cc_debt.amount investable_amount -= payable_amount create_credit_card_transaction(cc_debt.bank_name, description_prefix, cc_debt.card_name, payable_amount) if investable_amount <= 0: return if investable_amount <= 0: return # Invest investments = InvestmentAdviser().advise(investable_amount) for inv in investments: _create_investment_transaction(inv["bank"], description_prefix, inv["account"], inv["account"], inv["amount"])
def get_credit_card_debts() -> CreditCardDebtList: """ Returns all credit card debts """ output = CreditCardDebtList(config.CONSTANTS["HOME_CURRENCY"]) credit_cards = get_credit_cards() currency_converter = CurrencyConverter() for credit_card in credit_cards["credit_cards"]: debt = credit_card["credit_limit"] - credit_card["usable_limit"] if debt <= 0: continue local_debt = currency_converter.convert_to_local_currency( debt, credit_card["currency"]) cc_debt = CreditCardDebt(credit_card["bank_name"], credit_card["card_name"], local_debt) output.debts.append(cc_debt) return output
def get_reserved_balance() -> float: """ Returns the reserved bank account balance """ output = 0 home_curr = config.CONSTANTS["HOME_CURRENCY"] curr_conv = CurrencyConverter() for bank_account in get_bank_accounts()["bank_accounts"]: if not "reserved" in bank_account: continue for balance in bank_account["reserved"]: reserved_amt = balance["amount"] \ if bank_account["currency"] == home_curr \ else curr_conv.convert_to_local_currency( balance["amount"], bank_account["currency"]) output += reserved_amt return output
def open_amount(self) -> tuple: """ Payment open amount """ currency_conv = CurrencyConverter() scheme = self.scheme open_amount, open_currency = self.amount if scheme.repeats_forever: return open_amount, open_currency open_amount *= self.scheme.repeat for rec in self.scheme.recurrences: paid_amount, paid_currency = rec.paid_amount converted_paid_amount = currency_conv.convert_to_currency( paid_amount, paid_currency, open_currency) open_amount -= converted_paid_amount return open_amount, open_currency
def get_liquid_assets_in_both_currencies( deduct_income_tax: bool = False, own_percentage_only: bool = False) -> List: """ Asset balances in original and home currencies """ output = [] assets = get_assets(deduct_income_tax=deduct_income_tax, own_percentage_only=own_percentage_only) currency_converter = CurrencyConverter() for asset in assets["assets"]: if not is_liquid(asset["type"]): continue org_amount = asset["sales_value"] * asset["quantity"] local_amount = currency_converter.convert_to_local_currency( org_amount, asset["currency"]) name = asset["bank"] + " - " + asset["type"] found = False for out in output: if out["name"] == name and out["original_currency"] == asset[ "currency"]: found = True out["home_balance"] += local_amount out["original_balance"] += org_amount break if not found: output_dict = { "name": asset["bank"] + " - " + asset["type"], "home_balance": local_amount, "original_balance": org_amount, "original_currency": asset["currency"], "is_investment": True } output.append(output_dict) return output
def _read_bank_accounts(self): currency_conv = CurrencyConverter() currencies = bank_account.get_currencies() for currency in currencies: accounts = bank_account.get_accounts_with_currency(currency) currency_sum = 0 home_sum = 0 bank_sum = 0 home_perc = 0 bank_perc = 0 for account in accounts: account_balance = currency_conv.convert_to_local_currency( account["balance"], account["currency"]) currency_sum += account_balance if account["bank_name"] == config.CONSTANTS["HOME_COMPANY"]: home_sum += account_balance else: bank_sum += account_balance if currency_sum != 0: home_perc = int((home_sum / currency_sum) * 100) bank_perc = 100 - home_perc curr_dict = {"currency": currency, "currency_sum": currency_sum, "bank_sum": bank_sum, "home_sum": home_sum, "bank_perc": bank_perc, "home_perc": home_perc} self._out["Currencies"].append(curr_dict)
def get_account_balances_in_both_currencies() -> List: """ Account balances in original and home currencies """ output = [] accounts = get_bank_accounts() currency_converter = CurrencyConverter() for account in accounts["bank_accounts"]: amount_home = currency_converter.convert_to_local_currency( account["balance"], account["currency"]) reserved = 0 if "reserved" in account: for res_entry in account["reserved"]: reserved += res_entry["amount"] reserved_home = currency_converter.convert_to_local_currency( reserved, account["currency"]) usable = account["balance"] - reserved usable_home = amount_home - reserved_home output_dict = { "name": account["bank_name"] + " - " + account["account_name"], "home_balance": amount_home, "original_balance": account["balance"], "original_currency": account["currency"], "is_investment": account["is_investment"], "original_reserved": reserved, "home_reserved": reserved_home, "original_usable": usable, "home_usable": usable_home } output.append(output_dict) return output
class StatementEntry(): """ Bank statement entry """ date: datetime = None text: str = "" amount: float = 0 currency: str = "" def __post_init__(self): self._curr_conv = None @property def amount_in_home_currency(self) -> float: """ Amount in home currency """ if self._curr_conv is None: self._curr_conv = CurrencyConverter() return self._curr_conv.convert_to_local_currency( self.amount, self.currency)
class ReconciliationAPI(): """ Reconciliation API """ def __init__(self): self._out = {} self._company_dict = {} self._pay_stat_api = PaymentStatusAPI() self._curr = CurrencyConverter() def get_result(self, company_names: List[str]) -> dict: """ Returns payment status """ payment.generate_high_time_recurrences() self._out = {"reconciliations": []} for company_name in company_names: self._company_dict = {"header": {"company": company_name, "inc_sum": 0, "out_sum": 0, "balance": 0}, "incoming": [], "outgoing": []} self._process_open_payments(company_name) self._out["reconciliations"].append(self._company_dict) return self._out def _process_open_payments(self, company_name): open_payments = payment.get_open_payments_of_company(company_name) for open_payment in open_payments: open_payment_dict = self._pay_stat_api.get_result(open_payment.guid) open_amt = self._curr.convert_to_local_currency( open_payment_dict["summary"]["open_amount"], open_payment_dict["summary"]["currency"]) if open_payment.direction == payment.DIRECTION_IN: self._company_dict["incoming"].append(open_payment_dict) self._company_dict["header"]["inc_sum"] += open_amt self._company_dict["header"]["balance"] += open_amt elif open_payment.direction == payment.DIRECTION_OUT: self._company_dict["outgoing"].append(open_payment_dict) self._company_dict["header"]["out_sum"] += open_amt self._company_dict["header"]["balance"] -= open_amt
def amount_in_local_currency(self) -> float: """ Payment amount in home currency """ amount, currency = self.amount local_amount = CurrencyConverter().convert_to_local_currency( amount, currency) return local_amount
class Invoice: """ Invoice class """ @staticmethod def delete_invoices(invoice_guids: List): """ Deletes the provided invoices """ all_invoices = get_invoices() new_invoices = {"invoices": []} for i in range(len(all_invoices["invoices"])): invoice_i = all_invoices["invoices"][i] if invoice_i["guid"] not in invoice_guids: new_invoices["invoices"].append(invoice_i) Invoice._write_invoices_to_disk(new_invoices) @staticmethod def get_due_date_suggestion(invoice_date: datetime) -> datetime: """ Suggests a due date based on the invoice date """ output = date_time.get_next_month(date=invoice_date) output = date_time.get_first_day_of_next_month(output) while True: while output.weekday() != 2: # Wednesday output = date_time.get_next_day(output) if date_time.is_working_day(output): return output output = date_time.get_next_day(output) @staticmethod def get_invoice_date_suggestion() -> datetime: """ Suggests an invoice date """ output = datetime.datetime.now() if output.day > 15: output = date_time.get_last_day_of_month(output) else: output = date_time.get_last_day_of_prev_month(output) return output @staticmethod def _write_invoices_to_disk(invoices: List): with open(get_file_path(), "w", encoding="utf-8") as invoice_file: json.dump(invoices, invoice_file, indent=3) def __init__(self, invoice: dict): self._invoice = invoice self._amount = float(self._invoice["amount"]) self._vat_rate = float(self._invoice["vat_rate"]) self._income_tax_rate = float(self._invoice["income_tax_rate"]) self._currency_converter = CurrencyConverter() @property def alms_amount(self) -> float: """ Amount of recommended alms """ return (self.amount - self.income_tax_amount) * config.CONSTANTS["DEFAULT_ALMS_RATE"] / 100 @property def alms_payment_date(self) -> datetime: """ Alms payment date """ return self.due_date + datetime.timedelta(days=1) @property def amount(self) -> float: """ Invoice amount as float """ return self._amount @property def amount_plus_vat(self) -> float: """ Invoice amount + vat as float """ return self.amount + self.vat_amount @property def currency(self) -> str: """ Invoice currency """ return self._invoice["currency"] @property def due_date(self) -> datetime: """ Invoice due date """ return date_time.parse_json_date(self._invoice["due_date"]) @property def file_path(self) -> str: """ File path of invoice This is usually the PDF file of the e-archive invoice """ if "file_path" in self._invoice: return self._invoice["file_path"] return "" @file_path.setter def file_path(self, file_path: str): """ File path setter """ self._invoice["file_path"] = file_path @property def guid(self) -> str: """ Invoice GUID Every invoice will have a unique immutable GUID. But if you really need to change it, you can edit JSON data files """ return self._invoice["guid"] @property def income_tax_amount(self) -> float: """ Income tax amount """ return self.amount * self.income_tax_rate / 100 @property def income_tax_payment_date(self) -> datetime: """ Income tax payment date (suggestion) """ return datetime.date(self.invoice_date.year + 1, 3, 15) @property def income_tax_rate(self) -> float: """ Income tax rate Usually ~30% """ return self._income_tax_rate @property def income_tax_transfer_date(self) -> datetime: """ Suggested income tax transfer date """ return self.due_date + datetime.timedelta(days=1) @property def invoice_date(self) -> datetime: """ Invoice date """ return date_time.parse_json_date(self._invoice["invoice_date"]) @property def payer(self) -> Company: """ Company which will pay the invoice """ return Company(self._invoice["payer"]) @property def serial(self) -> str: """ Invoice serial number Paper invoice: Preprinted E-Archive: Provided by GIB """ return self._invoice["serial"] @property def vat_amount(self) -> float: """ Calculated VAT amount """ return self._amount * self._vat_rate / 100 @property def vat_amount_in_local_currency(self) -> float: """ Calculated VAT amount in local currency """ return self._currency_converter.convert_to_local_currency(self.vat_amount, self.currency) @property def vat_payment_date(self) -> datetime: """ VAT payment date """ invoice_date = self.invoice_date invoice_day = invoice_date.day if invoice_day < config.CONSTANTS["VAT_DECLARATION_LAST_DAY"]: output = datetime.date( invoice_date.year, invoice_date.month, config.CONSTANTS["VAT_DECLARATION_LAST_DAY"]) else: output = datetime.date( invoice_date.year, invoice_date.month, config.CONSTANTS["VAT_DECLARATION_LAST_DAY"]) output = output + datetime.timedelta(days=30) return output @property def vat_rate(self) -> float: """ VAT rate """ return self._vat_rate @property def vat_transfer_date(self) -> datetime: """ VAT transfer date """ return self.vat_payment_date - datetime.timedelta(days=15) @property def is_vat_liable(self) -> bool: """ Is VAT liable or not Usually; foreign invoices are not VAT liable """ return not self.payer.is_foreign def save(self): """ Writes invoice data to disk """ if "guid" not in self._invoice: self._invoice["guid"] = identifier.get_guid() elif self._invoice["guid"] == "": self._invoice["guid"] = identifier.get_guid() current_invoices = get_invoices() new_invoices = {"invoices": []} updated = False for inv in current_invoices["invoices"]: if inv["guid"] == self._invoice["guid"]: new_invoices["invoices"].append(self._invoice) updated = True else: new_invoices["invoices"].append(inv) if not updated: new_invoices["invoices"].append(self._invoice) Invoice._write_invoices_to_disk(new_invoices)
def __init__(self, invoice: dict): self._invoice = invoice self._amount = float(self._invoice["amount"]) self._vat_rate = float(self._invoice["vat_rate"]) self._income_tax_rate = float(self._invoice["income_tax_rate"]) self._currency_converter = CurrencyConverter()
def record_cash_movement(company: str, direction: str, amount: float, currency: str, description: str, income_tax_only: bool = False): """ Records a new cash movement """ ############################## # Preparation ############################## backup.execute() changed_payments = [] curr_conv = CurrencyConverter() open_amount = amount open_payments = get_open_payments_of_company(company) date_iso = datetime.datetime.now().isoformat() ############################## # Deduct from open payments ############################## for payment in open_payments: if open_amount <= 0: break if payment.direction != direction: continue if income_tax_only and (not payment.is_income_tax): continue payment.generate_very_long_term_recurrences() scheme = payment.scheme recurrences = scheme.recurrences for recurrence in recurrences: if open_amount <= 0: break if not recurrence.cleared: rec_open_amount, rec_curr = recurrence.open_amount open_amount_conv = curr_conv.convert_to_currency( from_amount=open_amount, from_currency=currency, to_currency=rec_curr) if open_amount_conv >= rec_open_amount: coll = { "date": date_iso, "description": description, "amount": rec_open_amount, "currency": rec_curr } recurrence.add_collection(Collection(coll)) recurrence.cleared = True remain_amount = open_amount_conv - rec_open_amount open_amount = open_amount * (remain_amount / open_amount_conv) else: coll = { "date": date_iso, "description": description, "amount": open_amount_conv, "currency": rec_curr } recurrence.add_collection(Collection(coll)) open_amount = 0 scheme.recurrences = recurrences payment.scheme = scheme if payment.open_amount[0] <= 0: payment.cleared = True changed_payments.append(payment) ############################## # Overpayment? Need to be paid back ############################## if open_amount > 0: if direction == DIRECTION_IN: pay_back_dir = DIRECTION_OUT else: pay_back_dir = DIRECTION_IN pay_back_dict = { "creation_date": date_iso, "company": company, "description": description + " - fazla ödeme iade", "direction": pay_back_dir, "amount": open_amount, "currency": currency, "cleared": False, "scheme": { "frequency": 1, "period": "D", "start": date_iso, "repeat": 1, "recurrence": [] } } changed_payments.append(Payment(pay_back_dict)) ############################## # Finish ############################## for payment in changed_payments: payment.save()
def __init__(self) -> None: self._curr_conv = CurrencyConverter()
class AssetProfitAPI(): """ Asset profit API class """ def __init__(self) -> None: self._curr_conv = CurrencyConverter() @property def result(self) -> dict: """ Returns result """ out = {"Profits": [], "Sums": {"liquid_sales": 0, "liquid_profit": 0, "sales": 0, "liquid_sales_home": 0, "liquid_profit_home": 0, "sales_home": 0}} assets = imp_asset.get_assets(deduct_income_tax=True, own_percentage_only=True) assets["assets"].sort(key=lambda x: imp_asset.is_liquid(x["type"]), reverse=True) for asset in assets["assets"]: asset_profit = self._calc_asset_profit(asset) history = "" prev_hist_val = 0 if "value_history" in asset: for history_entry in asset["value_history"]: hist_asset = deepcopy(asset) hist_asset["sales_value"] = history_entry["value"] hist_profit = self._calc_asset_profit(hist_asset) if history != "": if hist_profit["usd_profit"] > prev_hist_val: history += " ↑ " else: history += " ↓ " history += str(round(hist_profit["usd_profit"])) prev_hist_val = hist_profit["usd_profit"] asset_dict = deepcopy(asset_profit) asset_dict["name"] = asset["name"] asset_dict["purchase_date"] = date_time.get_formatted_date(asset_profit["purchase_date"]) # pylint: disable=C0301 asset_dict["quantity"] = asset["quantity"] asset_dict["history"] = history out["Profits"].append(asset_dict) if imp_asset.is_liquid(asset["type"]): out["Sums"]["liquid_sales"] += int(asset_dict["actual_usd_total"]) out["Sums"]["liquid_profit"] += int(asset_dict["usd_profit"]) out["Sums"]["sales"] += int(asset_dict["actual_usd_total"]) out["Sums"]["liquid_sales_home"] = int(self._curr_conv.convert_to_local_currency( out["Sums"]["liquid_sales"], "USD")) out["Sums"]["liquid_profit_home"] = int(self._curr_conv.convert_to_local_currency( out["Sums"]["liquid_profit"], "USD")) out["Sums"]["sales_home"] = int(self._curr_conv.convert_to_local_currency( out["Sums"]["sales"], "USD")) return out def _calc_asset_profit(self, asset: dict) -> dict: purchase_date = date_time.parse_json_date(asset["purchase_date"]) old_currency_converter = OldCurrencyConverter(purchase_date) purchase_value = self._curr_conv.convert_to_local_currency(asset["purchase_value"], asset["currency"]) purchase_total = asset["quantity"] * purchase_value purchase_usd_total = old_currency_converter.convert_to_foreign_currency(purchase_total, "USD") sales_value = self._curr_conv.convert_to_local_currency(asset["sales_value"], asset["currency"]) sales_total = asset["quantity"] * sales_value actual_usd_price = self._curr_conv.convert_to_foreign_currency(sales_value, "USD") actual_usd_total = asset["quantity"] * actual_usd_price usd_profit = actual_usd_total - purchase_usd_total if purchase_usd_total == 0: perc_profit = 0 else: perc_profit = (usd_profit / purchase_usd_total) * 100 result = { "purchase_date": purchase_date, "purchase_value": purchase_value, "purchase_total": purchase_total, "purchase_usd_total": purchase_usd_total, "sales_value": sales_value, "sales_total": sales_total, "actual_usd_price": actual_usd_price, "actual_usd_total": actual_usd_total, "usd_profit": usd_profit, "perc_profit": perc_profit } return result
def amount_in_home_currency(self) -> float: """ Amount in home currency """ if self._curr_conv is None: self._curr_conv = CurrencyConverter() return self._curr_conv.convert_to_local_currency( self.amount, self.currency)
class IncomeTaxCalculator(): """ Income tax calculator class """ def __init__(self): self._tax_rates = [] self._default_tax_rate = 0 self._default_tax_rate_calculated = False self._tmp_tax_rate = 0 self._tmp_tax_rate_calculated = False self._forecast_tax_rate = 0 self._forecast_tax_rate_calculated = False self._converter = CurrencyConverter() self._read_tax_rates() @property def default_tax_rate(self) -> float: """ Returns average tax rate from historic invoices """ if not self._default_tax_rate_calculated: today = date.today() invoices = get_invoices_of_last_year() invoice_sum = 0 for invoice in invoices: home_amount = self._converter.convert_to_local_currency( invoice["amount"], invoice["currency"]) inv_date = parse_json_date(invoice["invoice_date"]) if inv_date.year < today.year: home_amount *= 1 + (config.CONSTANTS["TUFE_RATE"] / 100) invoice_sum += home_amount annual_tax = self._calc_annual_tax(invoice_sum) self._default_tax_rate = (annual_tax / invoice_sum) * 100 self._default_tax_rate_calculated = True return self._default_tax_rate @property def temp_tax_rate(self) -> float: """ Returns temporay tax rate """ if not self._tmp_tax_rate_calculated: self._tmp_tax_rate = self.default_tax_rate / 2 self._tmp_tax_rate_calculated = True return self._tmp_tax_rate @property def safety_tax_rate(self) -> float: """ Returns safety tax rate """ return self.temp_tax_rate @property def forecast_tax_rate(self) -> float: """ Returns forecast tax rate """ if not self._forecast_tax_rate_calculated: # Last year (with inflation) last_year = date.today().year - 1 last_year_invoices = get_invoices_of_fiscal_year(last_year) invoice_sum = 0 for invoice in last_year_invoices: home_amount = self._converter.convert_to_local_currency( invoice["amount"], invoice["currency"]) home_amount *= 1 + (config.CONSTANTS["TUFE_RATE"] / 100) invoice_sum += home_amount if invoice_sum == 0: last_year_rate = 0 else: last_year_annual_tax = self._calc_annual_tax(invoice_sum) last_year_rate = last_year_annual_tax / invoice_sum # This year (projection) this_year_invoices = get_invoices_of_fiscal_year(date.today().year) invoice_sum = 0 for invoice in this_year_invoices: home_amount = self._converter.convert_to_local_currency( invoice["amount"], invoice["currency"]) home_amount *= 1 + (config.CONSTANTS["TUFE_RATE"] / 100) invoice_sum += home_amount invoice_sum += Activity.get_total_activity_earnings() invoice_sum = invoice_sum * (12 - (date.today().month) + 1) if invoice_sum == 0: this_year_rate = 0 else: this_year_annual_tax = self._calc_annual_tax(invoice_sum) this_year_rate = this_year_annual_tax / invoice_sum # Average if this_year_rate == 0: self._forecast_tax_rate = last_year_rate elif last_year_rate == 0: self._forecast_tax_rate = this_year_rate else: if this_year_rate > last_year_rate: self._forecast_tax_rate = this_year_rate else: self._forecast_tax_rate = (this_year_rate + last_year_rate) / 2 self._forecast_tax_rate *= 100 self._forecast_tax_rate_calculated = True return self._forecast_tax_rate def calc_invoice_tax_rate(self, year: int, amount: float) -> float: """ Calculate tax rate for given invoice """ fiscal_invoices = get_invoices_of_fiscal_year(year) invoice_sum = 0 for invoice in fiscal_invoices: home_amount = self._converter.convert_to_local_currency( invoice["amount"], invoice["currency"]) invoice_sum += home_amount invoice_sum += amount for tax_rate in self._tax_rates: if tax_rate["amount"] >= invoice_sum: return tax_rate["rate"] raise Exception("Couldn't calculate invoice tax rate") def calc_invoice_tax_amount(self, year: int, amount: float) -> float: """ Calculate tax for given invoice """ tax_rate = self.calc_invoice_tax_rate(year, amount) return amount * tax_rate / 100 def _read_tax_rates(self): with open(self._income_tax_file_path, encoding="utf-8") as tax_file: json_data = json.load(tax_file) self._tax_rates = json_data["rates"] def _calc_annual_tax(self, amount: float) -> float: out = 0 remain = amount for tax_rate in self._tax_rates: if remain > tax_rate["amount"]: tax_amount = tax_rate["amount"] * tax_rate["rate"] / 100 out += tax_amount remain -= tax_rate["amount"] else: tax_amount = remain * tax_rate["rate"] / 100 out += tax_amount remain = 0 break return out @property def _income_tax_file_path(self) -> str: return path.join(config.CONSTANTS["DATA_DIR_PATH"] + _INCOME_TAX_FILE)
def __init__(self): self._out = {} self._company_dict = {} self._pay_stat_api = PaymentStatusAPI() self._curr = CurrencyConverter()
def get_plan_vs_actual_list() -> List: """ Plan vs actual """ conv = CurrencyConverter() out = get_plan_list() fiscal = _get_latest_fiscal_file_content() for subject in out: subject["actuals"] = [{ "month": 1, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 2, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 3, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 4, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 5, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 6, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 7, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 8, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 9, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 10, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 11, "amount": 0, "status_icon": _GREEN_ICON }, { "month": 12, "amount": 0, "status_icon": _GREEN_ICON }] for actual_months in fiscal["actuals"]: for actual in actual_months["values"]: if actual["domain"] != subject["domain"]: continue if actual["subject"] != subject["subject"]: continue if actual["direction"] != subject["direction"]: continue local_amount = conv.convert_to_local_currency( actual["amount"], actual["currency"]) for out_actual in subject["actuals"]: if out_actual["month"] == actual_months["month"]: out_actual["amount"] += local_amount out_actual["status_icon"] = _get_status_icon( subject["monthly_plan_amount"], out_actual["amount"]) break return out
def open_amount_in_local_currency(self) -> float: """ Payment open amount in local currency """ open_amount, curr = self.open_amount local_amount = CurrencyConverter().convert_to_local_currency( open_amount, curr) return local_amount
def get_payment_objects_from_invoice(invoice: Invoice) -> list: """ Extracts new payment objects out of an invoice """ # Preparation output = [] currency_converter = CurrencyConverter() inc_tax_calc = IncomeTaxCalculatorFactory.get_instance() invoice_currency = invoice.currency invoice_date = invoice.invoice_date invoice_payer = invoice.payer invoice_serial = invoice.serial payment_amount = invoice.amount_plus_vat description_prefix = invoice_payer.name + " - " + date_time.get_formatted_date( invoice_date) + "(" + invoice_serial + ")" # Incoming payment incoming_payment_json = { "guid": identifier.get_guid(), "creation_date": datetime.datetime.now().isoformat(), "company": invoice_payer.name, "description": description_prefix + " - Incoming payment", "invoice_guid": invoice.guid, "direction": DIRECTION_IN, "amount": payment_amount, "currency": invoice_currency, "cleared": False } incoming_scheme_json = { "frequency": 1, "period": PERIOD_DAILY, "start": invoice.due_date.isoformat(), "repeat": 1, "recurrence": [{ "recurrence_date": invoice.due_date.isoformat(), "expected_payment_date": invoice.due_date.isoformat(), "amount": payment_amount, "currency": invoice_currency, "cleared": False, "collections": [] }] } incoming_scheme_obj = Scheme(incoming_scheme_json) incoming_payment_obj = Payment(incoming_payment_json) incoming_payment_obj.scheme = incoming_scheme_obj output.append(incoming_payment_obj) # VAT transfer if invoice.is_vat_liable: vat_amount = invoice.vat_amount_in_local_currency vat_transfer_json = { "guid": identifier.get_guid(), "creation_date": datetime.datetime.now().isoformat(), "company": config.CONSTANTS["DEFAULT_BANK"], "description": description_prefix + " - VAT transfer", "invoice_guid": "", "direction": DIRECTION_TRANSFER, "amount": vat_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False } vat_transfer_date = invoice.vat_transfer_date vat_transfer_scheme_json = { "frequency": 1, "period": PERIOD_DAILY, "start": vat_transfer_date.isoformat(), "repeat": 1, "recurrence": [{ "recurrence_date": vat_transfer_date.isoformat(), "expected_payment_date": vat_transfer_date.isoformat(), "amount": vat_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False, "collections": [] }] } vat_transfer_scheme_obj = Scheme(vat_transfer_scheme_json) vat_transfer_payment_obj = Payment(vat_transfer_json) vat_transfer_payment_obj.scheme = vat_transfer_scheme_obj output.append(vat_transfer_payment_obj) # VAT payment if invoice.is_vat_liable: vat_amount = invoice.vat_amount_in_local_currency vat_payment_json = { "guid": identifier.get_guid(), "creation_date": datetime.datetime.now().isoformat(), "company": config.CONSTANTS["HOME_GOVERNMENT"], "description": description_prefix + " - VAT payment", "invoice_guid": "", "direction": DIRECTION_OUT, "amount": vat_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False, "is_vat": True } vat_payment_date = invoice.vat_payment_date vat_payment_scheme_json = { "frequency": 1, "period": PERIOD_DAILY, "start": vat_payment_date.isoformat(), "repeat": 1, "recurrence": [{ "recurrence_date": vat_payment_date.isoformat(), "expected_payment_date": vat_payment_date.isoformat(), "amount": vat_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False, "collections": [] }] } vat_payment_scheme_obj = Scheme(vat_payment_scheme_json) vat_payment_payment_obj = Payment(vat_payment_json) vat_payment_payment_obj.scheme = vat_payment_scheme_obj output.append(vat_payment_payment_obj) # Income tax investment & transfer itax_amount = currency_converter.convert_to_local_currency( invoice.income_tax_amount, invoice_currency) itax_investment_rate = 100 itax_investment_rate -= inc_tax_calc.safety_tax_rate itax_investment_rate -= inc_tax_calc.temp_tax_rate itax_investment_amount = itax_amount * itax_investment_rate / 100 itax_amount -= itax_investment_amount itax_transfer_json = { "guid": identifier.get_guid(), "creation_date": datetime.datetime.now().isoformat(), "company": config.CONSTANTS["DEFAULT_BANK"], "description": description_prefix + " - income tax investment", "invoice_guid": "", "direction": DIRECTION_TRANSFER, "amount": itax_investment_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False } itax_transfer_date = invoice.income_tax_transfer_date itax_transfer_scheme_json = { "frequency": 1, "period": PERIOD_DAILY, "start": itax_transfer_date.isoformat(), "repeat": 1, "recurrence": [{ "recurrence_date": itax_transfer_date.isoformat(), "expected_payment_date": itax_transfer_date.isoformat(), "amount": itax_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False, "collections": [] }] } itax_transfer_scheme_obj = Scheme(itax_transfer_scheme_json) itax_transfer_payment_obj = Payment(itax_transfer_json) itax_transfer_payment_obj.scheme = itax_transfer_scheme_obj output.append(itax_transfer_payment_obj) itax_transfer_json = { "guid": identifier.get_guid(), "creation_date": datetime.datetime.now().isoformat(), "company": config.CONSTANTS["DEFAULT_BANK"], "description": description_prefix + " - income tax transfer", "invoice_guid": "", "direction": DIRECTION_TRANSFER, "amount": itax_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False } itax_transfer_date = invoice.income_tax_transfer_date itax_transfer_scheme_json = { "frequency": 1, "period": PERIOD_DAILY, "start": itax_transfer_date.isoformat(), "repeat": 1, "recurrence": [{ "recurrence_date": itax_transfer_date.isoformat(), "expected_payment_date": itax_transfer_date.isoformat(), "amount": itax_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False, "collections": [] }] } itax_transfer_scheme_obj = Scheme(itax_transfer_scheme_json) itax_transfer_payment_obj = Payment(itax_transfer_json) itax_transfer_payment_obj.scheme = itax_transfer_scheme_obj output.append(itax_transfer_payment_obj) # Income tax payment itax_amount = currency_converter.convert_to_local_currency( invoice.income_tax_amount, invoice_currency) itax_payment_json = { "guid": identifier.get_guid(), "creation_date": datetime.datetime.now().isoformat(), "company": config.CONSTANTS["HOME_GOVERNMENT"], "description": description_prefix + " - income tax payment", "invoice_guid": "", "direction": DIRECTION_OUT, "amount": itax_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False, "is_income_tax": True } itax_payment_date = invoice.income_tax_payment_date itax_payment_scheme_json = { "frequency": 1, "period": PERIOD_DAILY, "start": itax_payment_date.isoformat(), "repeat": 1, "recurrence": [{ "recurrence_date": itax_payment_date.isoformat(), "expected_payment_date": itax_payment_date.isoformat(), "amount": itax_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False, "collections": [] }] } itax_payment_scheme_obj = Scheme(itax_payment_scheme_json) itax_payment_payment_obj = Payment(itax_payment_json) itax_payment_payment_obj.scheme = itax_payment_scheme_obj output.append(itax_payment_payment_obj) # Alms alms_amount = currency_converter.convert_to_local_currency( invoice.alms_amount, invoice_currency) alms_payment_json = { "guid": identifier.get_guid(), "creation_date": datetime.datetime.now().isoformat(), "company": config.CONSTANTS["COMPANY_NAME_UNKNOWN"], "description": description_prefix + " - alms", "invoice_guid": "", "direction": DIRECTION_OUT, "amount": alms_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False } alms_payment_date = invoice.alms_payment_date alms_payment_scheme_json = { "frequency": 1, "period": PERIOD_DAILY, "start": alms_payment_date.isoformat(), "repeat": 1, "recurrence": [{ "recurrence_date": alms_payment_date.isoformat(), "expected_payment_date": alms_payment_date.isoformat(), "amount": alms_amount, "currency": config.CONSTANTS["HOME_CURRENCY"], "cleared": False, "collections": [] }] } alms_payment_scheme_obj = Scheme(alms_payment_scheme_json) alms_payment_payment_obj = Payment(alms_payment_json) alms_payment_payment_obj.scheme = alms_payment_scheme_obj output.append(alms_payment_payment_obj) # Flush return output
def earned_amount_in_local_currency(self) -> float: """ Activity generated amount in local currency """ foreign_amount, foreign_currency = self.earned_amount return CurrencyConverter().convert_to_local_currency( foreign_amount, foreign_currency)