items.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. # GPL3 or any later version
  2. import os
  3. import json
  4. import time
  5. import gi
  6. import threading
  7. gi.require_version('Gtk', '3.0')
  8. from gi.repository import Gtk
  9. from gi.repository import Gdk
  10. from gi.repository import GLib
  11. from modules import wallet
  12. from modules import images
  13. from modules import ui
  14. from modules import transactions as tmodule
  15. from modules import graphs
  16. def select_dialogue(win, mode="normal"):
  17. # This is an item selector.
  18. dialogWindow = Gtk.Dialog("Select Item",
  19. buttons=(),
  20. )
  21. dialogWindow.set_size_request(400, 400)
  22. r = Gtk.VBox()
  23. r.ret = None
  24. def todo(w, win, item):
  25. r.ret = item
  26. try:
  27. if type(item) == dict:
  28. item["amount"] = item["amount"].get_value()
  29. item["price"] = item["price"].get_value()
  30. except:
  31. pass
  32. dialogWindow.destroy()
  33. box = dialogWindow.get_content_area()
  34. select_widget(win, box, todo, mode=mode)
  35. box.show_all()
  36. response = dialogWindow.run()
  37. dialogWindow.destroy()
  38. return r.ret
  39. def select_widget(win, box, todo, mode="normal"):
  40. # Draws widget for searching and selecting items.
  41. search_box = Gtk.HBox()
  42. box.pack_start(search_box, 0,0,1)
  43. amount_entry, price_entry = False, False
  44. if mode == "transaction_add":
  45. totals = wallet.get_totals(win.wallet)
  46. currancy = totals.get("currancy", "$")
  47. # amount of the item
  48. search_box.pack_start(Gtk.Label(" x "),0,0,0)
  49. amount_adjust = Gtk.Adjustment(1,
  50. lower=-10000000000000000000,
  51. upper=10000000000000000000,
  52. step_increment=1)
  53. amount_entry = Gtk.SpinButton(adjustment=amount_adjust,
  54. digits=2)
  55. search_box.pack_start(amount_entry,0,0,0)
  56. search_box.pack_start(Gtk.Label(" "+currancy+" "),0,0,0)
  57. price_adjust = Gtk.Adjustment(0,
  58. lower=-10000000000000000000,
  59. upper=10000000000000000000,
  60. step_increment=1)
  61. price_entry = Gtk.SpinButton(adjustment=price_adjust,
  62. digits=2)
  63. search_box.pack_start(price_entry,0,0,0)
  64. sepbox = Gtk.HBox()
  65. sepbox.set_size_request(20,20)
  66. search_box.pack_start(sepbox,0,0,0)
  67. def on_changed(w):
  68. win.search_item = search.get_text()
  69. def on_search(w):
  70. refresh_items(win, pack, todo, amount_entry, price_entry, mode=mode, search=search.get_text())
  71. search = Gtk.Entry()
  72. search.connect("changed", on_changed)
  73. search.connect("activate", on_search)
  74. search_box.pack_start(search, 1,1,0)
  75. scrl = Gtk.ScrolledWindow()
  76. scrl.set_vexpand(0)
  77. box.pack_start(scrl, 1,1,1)
  78. pack = Gtk.VBox()
  79. scrl.add(pack)
  80. refresh_items(win, pack, todo, amount_entry, price_entry, mode=mode)
  81. return (win, pack, todo, amount_entry, price_entry, "", mode)
  82. def refresh_items(win, pack, todo, amount_entry, price_entry, search="", mode="normal"):
  83. for i in pack.get_children():
  84. i.destroy()
  85. flowbox = Gtk.FlowBox()
  86. flowbox.set_valign(Gtk.Align.START)
  87. flowbox.set_max_children_per_line(30)
  88. flowbox.set_selection_mode(Gtk.SelectionMode.NONE)
  89. def on_add_item(w):
  90. editor(win, new=True)
  91. refresh_items(win, pack, todo, amount_entry, price_entry, search=search, mode=mode)
  92. add_item = Gtk.Button()
  93. add_item.add(ui.icon(win, "list-add"))
  94. add_item.set_relief(Gtk.ReliefStyle.NONE)
  95. flowbox.add(add_item)
  96. add_item.connect("clicked", on_add_item)
  97. folder = wallet.save_folder()+"items/"
  98. try:
  99. items = list(os.walk(folder))[0][2]
  100. items = sorted(items)
  101. except:
  102. items = []
  103. for i in items:
  104. with open(folder+i) as json_file:
  105. idata = json.load(json_file)
  106. if search:
  107. if search.lower() not in idata.get("name").lower() and search.lower() not in i.lower():
  108. continue
  109. item_button = Gtk.Button()
  110. if mode == "transaction_add":
  111. item_button.connect("clicked", todo, win, {"item":i.replace(".json", ""),
  112. "amount":amount_entry,
  113. "price":price_entry})
  114. else:
  115. item_button.connect("clicked", todo, win, i)
  116. item_button.set_relief(Gtk.ReliefStyle.NONE)
  117. item_box = Gtk.VBox()
  118. item_button.add(item_box)
  119. save_as = idata.get("image", "")
  120. if os.path.exists(save_as):
  121. image = ui.load(win, ui.net_image_calculation, ui.net_image_render, "", 100 , save_as, False)
  122. else:
  123. image = ui.icon(win, "package-x-generic")
  124. item_box.pack_start(image, 0,0,0)
  125. item_box.pack_start(Gtk.Label(str(idata.get("name", ""))), 0,0,0)
  126. item_box.pack_start(Gtk.Label(i.replace(".json", "")),0,0,0)
  127. flowbox.add(item_button)
  128. flowbox.show_all()
  129. pack.pack_start(flowbox, 1,1,1)
  130. def editor(win, item="", new=False):
  131. # editor
  132. currancy = wallet.get_totals(win.wallet).get("currancy", "$")
  133. folder = wallet.save_folder()+"items/"
  134. try:
  135. os.makedirs(folder)
  136. except:
  137. pass
  138. data = {}
  139. edit_id = True
  140. try:
  141. search = win.search_item
  142. except:
  143. search = ""
  144. if not item:
  145. item = search
  146. if item:
  147. try:
  148. if not item.endswith(".json"):
  149. item = item+".json"
  150. with open(folder+item) as json_file:
  151. data = json.load(json_file)
  152. item = item.replace(".json", "")
  153. edit_id = False
  154. except:
  155. pass
  156. if not data:
  157. data = {
  158. "name":"",
  159. "image":""}
  160. try:
  161. item = str(int(search))
  162. except:
  163. data["name"] = search
  164. dialogWindow = Gtk.Dialog("Item",
  165. buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
  166. Gtk.STOCK_OK, Gtk.ResponseType.OK),
  167. )
  168. dialogWindow.set_size_request(200, 200)
  169. box = dialogWindow.get_content_area()
  170. main_data_box = Gtk.HBox()
  171. box.pack_start(main_data_box, 0,1,1)
  172. # IMAGE
  173. def image_edit(w):
  174. search = id_entry.get_text()+" "+name_entry.get_text()
  175. if search:
  176. images.select_image(win, search)
  177. save_as = win.return_search
  178. data["image"] = save_as
  179. add_image.get_children()[0].destroy()
  180. image = ui.load(win, ui.net_image_calculation, ui.net_image_render, "", 100 , save_as, False)
  181. add_image.add(image)
  182. add_image.show_all()
  183. add_image = Gtk.Button()
  184. main_data_box.pack_start(add_image, 0,0,0)
  185. add_image.connect("clicked", image_edit)
  186. add_image.set_relief(Gtk.ReliefStyle.NONE)
  187. if not data.get("image"):
  188. add_image.add(ui.icon(win, "image-x-generic"))
  189. else:
  190. save_as = data.get("image")
  191. image = ui.load(win, ui.net_image_calculation, ui.net_image_render, "", 100 , save_as, False)
  192. add_image.add(image)
  193. text_data_box = Gtk.VBox()
  194. main_data_box.pack_start(text_data_box, 1,1,1)
  195. # ID
  196. def on_entry(w, d):
  197. data[d] = w.get_text()
  198. id_box = Gtk.HBox()
  199. text_data_box.pack_start(id_box, 0,0,5)
  200. id_box.pack_start(Gtk.Label(" ID: "), 0,0,0)
  201. id_entry = Gtk.Entry()
  202. id_entry.grab_focus()
  203. id_entry.set_sensitive(edit_id)
  204. id_box.pack_end(id_entry, 0,0,0)
  205. # NAME
  206. name_box = Gtk.HBox()
  207. text_data_box.pack_start(name_box, 0,0,5)
  208. name_box.pack_start(Gtk.Label(" Name: "), 0,0,0)
  209. name_entry = Gtk.Entry()
  210. name_entry.connect("changed", on_entry, "name")
  211. name_box.pack_end(name_entry, 0,0,0)
  212. # TOTALS
  213. total_amount = 0
  214. total_money = 0
  215. all_prices = []
  216. all_trans = []
  217. graph_data = {"items":[],
  218. "zoom":[0,0],
  219. "allow_negative":True
  220. }
  221. tfolder = wallet.save_folder()+"wallets/"+win.wallet+"/transactions/"
  222. try:
  223. transactions = list(os.walk(tfolder))[0][2]
  224. transactions = sorted(transactions)
  225. except:
  226. transactions = []
  227. for i in transactions:
  228. try:
  229. with open(tfolder+i) as json_file:
  230. tdata = json.load(json_file)
  231. for b in tdata.get("items", []):
  232. if b.get("item") == item:
  233. all_trans.append(i)
  234. total_money = total_money + ( b.get("price", 0) * b.get("amount", 0))
  235. graph_data["items"].append({"amount":b.get("price", 0) * b.get("amount", 0),
  236. "timestamp":int(i.replace(".json", ""))
  237. })
  238. all_prices.append(b.get("price", 0))
  239. total_amount = total_amount + b.get("amount", 0)
  240. except Exception as e:
  241. print(i, e )
  242. try:
  243. average_price = sum(all_prices) / len(all_prices)
  244. except:
  245. average_price = 0
  246. # Notebook
  247. notebook = Gtk.Notebook()
  248. notebook.set_scrollable(True)
  249. if not new:
  250. box.pack_start(notebook, 1,1,1)
  251. totals_box = Gtk.VBox()
  252. totals_box.pack_start(Gtk.Label("Total Items: "+str(round(total_amount, 2))), 0,0,0)
  253. totals_box.pack_start(Gtk.Label("Total Money: "+currancy+str(round(total_money,2))), 0,0,0)
  254. totals_box.pack_start(Gtk.Label("Average Price: "+currancy+str(round(average_price,2))), 0,0,0)
  255. detailsbox = Gtk.HBox()
  256. detailsbox.pack_start(Gtk.Label(" Totals "), True, True, True)
  257. detailsbox.show_all()
  258. notebook.append_page(totals_box, detailsbox)
  259. # TRANSACTIONS
  260. transactions_scrl = Gtk.ScrolledWindow()
  261. trbox = Gtk.VBox()
  262. transactions_scrl.add(trbox)
  263. for i in all_trans:
  264. with open(tfolder+i) as json_file:
  265. tdata = json.load(json_file)
  266. def on_tbutton(w, name):
  267. tmodule.editor(win, name)
  268. tbutton = Gtk.Button()
  269. tbutton.connect("clicked", on_tbutton, i)
  270. tbutton.set_relief(Gtk.ReliefStyle.NONE)
  271. tbox = Gtk.HBox()
  272. tbutton.add(tbox)
  273. tbox.pack_start(ui.icon(win,"task-past-due"), 0,0,0)
  274. try:
  275. tdate = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(i.replace(".json", ""))))
  276. except Exception as e:
  277. print( e )
  278. tdate = "[Date Unknown]"
  279. tbox.pack_start(Gtk.Label(tdate), 1,1,1)
  280. tbox.pack_end(Gtk.Label(str(round(tdata.get("total", 0), 2))), 0,0,5)
  281. trbox.pack_start(tbutton, 0,0,0)
  282. detailsbox = Gtk.HBox()
  283. detailsbox.pack_start(Gtk.Label(" Transactions "), True, True, True)
  284. detailsbox.show_all()
  285. notebook.append_page(transactions_scrl, detailsbox)
  286. # GRAPH
  287. the_graph = graphs.graph(win, graph_data, "Graph", currancy=currancy, add_value=0)
  288. detailsbox = Gtk.HBox()
  289. detailsbox.pack_start(Gtk.Label(" Graph "), True, True, True)
  290. detailsbox.show_all()
  291. notebook.append_page(the_graph, detailsbox)
  292. # Auto filling
  293. if item:
  294. id_entry.set_text( str(item).replace(".json", "") )
  295. name_entry.grab_focus()
  296. name_entry.set_text(str(data.get("name", "")))
  297. box.show_all()
  298. response = dialogWindow.run()
  299. if response == Gtk.ResponseType.OK:
  300. item = id_entry.get_text()
  301. if new: # Failsafe for in case the user will accidentaly overwrite
  302. n = 0 # an existing item by mistake.
  303. nn = item
  304. while os.path.exists(folder+str(item)+".json"):
  305. n = n + 1
  306. item = nn+"_"+str(n)
  307. filename = folder+str(item)+".json"
  308. with open(filename, "w") as fp:
  309. json.dump(data, fp, indent=4)
  310. dialogWindow.destroy()