dbread.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  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. return empl_all
  133. def gen_firms(self, db_file, headers) -> list:
  134. '''generates company list from firme.db file
  135. :param db_file is firme.db from winment/data folder'''
  136. file_db = self.update_copy(self.winment_path + db_file)
  137. with Table(file_db) as table:
  138. for row in table:
  139. yield [row[header] for header in headers]
  140. def firmlist(self, headers, db_file='/firme.db', ban=None) -> list:
  141. '''returns company list from firme.db file
  142. :param db_file is firme.db from winment/data folder
  143. :param list headers is the fields from firme.db file
  144. :param list|str ban companies excluded from list'''
  145. comp_list = []
  146. for a_company in self.gen_firms(db_file, headers):
  147. company = Company(
  148. name=a_company[0],
  149. vat_code=a_company[1],
  150. reg_number=a_company[2],
  151. address=a_company[3],
  152. location=a_company[4],
  153. county=a_company[5],
  154. shortname=a_company[6],
  155. adm=a_company[7],
  156. admp=a_company[8],
  157. admcnp=a_company[9],
  158. obs=a_company[10])
  159. comp_list.append(company)
  160. if ban:
  161. if type(ban) is list:
  162. for r in comp_list:
  163. for company_shortname in ban:
  164. if company_shortname == r.shortname:
  165. comp_list.remove(r)
  166. else:
  167. for r in comp_list:
  168. if r == ban:
  169. comp_list.remove(r)
  170. return comp_list
  171. def filtered_firmlist(self, headers, db_file='/firme.db', ban=None) -> list:
  172. '''generates company list from firme.db file
  173. :param db_file is firme.db from winment/data folder
  174. :param list headers is the fields from firme.db file
  175. :param list|str ban companies excluded from list'''
  176. if ban:
  177. if type(ban) is list:
  178. for a_company in self.gen_firms(db_file, headers):
  179. company = Company(
  180. name=a_company[0],
  181. vat_code=a_company[1],
  182. reg_number=a_company[2],
  183. address=a_company[3],
  184. location=a_company[4],
  185. county=a_company[5],
  186. shortname=a_company[6],
  187. adm=a_company[7],
  188. admp=a_company[8],
  189. admcnp=a_company[9],
  190. obs=a_company[10])
  191. if a_company[6] not in ban:
  192. yield [company.name, company.vat_code, company.reg_number,
  193. company.address, company.location, company.county,
  194. company.shortname, company.adm, company.admp,
  195. company.admcnp, company.obs]
  196. else:
  197. for a_company in self.gen_firms(db_file, headers):
  198. company = Company(
  199. name=a_company[0],
  200. vat_code=a_company[1],
  201. reg_number=a_company[2],
  202. address=a_company[3],
  203. location=a_company[4],
  204. county=a_company[5],
  205. shortname=a_company[6],
  206. adm=a_company[7],
  207. admp=a_company[8],
  208. admcnp=a_company[9],
  209. obs=a_company[10])
  210. yield [company.name, company.vat_code, company.reg_number,
  211. company.address, company.location, company.county,
  212. company.shortname, company.adm, company.admp,
  213. company.admcnp, company.obs]
  214. def get_last_month(self, short_name) -> str:
  215. '''returns last month of a company in format YYYY_MM
  216. :param str short_name is the company shortname'''
  217. short_name = self.winment_path + short_name
  218. month_folders = [f for f in os.listdir(short_name) if re.match(r'[0-9_]+$', f)]
  219. month_folders.reverse()
  220. return month_folders[0]
  221. def get_bank_accounts(self, short_name, db_file='/nbanca.db'):
  222. #.......................................................................
  223. # TO DO: put an all_ parameter to yield all_ accounts or
  224. # just one,
  225. # make a named tuple with bank accounts.
  226. #.......................................................................
  227. headers = ['Codbanca', 'Denumire', 'NrCont']
  228. headers2 = ['COD', 'DENUMIRE']
  229. short_name = self.winment_path + short_name
  230. nbanks = self.update_copy(short_name + '/nbanci.db')
  231. file_db = self.update_copy(short_name + db_file)
  232. bank_codes = {}
  233. with Table(file_db) as table, Table(nbanks) as nbanks:
  234. # tables = zip(table, nbanks)
  235. for bank in nbanks:
  236. data = [bank[header] for header in headers2]
  237. bdict = {data[i]: data[i + 1] for i in range(0, len(data), 2)}
  238. bank_codes.update(bdict)
  239. for row in table:
  240. if row.NrCont:
  241. bank_account = [row[header] for header in headers]
  242. bank_account.append(bank_codes[bank_account[0]])
  243. if bank_account[2].startswith(' '):
  244. yield bank_account
  245. def get_oblig(self, short_name, db_file='/ObligPI.DB'):
  246. headers = ['Part', 'TipDoc', 'Doc', 'NrDoc', 'DataDoc', 'Valoare', 'Rest']
  247. short_name = self.winment_path + short_name
  248. # nbanks = self.update_copy(short_name + '/nbanci.db')
  249. oblig_db = self.update_copy(short_name + db_file)
  250. with Table(oblig_db) as table: # , Table(nbanks) as nbanks
  251. all_ = []
  252. parts = []
  253. tips = []
  254. docs = []
  255. nrs = []
  256. dates = []
  257. values = []
  258. rests = []
  259. for row in table:
  260. if row.TipDoc == 1:
  261. parts.append(row.Part)
  262. all_.append(parts)
  263. tips.append(row.TipDoc)
  264. all_.append(tips)
  265. docs.append(row.Doc)
  266. all_.append(docs)
  267. nrs.append(row.NrDoc)
  268. all_.append(nrs)
  269. dates.append(row.DataDoc)
  270. all_.append(dates)
  271. values.append(row.Valoare)
  272. all_.append(values)
  273. rests.append(row.Rest)
  274. all_.append(rests)
  275. df_dict = dict(zip(headers, all_))
  276. return df_dict
  277. def corp_list(self, name=None):
  278. '''returns company list from actual shortnames from winmwnt/data folder
  279. '''
  280. dir_list = [f.name for f in os.scandir(self.winment_path) if f.is_dir() and '@' not in f.name]
  281. if name:
  282. if type(name) is list:
  283. for r in name:
  284. dir_list.remove(r)
  285. else:
  286. dir_list.remove(name)
  287. return dir_list
  288. def verif_corp(self, file_='/firme.db', ban=None):
  289. headers = ['Denumire', 'CF', 'J', 'Adresa', 'Oras', 'Judet', 'Prescurtat', 'Obs']
  290. corplist = self.make_list(self.winment_path + file_, headers) # dbRead.make_list(m_path + '/FIRME.DB', headers)
  291. if ban:
  292. if type(ban) is list:
  293. for r in corplist:
  294. for i in ban:
  295. if i == r[6]:
  296. corplist.remove(r)
  297. else:
  298. for r in corplist:
  299. if r == ban:
  300. corplist.remove(r)
  301. return corplist
  302. def verif_cont(self, file_) -> list:
  303. '''returns an account with its values from the balance
  304. :param file_ is shortname/ncont.db'''
  305. accounts = []
  306. headers = ['Clasa', 'Simbol', 'Denumire', 'SoldID', 'SoldIC', 'PrecedentD', 'PrecedentC', 'CurentD', 'CurentC']
  307. accountlist = self.make_list(self.winment_path + file_, headers) # + lunaCurenta
  308. for elem in accountlist:
  309. account = Account(clasa=elem[0],
  310. simbol=elem[1],
  311. denumire=elem[2],
  312. soldid=elem[3],
  313. soldic=elem[4],
  314. precedentd=elem[5],
  315. precedentc=elem[6],
  316. curentd=elem[7],
  317. curentc=elem[8])
  318. accounts.append(account)
  319. return accountlist
  320. def an_inc(self, account_list, boolind, ind2, ind3):
  321. '''returns the annual turnover in given year
  322. :param int boolind:account class number
  323. :param int ind2, ind3:debit or credit position in balance
  324. (6-rulaj curent debit, 8-rulaj cumulat debit, index starting from 0)'''
  325. tt = 0
  326. for account in account_list:
  327. # n = len(account[boolind]) == 3 and account[boolind] != '...' and int(account[boolind]) > 700 and int(account[boolind]) < 760
  328. n = account[boolind] == 7
  329. can = account[1][:2] != '76'
  330. # print(account[1][:2])
  331. if n and can:
  332. tt += int(account[ind2]) + int(account[ind3])
  333. return tt
  334. def divid(self, account_list, account='457') -> int:
  335. '''returns dividends/year
  336. :param account_list is account from ncont.db'''
  337. div_ = 0
  338. for acc in account_list:
  339. if acc[1][:3] == account:
  340. div_ += acc[8] + acc[6]
  341. return round(div_)
  342. def divid_current(self, account_list, account='457') -> int:
  343. '''returns dividends from current month
  344. :param account_list is account from ncont.db'''
  345. div_ = 0
  346. for acc in account_list:
  347. if acc[1][:3] == account:
  348. div_ += acc[8]
  349. return round(div_)
  350. def divid_intermed(self, account_list, account='463') -> int:
  351. '''returns dividends from current result/year
  352. :param account_list is account from ncont.db'''
  353. div_ = 0
  354. for acc in account_list:
  355. if acc[1][:3] == account:
  356. div_ += acc[7] + acc[5]
  357. return round(div_)
  358. def divid_inter_current(self, account_list, account='463') -> int:
  359. '''returns dividends from current results in the current month
  360. :param account_list is account from ncont.db'''
  361. div_ = 0
  362. for acc in account_list:
  363. if acc[1][:3] == account:
  364. div_ += acc[7]
  365. return round(div_)
  366. def spons(self, account_list, account='658.02') -> int:
  367. '''returns sponsored money/year
  368. :param account_list is account from ncont.db'''
  369. spons_ = 0
  370. for acc in account_list:
  371. if acc[1] == account:
  372. spons_ += acc[8] + acc[6]
  373. return round(spons_)
  374. def result(self, account_list, boolind, ind2, ind3) -> int: # account='121'
  375. '''returns the final result in given year
  376. :param int boolind:account class number
  377. :param int ind2, ind3:debit or credit position in balance
  378. (6-rulaj curent debit, 8-rulaj cumulat debit, index starting from 0)'''
  379. res_minus = res_plus = 0
  380. for r_minus in account_list:
  381. p = r_minus[boolind] == 6
  382. if p:
  383. res_minus += int(r_minus[ind2]) + int(r_minus[ind3])
  384. for r_plus in account_list:
  385. i = r_plus[boolind] == 7
  386. if i:
  387. res_plus += int(r_plus[ind2]) + int(r_plus[ind3])
  388. return res_plus - res_minus
  389. def ins_payable(self, account_list, account='431') -> int:
  390. '''returns insurences payable in current month
  391. :param account_list is account from ncont.db'''
  392. ins = 0
  393. for acc in account_list:
  394. p = acc[1][:3] == account
  395. if p:
  396. ins += acc[8]
  397. return round(ins)
  398. def CAS_payable(self, account_list, accounts=('431.02', '431.05')) -> int:
  399. '''returns CAS payable in current month
  400. :param account_list is account from ncont.db'''
  401. CAS = 0
  402. acc_1, acc_2 = accounts
  403. for acc in account_list:
  404. p = acc[1] == acc_1
  405. d = acc[1] == acc_2
  406. if p: CAS += acc[8]
  407. if d: CAS += acc[8]
  408. return round(CAS)
  409. def CASS_payable(self, account_list, accounts=('431.04', '431.06')) -> int:
  410. '''returns CASS payable in current month
  411. :param account_list is account from ncont.db'''
  412. CASS = 0
  413. acc_1, acc_2 = accounts
  414. for acc in account_list:
  415. p = acc[1] == acc_1
  416. d = acc[1] == acc_2
  417. if p: CASS += acc[8]
  418. if d: CASS += acc[8]
  419. return round(CASS)
  420. def sal_tax_payable(self, account_list, account='431.44') -> int:
  421. '''returns salary tax payable in current month
  422. :param account_list is account from ncont.db'''
  423. tax = 0
  424. for acc in account_list:
  425. p = acc[1] == account
  426. if p:
  427. tax += acc[8]
  428. return round(tax)
  429. def cam_payable(self, account_list, account='436') -> int:
  430. '''returns CAM payable in current month
  431. :param account_list is account from ncont.db'''
  432. cam = 0
  433. for acc in account_list:
  434. p = acc[1][:3] == account
  435. if p:
  436. cam += acc[8]
  437. return round(cam)
  438. def vat_payable(self, account_list, accounts=('442.03', '442.04')) -> int:
  439. '''returns VAT payable in current month
  440. :param account_list is account from ncont.db'''
  441. tt = 0
  442. acc_1, acc_2 = accounts
  443. for acc in account_list:
  444. p = acc[1] == acc_1
  445. d = acc[1] == acc_2
  446. if p:
  447. tt += acc[8]
  448. elif d:
  449. tt -= acc[7] + acc[8]
  450. return round(tt)
  451. def vat_final(self, acc_list, accounts=('442.03', '442.04')) -> int:
  452. '''returns VAT final payable in current month
  453. :param account_list is account from ncont.db'''
  454. tt = 0
  455. acc_1, acc_2 = accounts
  456. for acc in acc_list:
  457. account = Account(clasa=acc[0],
  458. simbol=acc[1],
  459. denumire=acc[2],
  460. soldid=acc[3],
  461. soldic=acc[4],
  462. precedentd=acc[5],
  463. precedentc=acc[6],
  464. curentd=acc[7],
  465. curentc=acc[8])
  466. payable = account.simbol == acc_1
  467. deductible = account.simbol == acc_2
  468. if payable:
  469. tt += account.soldf('c')
  470. elif deductible:
  471. tt -= account.soldf('d')
  472. return round(tt)
  473. def tax_payable(self, account_list, account='441') -> int:
  474. '''returns income TAX payable in current month
  475. :param account_list is account from ncont.db'''
  476. tax = 0
  477. for acc in account_list:
  478. p = acc[1][:3] == account
  479. if p:
  480. tax += acc[8]
  481. return round(tax)
  482. def div_tax_payable(self, acc_list, accounts='446.07') -> int:
  483. '''returns dividend TAX payable in current month
  484. :param account_list is account from ncont.db'''
  485. tt = 0
  486. # acc_1, acc_2 = accounts
  487. for acc in acc_list:
  488. account = Account(clasa=acc[0],
  489. simbol=acc[1],
  490. denumire=acc[2],
  491. soldid=acc[3],
  492. soldic=acc[4],
  493. precedentd=acc[5],
  494. precedentc=acc[6],
  495. curentd=acc[7],
  496. curentc=acc[8])
  497. payable = account.simbol == accounts
  498. # deductible = account.simbol == acc_2
  499. if payable:
  500. tt += account.curentc
  501. # elif deductible:
  502. # tt -= account.soldf('d')
  503. return round(tt)
  504. def advance_final(self, acc_list, accounts='542') -> int:
  505. '''returns final dvances/year
  506. :param account_list is account from ncont.db'''
  507. tt = 0
  508. # acc_1, acc_2 = accounts
  509. for acc in acc_list:
  510. account = Account(clasa=acc[0],
  511. simbol=acc[1],
  512. denumire=acc[2],
  513. soldid=acc[3],
  514. soldic=acc[4],
  515. precedentd=acc[5],
  516. precedentc=acc[6],
  517. curentd=acc[7],
  518. curentc=acc[8])
  519. payable = account.simbol[:3] == accounts
  520. # deductible = account.simbol == acc_2
  521. if payable:
  522. tt += account.soldf('d')
  523. # elif deductible:
  524. # tt -= account.soldf('d')
  525. return round(tt)
  526. def deb_div(self, acc_list, accounts='461') -> int:
  527. '''returns advances transfered to deb. diversi/year
  528. :param account_list is account from ncont.db'''
  529. tt = 0
  530. # acc_1, acc_2 = accounts
  531. for acc in acc_list:
  532. account = Account(clasa=acc[0],
  533. simbol=acc[1],
  534. denumire=acc[2],
  535. soldid=acc[3],
  536. soldic=acc[4],
  537. precedentd=acc[5],
  538. precedentc=acc[6],
  539. curentd=acc[7],
  540. curentc=acc[8])
  541. payable = account.simbol[:3] == accounts
  542. # deductible = account.simbol == acc_2
  543. if payable:
  544. tt += account.soldf('d')
  545. # elif deductible:
  546. # tt -= account.soldf('d')
  547. return round(tt)
  548. def credit_final(self, acc_list, accounts='455') -> int:
  549. '''returns credited ammount/year
  550. :param account_list is account from ncont.db'''
  551. tt = 0
  552. # acc_1, acc_2 = accounts
  553. for acc in acc_list:
  554. account = Account(clasa=acc[0],
  555. simbol=acc[1],
  556. denumire=acc[2],
  557. soldid=acc[3],
  558. soldic=acc[4],
  559. precedentd=acc[5],
  560. precedentc=acc[6],
  561. curentd=acc[7],
  562. curentc=acc[8])
  563. payable = account.simbol[:3] == accounts
  564. # deductible = account.simbol == acc_2
  565. if payable:
  566. tt += account.soldf('d')
  567. # elif deductible:
  568. # tt -= account.soldf('d')
  569. return round(tt)
  570. if __name__ == '__main__':
  571. mentor = WinMentor()
  572. # accounts = list(mentor.get_bank_accounts('WEBS'))
  573. # account_num = [n for n in accounts[1] if n.startswith(' ')]
  574. for account in mentor.get_bank_accounts('WEBS'):
  575. # if account[2].startswith(' '):
  576. print(account)