dbread.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. '''
  2. Created on Jun 21, 2018 @author: levente.marton
  3. '''
  4. import os
  5. import shutil
  6. import re
  7. import datetime
  8. from dataclasses import dataclass
  9. from pypxlib import Table
  10. @dataclass
  11. class Company:
  12. name: str
  13. vat_code: str
  14. reg_number: str
  15. address: str
  16. location: str
  17. county: str
  18. shortname: str
  19. obs: str
  20. adm: str
  21. admp: str
  22. admcnp: str
  23. mail: str = None
  24. price: int = None
  25. @dataclass
  26. class Account:
  27. clasa: str
  28. simbol: str
  29. denumire: str
  30. soldid: str = None
  31. soldic: str = None
  32. precedentd: str = None
  33. precedentc: str = None
  34. curentd: str = None
  35. curentc: str = None
  36. def soldf(self, type_):
  37. if type_ == 'd':
  38. return round((self.soldid + self.precedentd + self.curentd) -
  39. (self.soldic + self.precedentc + self.curentc))
  40. elif type_ == 'c':
  41. return round((self.soldic + self.precedentc + self.curentc) -
  42. (self.soldid + self.precedentd + self.curentd))
  43. class WinMentor(object):
  44. '''
  45. Class to read winmentor database
  46. '''
  47. def __init__(self, winment_path=os.getenv('WINMENT', 'c:/winment/data/').replace('\\', '/')):
  48. '''
  49. Constructor
  50. '''
  51. self.winment_path = winment_path
  52. @property
  53. def get_winment_path(self):
  54. return self.winment_path
  55. @get_winment_path.setter
  56. def set_winment_path(self, value):
  57. # self.value = value
  58. self.winment_path = value
  59. return self.winment_path
  60. def update_copy(self, db_file) -> str:
  61. '''returns the updated version of a .db file
  62. :param db_file is a .db from winmentor'''
  63. # self._to_file = db_file
  64. _, file_name = os.path.split(db_file)
  65. dir_list = db_file.split('/')
  66. # !!NOTE: if path is ?/winment/data/ then this must be 3 & 5
  67. # if is ?/winment/winment/data/ then 4 & 6
  68. dir_to_file = dir_list[4]
  69. if len(dir_list) != 6:
  70. os.makedirs(os.path.join('cash', dir_to_file), exist_ok=True)
  71. cashed_copy_mtime = -1
  72. if os.path.isfile(os.path.join('./cash/', dir_to_file, file_name)):
  73. cashed_copy_mtime = os.stat(os.path.join('./cash/', dir_to_file, file_name)).st_mtime
  74. if os.stat(db_file).st_mtime != cashed_copy_mtime:
  75. shutil.copy2(db_file, os.path.join('./cash', dir_to_file))
  76. return(os.path.join('./cash/', dir_to_file, file_name))
  77. else:
  78. os.makedirs('cash', exist_ok=True)
  79. cashed_copy_mtime = -1
  80. if os.path.isfile('./cash/' + file_name):
  81. cashed_copy_mtime = os.stat('./cash/' + file_name).st_mtime
  82. if os.stat(db_file).st_mtime != cashed_copy_mtime:
  83. shutil.copy2(db_file, './cash')
  84. return('./cash/' + file_name)
  85. def make_list(self, db_file, headers) -> list:
  86. '''returns a list of lists with elements from a given db file
  87. :param db_file is .db file from winmentor
  88. :param headers are the fields of the specified db file'''
  89. file_name = self.update_copy(db_file)
  90. with Table(file_name) as table:
  91. m_list = []
  92. for row in table:
  93. item = []
  94. for header in headers:
  95. element = row[header]
  96. if type(element) == datetime.date:
  97. if element < datetime.date(1999, 1, 1):
  98. element = ''
  99. item.append(element)
  100. m_list.append(item)
  101. return m_list
  102. def make_sal_list(self, file_1, file_2) -> list:
  103. '''returns list with all employees in current month
  104. :param file_1 is npers.db from shortname
  105. :param file_2 is likisal.db shortname/current_month'''
  106. file_name1 = self.update_copy(self.winment_path + file_1)
  107. file_name2 = self.update_copy(self.winment_path + file_2)
  108. with Table(file_name1) as perss, Table(file_name2) as sals:
  109. empl_all = []
  110. # for field in perss.fields:
  111. for sal in sals:
  112. for pers in perss:
  113. # print(pers)
  114. if pers.Cod == sal.Cod:
  115. empl = []
  116. empl.append(pers.Cod)
  117. empl.append(f'{pers.Nume} {pers.Prenume}')
  118. empl.append(pers.DataAngF.strftime('%d-%m-%Y'))
  119. empl.append(sal.VenitBrut)
  120. empl.append(sal.SalRealizat)
  121. empl.append(sal.CO)
  122. empl.append(round(sal.SalOra, 2))
  123. empl.append(sal.ContribAngajat)
  124. empl.append(round(sal.ContribAngajator, 2))
  125. empl.append(sal.VenitNet)
  126. empl.append(sal.Impozit)
  127. empl.append(sal.SalarNet)
  128. empl.append(sal.OreLucrate)
  129. empl.append(sal.ZileLuk)
  130. empl.append(sal.ZileCO)
  131. empl_all.append(empl)
  132. # dict_ = {}
  133. # dict_['Cod'] = pers.Cod
  134. # dict_['Nume'] = f'{pers.Nume} {pers.Prenume}'
  135. # dict_['DataAngF'] = pers.DataAngF.strftime('%d-%m-%Y')
  136. # dict_['VenitBrut'] = sal.VenitBrut
  137. # dict_['SalRealizat'] = sal.SalRealizat
  138. # dict_['CO'] = sal.CO
  139. # dict_['SalOra'] = round(sal.SalOra, 2)
  140. # dict_['ContribAngajat'] = sal.ContribAngajat
  141. # dict_['ContribAngajator'] = round(sal.ContribAngajator, 2)
  142. # dict_['VenitNet'] = sal.VenitNet
  143. # dict_['Impozit'] = sal.Impozit
  144. # dict_['SalarNet'] = sal.SalarNet
  145. # dict_['OreLucrate'] = sal.OreLucrate
  146. # dict_['ZileLuk'] = sal.ZileLuk
  147. # dict_['ZileCO'] = sal.ZileCO
  148. # empl.append(dict_)
  149. return empl_all
  150. def gen_firms(self, db_file, headers) -> list:
  151. '''generates company list from firme.db file
  152. :param db_file is firme.db from winment/data folder'''
  153. file_db = self.update_copy(self.winment_path + db_file)
  154. with Table(file_db) as table:
  155. for row in table:
  156. yield [row[header] for header in headers]
  157. def firmlist(self, headers, db_file='/firme.db', ban=None) -> list:
  158. '''returns company list from firme.db file
  159. :param db_file is firme.db from winment/data folder
  160. :param list headers is the fields from firme.db file
  161. :param list|str ban companies excluded from list'''
  162. comp_list = []
  163. for a_company in self.gen_firms(db_file, headers):
  164. company = Company(
  165. name=a_company[0],
  166. vat_code=a_company[1],
  167. reg_number=a_company[2],
  168. address=a_company[3],
  169. location=a_company[4],
  170. county=a_company[5],
  171. shortname=a_company[6],
  172. adm=a_company[7],
  173. admp=a_company[8],
  174. admcnp=a_company[9],
  175. obs=a_company[10])
  176. comp_list.append(company)
  177. if ban:
  178. if type(ban) is list:
  179. for r in comp_list:
  180. for company_shortname in ban:
  181. if company_shortname == r.shortname:
  182. comp_list.remove(r)
  183. else:
  184. for r in comp_list:
  185. if r == ban:
  186. comp_list.remove(r)
  187. return comp_list
  188. def filtered_firmlist(self, headers, db_file='/firme.db', ban=None) -> list:
  189. '''generates company list from firme.db file
  190. :param db_file is firme.db from winment/data folder
  191. :param list headers is the fields from firme.db file
  192. :param list|str ban companies excluded from list'''
  193. if ban:
  194. if type(ban) is list:
  195. for a_company in self.gen_firms(db_file, headers):
  196. company = Company(
  197. name=a_company[0],
  198. vat_code=a_company[1],
  199. reg_number=a_company[2],
  200. address=a_company[3],
  201. location=a_company[4],
  202. county=a_company[5],
  203. shortname=a_company[6],
  204. adm=a_company[7],
  205. admp=a_company[8],
  206. admcnp=a_company[9],
  207. obs=a_company[10])
  208. if a_company[6] not in ban:
  209. yield [company.name, company.vat_code, company.reg_number,
  210. company.address, company.location, company.county,
  211. company.shortname, company.adm, company.admp,
  212. company.admcnp, company.obs]
  213. else:
  214. for a_company in self.gen_firms(db_file, headers):
  215. company = Company(
  216. name=a_company[0],
  217. vat_code=a_company[1],
  218. reg_number=a_company[2],
  219. address=a_company[3],
  220. location=a_company[4],
  221. county=a_company[5],
  222. shortname=a_company[6],
  223. adm=a_company[7],
  224. admp=a_company[8],
  225. admcnp=a_company[9],
  226. obs=a_company[10])
  227. yield [company.name, company.vat_code, company.reg_number,
  228. company.address, company.location, company.county,
  229. company.shortname, company.adm, company.admp,
  230. company.admcnp, company.obs]
  231. def get_last_month(self, short_name) -> str:
  232. '''returns last month of a company in format YYYY_MM
  233. :param str short_name is the company shortname'''
  234. short_name = self.winment_path + short_name
  235. month_folders = [f for f in os.listdir(short_name) if re.match(r'[0-9_]+$', f)]
  236. month_folders.reverse()
  237. return month_folders[0]
  238. def get_bank_accounts(self, short_name, db_file='/nbanca.db'):
  239. #.......................................................................
  240. # TO DO: put an all parameter to yield all accounts or
  241. # just one,
  242. # make a named tuple with bank accounts.
  243. #.......................................................................
  244. headers = ['Codbanca', 'Denumire', 'NrCont']
  245. headers2 = ['COD', 'DENUMIRE']
  246. short_name = self.winment_path + short_name
  247. nbanks = self.update_copy(short_name + '/nbanci.db')
  248. file_db = self.update_copy(short_name + db_file)
  249. bank_codes = {}
  250. with Table(file_db) as table, Table(nbanks) as nbanks:
  251. # tables = zip(table, nbanks)
  252. for bank in nbanks:
  253. data = [bank[header] for header in headers2]
  254. bdict = {data[i]: data[i + 1] for i in range(0, len(data), 2)}
  255. bank_codes.update(bdict)
  256. for row in table:
  257. if row.NrCont:
  258. bank_account = [row[header] for header in headers]
  259. bank_account.append(bank_codes[bank_account[0]])
  260. if bank_account[2].startswith(' '):
  261. yield bank_account
  262. def corp_list(self, name=None):
  263. '''returns company list from actual shortnames from winmwnt/data folder
  264. '''
  265. dir_list = [f.name for f in os.scandir(self.winment_path) if f.is_dir() and '@' not in f.name]
  266. if name:
  267. if type(name) is list:
  268. for r in name:
  269. dir_list.remove(r)
  270. else:
  271. dir_list.remove(name)
  272. return dir_list
  273. def verif_corp(self, file_='/firme.db', ban=None):
  274. headers = ['Denumire', 'CF', 'J', 'Adresa', 'Oras', 'Judet', 'Prescurtat', 'Obs']
  275. corplist = self.make_list(self.winment_path + file_, headers) # dbRead.make_list(m_path + '/FIRME.DB', headers)
  276. if ban:
  277. if type(ban) is list:
  278. for r in corplist:
  279. for i in ban:
  280. if i == r[6]:
  281. corplist.remove(r)
  282. else:
  283. for r in corplist:
  284. if r == ban:
  285. corplist.remove(r)
  286. return corplist
  287. def verif_cont(self, file_) -> list:
  288. '''returns an account with its values from the balance
  289. :param file_ is shortname/ncont.db'''
  290. accounts = []
  291. headers = ['Clasa', 'Simbol', 'Denumire', 'SoldID', 'SoldIC', 'PrecedentD', 'PrecedentC', 'CurentD', 'CurentC']
  292. accountlist = self.make_list(self.winment_path + file_, headers) # + lunaCurenta
  293. for elem in accountlist:
  294. account = Account(clasa=elem[0],
  295. simbol=elem[1],
  296. denumire=elem[2],
  297. soldid=elem[3],
  298. soldic=elem[4],
  299. precedentd=elem[5],
  300. precedentc=elem[6],
  301. curentd=elem[7],
  302. curentc=elem[8])
  303. accounts.append(account)
  304. return accountlist
  305. def an_inc(self, account_list, boolind, ind2, ind3):
  306. '''returns the annual turnover in given year
  307. :param int boolind:account class number
  308. :param int ind2, ind3:debit or credit position in balance
  309. (6-rulaj curent debit, 8-rulaj cumulat debit, index starting from 0)'''
  310. tt = 0
  311. for account in account_list:
  312. # n = len(account[boolind]) == 3 and account[boolind] != '...' and int(account[boolind]) > 700 and int(account[boolind]) < 760
  313. n = account[boolind] == 7
  314. can = account[1][:2] != '76'
  315. # print(account[1][:2])
  316. if n and can:
  317. tt += int(account[ind2]) + int(account[ind3])
  318. return tt
  319. def divid(self, account_list, account='457') -> int:
  320. '''returns dividends/year
  321. :param account_list is account from ncont.db'''
  322. div_ = 0
  323. for acc in account_list:
  324. if acc[1][:3] == account:
  325. div_ += acc[8] + acc[6]
  326. return round(div_)
  327. def divid_current(self, account_list, account='457') -> int:
  328. '''returns dividends from current month
  329. :param account_list is account from ncont.db'''
  330. div_ = 0
  331. for acc in account_list:
  332. if acc[1][:3] == account:
  333. div_ += acc[8]
  334. return round(div_)
  335. def divid_intermed(self, account_list, account='463') -> int:
  336. '''returns dividends from current result/year
  337. :param account_list is account from ncont.db'''
  338. div_ = 0
  339. for acc in account_list:
  340. if acc[1][:3] == account:
  341. div_ += acc[7] + acc[5]
  342. return round(div_)
  343. def divid_inter_current(self, account_list, account='463') -> int:
  344. '''returns dividends from current results in the current month
  345. :param account_list is account from ncont.db'''
  346. div_ = 0
  347. for acc in account_list:
  348. if acc[1][:3] == account:
  349. div_ += acc[7]
  350. return round(div_)
  351. def spons(self, account_list, account='658.02') -> int:
  352. '''returns sponsored money/year
  353. :param account_list is account from ncont.db'''
  354. spons_ = 0
  355. for acc in account_list:
  356. if acc[1] == account:
  357. spons_ += acc[8] + acc[6]
  358. return round(spons_)
  359. def result(self, account_list, boolind, ind2, ind3) -> int: # account='121'
  360. '''returns the final result in given year
  361. :param int boolind:account class number
  362. :param int ind2, ind3:debit or credit position in balance
  363. (6-rulaj curent debit, 8-rulaj cumulat debit, index starting from 0)'''
  364. res_minus = res_plus = 0
  365. for r_minus in account_list:
  366. p = r_minus[boolind] == 6
  367. if p:
  368. res_minus += int(r_minus[ind2]) + int(r_minus[ind3])
  369. for r_plus in account_list:
  370. i = r_plus[boolind] == 7
  371. if i:
  372. res_plus += int(r_plus[ind2]) + int(r_plus[ind3])
  373. return res_plus - res_minus
  374. def ins_payable(self, account_list, account='431') -> int:
  375. '''returns insurences payable in current month
  376. :param account_list is account from ncont.db'''
  377. ins = 0
  378. for acc in account_list:
  379. p = acc[1][:3] == account
  380. if p:
  381. ins += acc[8]
  382. return round(ins)
  383. def CAS_payable(self, account_list, accounts=('431.02', '431.05')) -> int:
  384. '''returns CAS payable in current month
  385. :param account_list is account from ncont.db'''
  386. CAS = 0
  387. acc_1, acc_2 = accounts
  388. for acc in account_list:
  389. p = acc[1] == acc_1
  390. d = acc[1] == acc_2
  391. if p: CAS += acc[8]
  392. if d: CAS += acc[8]
  393. return round(CAS)
  394. def CASS_payable(self, account_list, accounts=('431.04', '431.06')) -> int:
  395. '''returns CASS payable in current month
  396. :param account_list is account from ncont.db'''
  397. CASS = 0
  398. acc_1, acc_2 = accounts
  399. for acc in account_list:
  400. p = acc[1] == acc_1
  401. d = acc[1] == acc_2
  402. if p: CASS += acc[8]
  403. if d: CASS += acc[8]
  404. return round(CASS)
  405. def sal_tax_payable(self, account_list, account='431.44') -> int:
  406. '''returns salary tax payable in current month
  407. :param account_list is account from ncont.db'''
  408. tax = 0
  409. for acc in account_list:
  410. p = acc[1] == account
  411. if p:
  412. tax += acc[8]
  413. return round(tax)
  414. def cam_payable(self, account_list, account='436') -> int:
  415. '''returns CAM payable in current month
  416. :param account_list is account from ncont.db'''
  417. cam = 0
  418. for acc in account_list:
  419. p = acc[1][:3] == account
  420. if p:
  421. cam += acc[8]
  422. return round(cam)
  423. def vat_payable(self, account_list, accounts=('442.03', '442.04')) -> int:
  424. '''returns VAT payable in current month
  425. :param account_list is account from ncont.db'''
  426. tt = 0
  427. acc_1, acc_2 = accounts
  428. for acc in account_list:
  429. p = acc[1] == acc_1
  430. d = acc[1] == acc_2
  431. if p:
  432. tt += acc[8]
  433. elif d:
  434. tt -= acc[7] + acc[8]
  435. return round(tt)
  436. def vat_final(self, acc_list, accounts=('442.03', '442.04')) -> int:
  437. '''returns VAT final payable in current month
  438. :param account_list is account from ncont.db'''
  439. tt = 0
  440. acc_1, acc_2 = accounts
  441. for acc in acc_list:
  442. account = Account(clasa=acc[0],
  443. simbol=acc[1],
  444. denumire=acc[2],
  445. soldid=acc[3],
  446. soldic=acc[4],
  447. precedentd=acc[5],
  448. precedentc=acc[6],
  449. curentd=acc[7],
  450. curentc=acc[8])
  451. payable = account.simbol == acc_1
  452. deductible = account.simbol == acc_2
  453. if payable:
  454. tt += account.soldf('c')
  455. elif deductible:
  456. tt -= account.soldf('d')
  457. return round(tt)
  458. def tax_payable(self, account_list, account='441') -> int:
  459. '''returns income TAX payable in current month
  460. :param account_list is account from ncont.db'''
  461. tax = 0
  462. for acc in account_list:
  463. p = acc[1][:3] == account
  464. if p:
  465. tax += acc[8]
  466. return round(tax)
  467. def div_tax_payable(self, acc_list, accounts='446.07') -> int:
  468. '''returns dividend TAX payable in current month
  469. :param account_list is account from ncont.db'''
  470. tt = 0
  471. # acc_1, acc_2 = accounts
  472. for acc in acc_list:
  473. account = Account(clasa=acc[0],
  474. simbol=acc[1],
  475. denumire=acc[2],
  476. soldid=acc[3],
  477. soldic=acc[4],
  478. precedentd=acc[5],
  479. precedentc=acc[6],
  480. curentd=acc[7],
  481. curentc=acc[8])
  482. payable = account.simbol == accounts
  483. # deductible = account.simbol == acc_2
  484. if payable:
  485. tt += account.curentc
  486. # elif deductible:
  487. # tt -= account.soldf('d')
  488. return round(tt)
  489. def advance_final(self, acc_list, accounts='542') -> int:
  490. '''returns final dvances/year
  491. :param account_list is account from ncont.db'''
  492. tt = 0
  493. # acc_1, acc_2 = accounts
  494. for acc in acc_list:
  495. account = Account(clasa=acc[0],
  496. simbol=acc[1],
  497. denumire=acc[2],
  498. soldid=acc[3],
  499. soldic=acc[4],
  500. precedentd=acc[5],
  501. precedentc=acc[6],
  502. curentd=acc[7],
  503. curentc=acc[8])
  504. payable = account.simbol[:3] == accounts
  505. # deductible = account.simbol == acc_2
  506. if payable:
  507. tt += account.soldf('d')
  508. # elif deductible:
  509. # tt -= account.soldf('d')
  510. return round(tt)
  511. def deb_div(self, acc_list, accounts='461') -> int:
  512. '''returns advances transfered to deb. diversi/year
  513. :param account_list is account from ncont.db'''
  514. tt = 0
  515. # acc_1, acc_2 = accounts
  516. for acc in acc_list:
  517. account = Account(clasa=acc[0],
  518. simbol=acc[1],
  519. denumire=acc[2],
  520. soldid=acc[3],
  521. soldic=acc[4],
  522. precedentd=acc[5],
  523. precedentc=acc[6],
  524. curentd=acc[7],
  525. curentc=acc[8])
  526. payable = account.simbol[:3] == accounts
  527. # deductible = account.simbol == acc_2
  528. if payable:
  529. tt += account.soldf('d')
  530. # elif deductible:
  531. # tt -= account.soldf('d')
  532. return round(tt)
  533. def credit_final(self, acc_list, accounts='455') -> int:
  534. '''returns credited ammount/year
  535. :param account_list is account from ncont.db'''
  536. tt = 0
  537. # acc_1, acc_2 = accounts
  538. for acc in acc_list:
  539. account = Account(clasa=acc[0],
  540. simbol=acc[1],
  541. denumire=acc[2],
  542. soldid=acc[3],
  543. soldic=acc[4],
  544. precedentd=acc[5],
  545. precedentc=acc[6],
  546. curentd=acc[7],
  547. curentc=acc[8])
  548. payable = account.simbol[:3] == accounts
  549. # deductible = account.simbol == acc_2
  550. if payable:
  551. tt += account.soldf('d')
  552. # elif deductible:
  553. # tt -= account.soldf('d')
  554. return round(tt)
  555. if __name__ == '__main__':
  556. mentor = WinMentor()
  557. # accounts = list(mentor.get_bank_accounts('WEBS'))
  558. # account_num = [n for n in accounts[1] if n.startswith(' ')]
  559. for account in mentor.get_bank_accounts('WEBS'):
  560. # if account[2].startswith(' '):
  561. print(account)