Skip to content

Commit

Permalink
Merge branch 'cleanup'
Browse files Browse the repository at this point in the history
  • Loading branch information
titov-vv committed Mar 4, 2024
2 parents 7f03264 + 222d479 commit dd17245
Show file tree
Hide file tree
Showing 86 changed files with 1,785 additions and 1,669 deletions.
2 changes: 1 addition & 1 deletion jal/compile_ui
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
/usr/lib/qt6/uic -g python -o ./ui/ui_login_lidl_plus_dlg.py ./ui/login_lidl_plus_dlg.ui
/usr/lib/qt6/uic -g python -o ./ui/ui_login_pingo_doce_dlg.py ./ui/login_pingo_doce_dlg.ui
/usr/lib/qt6/uic -g python -o ./ui/widgets/ui_income_spending_operation.py ./ui/widgets/income_spending_operation.ui
/usr/lib/qt6/uic -g python -o ./ui/widgets/ui_dividend_operation.py ./ui/widgets/dividend_operation.ui
/usr/lib/qt6/uic -g python -o ./ui/widgets/ui_asset_payment_operation.py ./ui/widgets/asset_payment_operation.ui
/usr/lib/qt6/uic -g python -o ./ui/widgets/ui_trade_operation.py ./ui/widgets/trade_operation.ui
/usr/lib/qt6/uic -g python -o ./ui/widgets/ui_transfer_operation.py ./ui/widgets/transfer_operation.ui
/usr/lib/qt6/uic -g python -o ./ui/widgets/ui_corporate_action_operation.py ./ui/widgets/corporate_action_operation.ui
Expand Down
59 changes: 40 additions & 19 deletions jal/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
class Setup:
DB_PATH = "jal.sqlite"
DB_CONNECTION = "JAL.DB"
DB_REQUIRED_VERSION = 52
DB_REQUIRED_VERSION = 53
SQLITE_MIN_VERSION = "3.35"
MAIN_WND_NAME = "JAL_MainWindow"
INIT_SCRIPT_PATH = 'jal_init.sql'
Expand Down Expand Up @@ -77,30 +77,19 @@ def load2combo(self, combobox):
combobox.addItem(self._names[item], userData=item)


class PredefinedAccountType(PredefinedList, QObject):
Cash = 1
Bank = 2
Card = 3
Investment = 4
Savings = 5
Loans = 6
eWallet = 7
class PredefinedAgents(PredefinedList, QObject): # These constant is linked with 'agents' table initial value and should be present in DB
db_update_query = "UPDATE agents SET name=:name WHERE id=:id"
Empty = 1 # Protected by trigger 'keep_predefined_agents' that should be aligned with max ID

def __init__(self):
super().__init__()
self._names = {
self.Cash: self.tr("Cash"),
self.Bank: self.tr("Bank accounts"),
self.Card: self.tr("Cards"),
self.Investment: self.tr("Investments"),
self.Savings: self.tr("Savings"),
self.Loans: self.tr("Debts / Loans"),
self.eWallet: self.tr("e-Wallets")
self.Empty: self.tr("None")
}


class PredefinedCategory:
Income = 1
class PredefinedCategory(PredefinedList, QObject): # These constants are linked with 'categories' table initial values and should be present in DB
db_update_query = "UPDATE categories SET name=:name WHERE id=:id"
Income = 1 # Protected by trigger 'keep_predefined_categories' that should be aligned with max ID
Spending = 2
Profits = 3
StartingBalance = 4
Expand All @@ -110,6 +99,38 @@ class PredefinedCategory:
Interest = 8
Profit = 9

def __init__(self):
super().__init__()
self._names = {
self.Income: self.tr("Income"),
self.Spending: self.tr("Spending"),
self.Profits: self.tr("Profits"),
self.StartingBalance: self.tr("Starting balance"),
self.Fees: self.tr("Fees"),
self.Taxes: self.tr("Taxes"),
self.Dividends: self.tr("Dividends"),
self.Interest: self.tr("Interest"),
self.Profit: self.tr("Results of investments")
}

class PredefinedTags(PredefinedList, QObject): # These constants are linked with 'tags' table initial values but are not mandatory as not used in code
db_update_query = "UPDATE tags SET tag=:name WHERE id=:id"
AccountType = 1
CashAccount = 2
BankAccount = 3
CardAccount = 4
BrokerAccount = 5

def __init__(self):
super().__init__()
self._names = {
self.AccountType: self.tr("Account type"),
self.CashAccount: self.tr("Cash"),
self.BankAccount: self.tr("Bank account"),
self.CardAccount: self.tr("Card"),
self.BrokerAccount: self.tr("Broker account")
}


class PredefinedAsset(PredefinedList, QObject):
Money = 1
Expand Down
8 changes: 4 additions & 4 deletions jal/data_export/tax_reports/portugal.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from decimal import Decimal
from datetime import datetime

from jal.db.operations import Dividend
from jal.db.operations import AssetPayment
from jal.data_export.taxes import TaxReport


Expand All @@ -24,9 +24,9 @@ def prepare_dividends(self):
for dividend in dividends:
country = dividend.asset().country()
note = ''
if dividend.subtype() == Dividend.StockDividend:
if dividend.subtype() == AssetPayment.StockDividend:
note = "Stock dividend"
if dividend.subtype() == Dividend.StockVesting:
if dividend.subtype() == AssetPayment.StockVesting:
note = "Stock vesting"
line = {
'report_template': "dividend",
Expand Down Expand Up @@ -77,7 +77,7 @@ def prepare_stocks_and_etf(self):
else: # Short trade
# Check were there any dividends during short position holding
short_dividend_eur = Decimal('0')
dividends = Dividend.get_list(self.account.id(), subtype=Dividend.Dividend)
dividends = AssetPayment.get_list(self.account.id(), subtype=AssetPayment.Dividend)
dividends = [x for x in dividends if
trade.open_operation().settlement() <= x.ex_date() <= trade.close_operation().settlement()]
for dividend in dividends:
Expand Down
10 changes: 5 additions & 5 deletions jal/data_export/tax_reports/russia.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from decimal import Decimal
from jal.constants import PredefinedAsset, PredefinedCategory
from jal.db.helpers import remove_exponent
from jal.db.operations import LedgerTransaction, Dividend, CorporateAction
from jal.db.operations import LedgerTransaction, AssetPayment, CorporateAction
from jal.db.asset import JalAsset
from jal.db.category import JalCategory
from jal.data_export.taxes import TaxReport
Expand Down Expand Up @@ -43,9 +43,9 @@ def prepare_dividends(self):
for dividend in dividends:
country = dividend.asset().country()
note = ''
if dividend.subtype() == Dividend.StockDividend:
if dividend.subtype() == AssetPayment.StockDividend:
note = "Дивиденд выплачен в натуральной форме (ценными бумагами)"
if dividend.subtype() == Dividend.StockVesting:
if dividend.subtype() == AssetPayment.StockVesting:
note = "Доход получен в натуральной форме (ценными бумагами)"
tax_rub = dividend.tax(self._currency_id)
tax2pay = Decimal('0.13') * dividend.amount(self._currency_id)
Expand Down Expand Up @@ -80,7 +80,7 @@ def prepare_trades_report(self, trades_list):
deals_report = []
ns = not self.use_settlement
# Prepare list of dividends withdrawn from account (due to short trades)
dividends_withdrawn = Dividend.get_list(self.account.id(), subtype=Dividend.Dividend)
dividends_withdrawn = AssetPayment.get_list(self.account.id(), subtype=AssetPayment.Dividend)
dividends_withdrawn = [x for x in dividends_withdrawn if self.year_begin <= x.timestamp() <= self.year_end]
dividends_withdrawn = [x for x in dividends_withdrawn if x.amount() < Decimal('0')]
for trade in trades_list:
Expand Down Expand Up @@ -221,7 +221,7 @@ def prepare_bonds(self):
# Second - take all bond interest payments not linked with buy/sell transactions
currency = JalAsset(self.account.currency())
country = self.account.country()
interests = Dividend.get_list(self.account.id(), subtype=Dividend.BondInterest, skip_accrued=True)
interests = AssetPayment.get_list(self.account.id(), subtype=AssetPayment.BondInterest, skip_accrued=True)
interests = [x for x in interests if self.year_begin <= x.timestamp() <= self.year_end] # Only in given range
for interest in interests:
amount = interest.amount()
Expand Down
19 changes: 9 additions & 10 deletions jal/data_export/taxes.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import importlib # it is used for delayed import in order to avoid circular reference in child classes
import os
import json
import logging
from datetime import datetime, timezone
from PySide6.QtWidgets import QApplication

from jal.constants import Setup, PredefinedAsset
from jal.db.helpers import get_app_path
from jal.db.settings import JalSettings
from jal.db.account import JalAccount
from jal.db.asset import JalAsset
from jal.db.operations import LedgerTransaction, Dividend
from jal.db.operations import LedgerTransaction, AssetPayment

REPORT_METHOD = 0
REPORT_TEMPLATE = 1
Expand Down Expand Up @@ -64,7 +63,7 @@ def report_template(self, report_name):
# Loads report parameters for given year into self._parameters
def load_parameters(self, year: int):
year_key = str(year)
file_path = get_app_path() + Setup.EXPORT_PATH + os.sep + Setup.TAX_REPORT_PATH + os.sep + self.country_name + ".json"
file_path = JalSettings.path(JalSettings.PATH_TAX_REPORT_TEMPLATE) + self.country_name + ".json"
try:
with open(file_path, 'r', encoding='utf-8') as json_file:
parameters = json.load(json_file)
Expand Down Expand Up @@ -112,9 +111,9 @@ def has_tax_treaty_with(self, country_code: str) -> bool:

# Returns a list of dividends that should be included into the report for given year
def dividends_list(self) -> list:
dividends = Dividend.get_list(self.account.id(), subtype=Dividend.Dividend)
dividends += Dividend.get_list(self.account.id(), subtype=Dividend.StockDividend)
dividends += Dividend.get_list(self.account.id(), subtype=Dividend.StockVesting)
dividends = AssetPayment.get_list(self.account.id(), subtype=AssetPayment.Dividend)
dividends += AssetPayment.get_list(self.account.id(), subtype=AssetPayment.StockDividend)
dividends += AssetPayment.get_list(self.account.id(), subtype=AssetPayment.StockVesting)
dividends = [x for x in dividends if self.year_begin <= x.timestamp() <= self.year_end]
return dividends

Expand All @@ -124,9 +123,9 @@ def shares_trades_list(self) -> list:
trades = [x for x in trades if x.asset().type() in [PredefinedAsset.Stock, PredefinedAsset.ETF]]
trades = [x for x in trades if x.close_operation().type() == LedgerTransaction.Trade]
trades = [x for x in trades if x.open_operation().type() == LedgerTransaction.Trade or (
x.open_operation().type() == LedgerTransaction.Dividend and (
x.open_operation().subtype() == Dividend.StockDividend or
x.open_operation().subtype() == Dividend.StockVesting))]
x.open_operation().type() == LedgerTransaction.AssetPayment and (
x.open_operation().subtype() == AssetPayment.StockDividend or
x.open_operation().subtype() == AssetPayment.StockVesting))]
trades = [x for x in trades if self.year_begin <= x.close_operation().settlement() <= self.year_end]
return trades

Expand Down
7 changes: 2 additions & 5 deletions jal/data_export/xlsx.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import os
import json
import logging
import xlsxwriter

from PySide6.QtCore import Qt, QModelIndex
from PySide6.QtWidgets import QApplication
from jal.constants import Setup
from jal.db.helpers import get_app_path
from jal.db.settings import JalSettings
from jal.widgets.helpers import ts2d


Expand Down Expand Up @@ -47,7 +44,7 @@ def save(self):

def load_template(self, file):
template = None
file_path = get_app_path() + Setup.EXPORT_PATH + os.sep + Setup.TEMPLATE_PATH + os.sep + file
file_path = JalSettings.path(JalSettings.PATH_TEMPLATES) + file
try:
with open(file_path, 'r', encoding='utf-8') as json_file:
template = json.load(json_file)
Expand Down
12 changes: 6 additions & 6 deletions jal/data_import/broker_statements/ibkr.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from jal.widgets.helpers import ManipulateDate, ts2dt, ts2d
from jal.db.helpers import format_decimal
from jal.db.account import JalAccount
from jal.db.operations import Dividend
from jal.db.operations import AssetPayment
from jal.data_import.statement import FOF, Statement_ImportError, Statement_Capabilities
from jal.data_import.statement_xml import StatementXML

Expand Down Expand Up @@ -311,13 +311,13 @@ def save_debug_info(self, account, asset):
element.attrib['accountId'] = 'U7654321' # Hide real account number
debug_info += etree.tostring(element).decode("utf-8")
debug_info += "----------------------------------------------------------------\n"
# Dump dividends info from database for the given asset from
# Dump asset_payments info from database for the given asset from
db_account = self._map_db_account(account)
db_asset = self._map_db_asset(asset)
dividends = JalAccount(db_account).dump_dividends()
dividends = [x for x in dividends if x[DIVIDENDS_TABLE_ASSET_FIELD] == db_asset]
payments = JalAccount(db_account).dump_asset_payments()
payments = [x for x in payments if x[DIVIDENDS_TABLE_ASSET_FIELD] == db_asset]
debug_info += "Database data:\n----------------------------------------------------------------\n"
debug_info += str(dividends)
debug_info += str(payments)
debug_info += "\n----------------------------------------------------------------\n"
super().save_debug_info(debug_info=debug_info)

Expand Down Expand Up @@ -1069,7 +1069,7 @@ def find_dividend4tax(self, timestamp, account_id, asset_id, prev_tax, new_tax,
db_account = self._map_db_account(account_id)
db_asset = self._map_db_asset(asset_id)
if db_account and db_asset:
for db_dividend in Dividend.get_list(db_account, db_asset, Dividend.Dividend):
for db_dividend in AssetPayment.get_list(db_account, db_asset, AssetPayment.Dividend):
dividends.append({
"id": -db_dividend.oid(),
"account": account_id,
Expand Down
40 changes: 20 additions & 20 deletions jal/data_import/statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@

from PySide6.QtCore import QObject
from PySide6.QtWidgets import QDialog, QMessageBox
from jal.constants import Setup, MarketDataFeed, PredefinedAsset, PredefinedAccountType
from jal.db.helpers import get_app_path
from jal.constants import Setup, MarketDataFeed, PredefinedAsset
from jal.db.settings import JalSettings
from jal.db.account import JalAccount
from jal.db.asset import JalAsset
from jal.db.operations import LedgerTransaction, Dividend, CorporateAction
from jal.db.operations import LedgerTransaction, AssetPayment, CorporateAction
from jal.widgets.helpers import ts2d
from jal.widgets.account_select import SelectAccountDialog
from jal.net.downloader import QuoteDownloader
Expand Down Expand Up @@ -136,7 +136,7 @@ def __init__(self):
# If 'debug_info' is given as parameter it is saved in JAL main directory text file appened with timestamp
def save_debug_info(self, **kwargs):
if 'debug_info' in kwargs:
dump_name = get_app_path() + os.sep + Setup.STATEMENT_DUMP + datetime.now().strftime("%y-%m-%d_%H-%M-%S") + ".txt"
dump_name = JalSettings.path(JalSettings.PATH_APP) + Setup.STATEMENT_DUMP + datetime.now().strftime("%y-%m-%d_%H-%M-%S") + ".txt"
try:
with open(dump_name, 'w') as dump_file:
dump_file.write(f"JAL statement dump, {datetime.now().strftime('%y/%m/%d %H:%M:%S')}\n")
Expand Down Expand Up @@ -315,7 +315,7 @@ def _key_match(self, element, key, value):
return False

def validate_format(self):
schema_name = get_app_path() + Setup.IMPORT_PATH + os.sep + Setup.IMPORT_SCHEMA_NAME
schema_name = JalSettings.path(JalSettings.PATH_APP) + Setup.IMPORT_PATH + os.sep + Setup.IMPORT_SCHEMA_NAME
try:
with open(schema_name, 'r') as schema_file:
try:
Expand Down Expand Up @@ -405,7 +405,7 @@ def _import_accounts(self, accounts):
if account['currency'] > 0:
raise Statement_ImportError(self.tr("Unmatched currency for account: ") + f"{account}")
account_data = account.copy()
account_data['type'] = PredefinedAccountType.Investment if 'type' not in account_data else account_data['type']
account_data['investing'] = 1 # if 'type' not in account_data else account_data['type']
account_data['currency'] = -account_data['currency'] # all currencies are already in db
new_account = JalAccount(data=account_data, search=True, create=True)
if new_account.id():
Expand Down Expand Up @@ -515,30 +515,30 @@ def _import_asset_payments(self, payments):
JalAccount(payment['account_id']).currency())
if payment['type'] == FOF.PAYMENT_DIVIDEND:
if payment['id'] > 0: # New dividend
payment['type'] = Dividend.Dividend
LedgerTransaction.create_new(LedgerTransaction.Dividend, payment)
payment['type'] = AssetPayment.Dividend
LedgerTransaction.create_new(LedgerTransaction.AssetPayment, payment)
else: # Dividend exists, only tax to be updated
dividend = LedgerTransaction.get_operation(LedgerTransaction.Dividend, -payment['id'])
dividend = LedgerTransaction.get_operation(LedgerTransaction.AssetPayment, -payment['id'])
dividend.update_tax(payment['tax'])
elif payment['type'] == FOF.PAYMENT_INTEREST:
payment['type'] = Dividend.BondInterest
LedgerTransaction.create_new(LedgerTransaction.Dividend, payment)
payment['type'] = AssetPayment.BondInterest
LedgerTransaction.create_new(LedgerTransaction.AssetPayment, payment)
elif payment['type'] == FOF.PAYMENT_AMORTIZATION:
payment['type'] = Dividend.BondAmortization
LedgerTransaction.create_new(LedgerTransaction.Dividend, payment)
payment['type'] = AssetPayment.BondAmortization
LedgerTransaction.create_new(LedgerTransaction.AssetPayment, payment)
elif payment['type'] == FOF.PAYMENT_STOCK_DIVIDEND:
if payment['id'] > 0: # New dividend
payment['type'] = Dividend.StockDividend
LedgerTransaction.create_new(LedgerTransaction.Dividend, payment)
payment['type'] = AssetPayment.StockDividend
LedgerTransaction.create_new(LedgerTransaction.AssetPayment, payment)
else: # Dividend exists, only tax to be updated
dividend = LedgerTransaction.get_operation(LedgerTransaction.Dividend, -payment['id'])
dividend = LedgerTransaction.get_operation(LedgerTransaction.AssetPayment, -payment['id'])
dividend.update_tax(payment['tax'])
elif payment['type'] == FOF.PAYMENT_STOCK_VESTING:
payment['type'] = Dividend.StockVesting
LedgerTransaction.create_new(LedgerTransaction.Dividend, payment)
payment['type'] = AssetPayment.StockVesting
LedgerTransaction.create_new(LedgerTransaction.AssetPayment, payment)
elif payment['type'] == FOF.PAYMENT_FEE:
payment['type'] = Dividend.Fee
LedgerTransaction.create_new(LedgerTransaction.Dividend, payment)
payment['type'] = AssetPayment.Fee
LedgerTransaction.create_new(LedgerTransaction.AssetPayment, payment)
else:
raise Statement_ImportError(self.tr("Unsupported payment type: ") + f"{payment}")

Expand Down
3 changes: 1 addition & 2 deletions jal/data_import/statements.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from PySide6.QtCore import QObject, Signal
from PySide6.QtWidgets import QFileDialog
from jal.constants import Setup
from jal.db.helpers import get_app_path
from jal.db.settings import JalSettings, FolderFor
from jal.data_import.statement import Statement_ImportError, Statement_Capabilities

Expand All @@ -24,7 +23,7 @@ def __init__(self, parent):
self.loadStatementsList()

def loadStatementsList(self):
statements_folder = get_app_path() + Setup.IMPORT_PATH + os.sep + Setup.STATEMENT_PATH
statements_folder = JalSettings.path(JalSettings.PATH_APP) + Setup.IMPORT_PATH + os.sep + Setup.STATEMENT_PATH
statement_modules = [filename[:-3] for filename in os.listdir(statements_folder) if filename.endswith(".py")]
for module_name in statement_modules:
logging.debug(f"Trying to load statement module: {module_name}")
Expand Down
Loading

0 comments on commit dd17245

Please sign in to comment.