hledger.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import datetime
  4. import settings
  5. import MySQLdb as mdb
  6. import sys
  7. import os
  8. import codecs
  9. MYSQL_QUERIES = {
  10. # "bank": "SELECT DISTINCT b.rowid as b_rowid, ba.ref as ba_ref, ba.label as ba_label, ba.account_number as ba_account_number, b.datev as b_datev, b.dateo as b_dateo, b.label as b_label, b.num_chq as b_num_chq, -b.amount as _b_amount, b.amount as b_amount, b.num_releve as b_num_releve, b.datec as b_datec, bu.url_id as bu_url_id, s.nom as s_nom, s.code_compta as s_code_compta, s.code_compta_fournisseur as s_code_compta_fournisseur, bca.label as bca_label, bca.rowid as bca_rowid, bcl.lineid as bcl_lineid FROM (llx_bank_account as ba, llx_bank as b) LEFT JOIN llx_bank_url as bu ON (bu.fk_bank = b.rowid AND bu.type = 'company') LEFT JOIN llx_societe as s ON bu.url_id = s.rowid LEFT JOIN llx_bank_class as bcl ON bcl.lineid = b.rowid LEFT JOIN llx_bank_categ as bca ON bca.rowid = bcl.fk_categ WHERE ba.rowid = b.fk_account AND ba.entity = 1 and b.num_releve <> '' ORDER BY b.datev, b.num_releve",
  11. "bank": "SELECT DISTINCT b.rowid as b_rowid, ba.ref as ba_ref, ba.label as ba_label, ba.account_number as ba_account_number, b.datev as b_datev, b.dateo as b_dateo, b.label as b_label, b.num_chq as b_num_chq, -b.amount as _b_amount, b.amount as b_amount, b.num_releve as b_num_releve, b.datec as b_datec, bu.url_id as bu_url_id, s.nom as s_nom, s.code_compta as s_code_compta, s.code_compta_fournisseur as s_code_compta_fournisseur, bca.label as bca_label, bca.rowid as bca_rowid, bcl.lineid as bcl_lineid, ccs.code as ccs_code, ccs.libelle as ccs_label FROM (llx_bank_account as ba, llx_bank as b) LEFT JOIN llx_bank_url as bu ON (bu.fk_bank = b.rowid AND bu.type = 'company') LEFT JOIN llx_societe as s ON bu.url_id = s.rowid LEFT JOIN llx_bank_class as bcl ON bcl.lineid = b.rowid LEFT JOIN llx_bank_categ as bca ON bca.rowid = bcl.fk_categ LEFT JOIN llx_paiementcharge as p ON p.fk_bank = b.rowid LEFT JOIN llx_chargesociales as cs ON cs.rowid = p.fk_charge LEFT JOIN llx_c_chargesociales as ccs ON cs.fk_type = ccs.id WHERE ba.rowid = b.fk_account AND ba.entity = 1 and b.num_releve <> '' ORDER BY b.datev, b.num_releve;",
  12. "sells": "SELECT DISTINCT s.rowid as s_rowid, s.nom as s_nom, s.address as s_address, s.zip as s_zip, s.town as s_town, c.code as c_code, s.phone as s_phone, s.siren as s_siren, s.siret as s_siret, s.ape as s_ape, s.idprof4 as s_idprof4, s.code_compta as s_code_compta, s.code_compta_fournisseur as s_code_compta_fournisseur, s.tva_intra as s_tva_intra, f.rowid as f_rowid, f.facnumber as f_facnumber, f.datec as f_datec, f.datef as f_datef, f.date_lim_reglement as f_date_lim_reglement, f.total as f_total, f.total_ttc as f_total_ttc, f.tva as f_tva, f.paye as f_paye, f.fk_statut as f_fk_statut, f.note_private as f_note_private, f.note_public as f_note_public, fd.rowid as fd_rowid, fd.label as fd_label, fd.description as fd_description, fd.subprice as fd_subprice, fd.tva_tx as fd_tva_tx, fd.qty as fd_qty, fd.total_ht as fd_total_ht, fd.total_tva as fd_total_tva, fd.total_ttc as fd_total_ttc, fd.date_start as fd_date_start, fd.date_end as fd_date_end, fd.special_code as fd_special_code, fd.product_type as fd_product_type, fd.fk_product as fd_fk_product, p.ref as p_ref, p.label as p_label, p.accountancy_code_sell as p_accountancy_code_sell, a.account_number as a_account_number FROM llx_societe as s LEFT JOIN llx_c_pays as c on s.fk_pays = c.rowid, llx_facture as f LEFT JOIN llx_facture_extrafields as extra ON f.rowid = extra.fk_object , llx_facturedet as fd LEFT JOIN llx_product as p on (fd.fk_product = p.rowid) LEFT JOIN llx_accountingaccount as a ON fd.fk_code_ventilation = a.rowid WHERE f.fk_soc = s.rowid AND f.rowid = fd.fk_facture AND f.entity = 1",
  13. "suppliers": "SELECT DISTINCT s.rowid as s_rowid, s.nom as s_nom, s.address as s_address, s.zip as s_zip, s.town as s_town, s.code_compta_fournisseur as s_code_supplier, c.code as c_code, s.phone as s_phone, s.siren as s_siren, s.siret as s_siret, s.ape as s_ape, s.idprof4 as s_idprof4, s.idprof5 as s_idprof5, s.idprof6 as s_idprof6, s.tva_intra as s_tva_intra, f.rowid as f_rowid, f.ref as f_ref, f.ref_supplier as f_ref_supplier, f.datec as f_datec, f.datef as f_datef, f.total_ht as f_total_ht, f.total_ttc as f_total_ttc, f.total_tva as f_total_tva, f.paye as f_paye, f.fk_statut as f_fk_statut, f.note_public as f_note_public, fd.rowid as fd_rowid, fd.description as fd_description, fd.tva_tx as fd_tva_tx, fd.qty as fd_qty, fd.remise_percent as fd_remise_percent, fd.total_ht as fd_total_ht, fd.total_ttc as fd_total_ttc, fd.tva as fd_tva, fd.product_type as fd_product_type, fd.fk_product as fd_fk_product, p.ref as p_ref, p.label as p_label, p.accountancy_code_buy as p_accountancy_code_buy, a.account_number as a_account_number FROM llx_societe as s LEFT JOIN llx_c_pays as c ON s.fk_pays = c.rowid, llx_facture_fourn as f LEFT JOIN llx_facture_fourn_extrafields as extra ON f.rowid = extra.fk_object , llx_facture_fourn_det as fd LEFT JOIN llx_product as p on (fd.fk_product = p.rowid) LEFT JOIN llx_accountingaccount as a ON fd.fk_code_ventilation = a.rowid WHERE f.fk_soc = s.rowid AND f.rowid = fd.fk_facture_fourn AND f.entity = 1",
  14. "social": "SELECT DISTINCT cc.libelle as cc_libelle, c.rowid as c_rowid, c.libelle as c_libelle, c.date_ech as c_date_ech, c.periode as c_periode, c.amount as c_amount, c.paye as c_paye, p.rowid as p_rowid, p.datep as p_datep, p.amount as p_amount, p.num_paiement as p_num_paiement, cc.accountancy_code as cc_acc_code, cc.code as cc_code FROM llx_c_chargesociales as cc, llx_chargesociales as c LEFT JOIN llx_paiementcharge as p ON p.fk_charge = c.rowid WHERE c.fk_type = cc.id AND c.entity = 1",
  15. }
  16. class Entry(object):
  17. accounting_years = settings.get('ACCOUNTING_YEARS')
  18. pc_default_tiers = settings.get('PC_REFS')['default_tiers']
  19. pc_default_client = settings.get('PC_REFS')['default_client']
  20. pc_default_supplier = settings.get('PC_REFS')['default_supplier']
  21. pc_default_produit = settings.get('PC_REFS')['default_produit']
  22. pc_default_charge = settings.get('PC_REFS')['default_charge']
  23. pc_default_bank = settings.get('PC_REFS')['default_bank']
  24. def __init__(self, cells):
  25. self.cells = cells
  26. for key in cells:
  27. value = self.cells[key]
  28. if value is None:
  29. self.cells[key] = ""
  30. elif isinstance(value, str):
  31. self.cells[key] = value.decode('iso8859-1')
  32. def get_accounting_year(self, field):
  33. value = self.cells[field]
  34. for (year, dbegin, dend) in Entry.accounting_years:
  35. if value >= dbegin and value <= dend:
  36. return year
  37. return str(value.year)
  38. class BankEntry(Entry):
  39. # ['ba_ref',
  40. # 's_nom',
  41. # 'b_rowid',
  42. # 'b_datev',
  43. # 'b_num_releve',
  44. # 'bu_url_id',
  45. # 'ba_label',
  46. # 's_code_compta',
  47. # 'b_label',
  48. # 'b_dateo',
  49. # '_b_amount',
  50. # 'b_num_chq',
  51. # 'b_datec',
  52. # 'b_amount',
  53. # 's_code_compta_fournisseur']
  54. @staticmethod
  55. def clean(row):
  56. return True
  57. #return row['b_num_releve'] != ""
  58. def addEntry(self, entry):
  59. pass
  60. def get_year(self):
  61. return self.get_accounting_year('b_datev')
  62. def getMissingPC(self):
  63. pc_missing = []
  64. if self.get_s_code() == "":
  65. pc_missing.append("tiers: %s" % (self.cells['s_nom']))
  66. if self.cells['ba_account_number'] == "":
  67. pc_missing.append("banque: %s" % (self.cells['ba_ref']))
  68. return pc_missing
  69. def get_s_code(self):
  70. supplier_or_client_by_bca_rowid = {
  71. 1: 'client',
  72. 2: 'client',
  73. 3: 'supplier',
  74. 4: 'supplier',
  75. 5: 'client',
  76. '': None
  77. }
  78. #entry_type = entry_type_by_bca_rowid[self.cells['bca_rowid']]
  79. entry_type = None
  80. if entry_type is None:
  81. if self.cells['b_label'] == "(SupplierInvoicePayment)":
  82. entry_type = "supplier"
  83. elif self.cells['b_label'] == "(CustomerInvoicePayment)":
  84. entry_type = "client"
  85. elif self.cells['b_label'] == "Règlement client":
  86. entry_type = "client"
  87. elif self.cells['b_label'] == "Solde initial":
  88. entry_type = "custom"
  89. #elif self.cells['b_label'] == "Souscription part sociale":
  90. # entry_type = "custom"
  91. elif self.cells['b_label'] == "(SocialContributionPayment)":
  92. entry_type = "social"
  93. else:
  94. entry_type = "custom"
  95. third_code = ""
  96. if entry_type == "client":
  97. third_code = self.cells['s_code_compta']
  98. if third_code == "":
  99. third_code = self.pc_default_client
  100. print "WARNING: Utilisation du tiers par défaut"
  101. print self.cells
  102. elif entry_type == "supplier":
  103. third_code = self.cells['s_code_compta_fournisseur']
  104. if third_code == "":
  105. third_code = self.pc_default_supplier
  106. elif entry_type == "social":
  107. third_code = SocialEntry.get_third_code(self.cells['ccs_code'])
  108. elif entry_type == "custom":
  109. third_code = self.get_custom_code()
  110. if third_code == "":
  111. print "WARNING: Utilisation du tiers par défaut"
  112. print self.cells
  113. third_code = self.pc_default_tiers
  114. else:
  115. print "ERROR: entry_type must be defined"
  116. return third_code
  117. def get_custom_code(self):
  118. fn = settings.get('PC_REFS')['fn_custom_code']
  119. return fn(self.cells)
  120. def get_ledger(self):
  121. s = ""
  122. s += "%(date)s %(description)s\n" % {
  123. 'date': self.cells['b_datev'].strftime("%Y/%m/%d"),
  124. 'description': self.cells['s_nom'] + " - " + self.cells['b_label']
  125. }
  126. amount = self.cells['b_amount']
  127. third_code = self.get_s_code()
  128. s += " %(account)s \t %(amount)s\n" % {
  129. 'account': settings.get_ledger_account(third_code),
  130. 'amount': amount
  131. }
  132. ba_code = self.cells['ba_account_number']
  133. if ba_code == "":
  134. ba_code = self.pc_default_bank
  135. s += " %(account)s \t %(amount)s\n" % {
  136. 'account': settings.get_ledger_account(ba_code),
  137. 'amount': -amount
  138. }
  139. return s
  140. class EntryCollection(object):
  141. def __init__(self, index, entry_class):
  142. self.collection = {}
  143. self.index = index
  144. self.entry_class = entry_class
  145. def addCollectionEntry(self, row):
  146. id = row[self.index]
  147. if id not in self.collection:
  148. self.collection[id] = self.entry_class(row)
  149. self.collection[id].addEntry(row)
  150. def get_collection(self):
  151. return self.collection.values()
  152. def get_by_year(self):
  153. by_year = {}
  154. for item in self.get_collection():
  155. item_year = item.get_year()
  156. if item_year not in by_year:
  157. by_year[item_year] = []
  158. by_year[item_year].append(item)
  159. return by_year
  160. def check_pc(self):
  161. pc_missing = set()
  162. for item in self.get_collection():
  163. pc_missing.update(item.getMissingPC())
  164. return pc_missing
  165. class Sell(Entry):
  166. @staticmethod
  167. def clean(row):
  168. return True
  169. def __init__(self, row):
  170. super(Sell, self).__init__(row)
  171. self.entries = {}
  172. def addEntry(self, row):
  173. id = row['fd_rowid']
  174. self.entries[id] = SellEntry(row)
  175. def get_year(self):
  176. return self.get_accounting_year('f_datef')
  177. def getMissingPC(self):
  178. pc_missing = []
  179. if self.cells['s_code_compta'] == "":
  180. pc_missing.append("tiers: %s %s" % (self.cells['s_nom'], self.cells['s_ape']))
  181. for entry in self.entries.values():
  182. if entry.get_product_account_code() == self.pc_default_produit:
  183. if self.cells['fd_description'] != "":
  184. description = self.cells['fd_description'].splitlines()[0]
  185. else:
  186. description = self.cells['fd_description']
  187. pc_missing.append("produit: %s %s" % (self.cells['s_nom'], description))
  188. return pc_missing
  189. def check(self):
  190. total_ttc = self.cells['f_total_ttc']
  191. total_tva = self.cells['f_tva']
  192. total_ht = self.cells['f_total']
  193. for entry in self.entries.values():
  194. total_ttc -= entry.cells['fd_total_ttc']
  195. total_tva -= entry.cells['fd_total_tva']
  196. total_ht -= entry.cells['fd_total_ht']
  197. if total_ttc > 1e-10:
  198. print "Erreur dans l'écriture %s: total ttc = %s" % (self.cells['f_facnumber'],total_ttc)
  199. if total_ht > 1e-10:
  200. print "Erreur dans l'écriture %s: total ht = %s" % (self.cells['f_facnumber'],total_ht)
  201. if total_tva > 1e-10:
  202. print "Erreur dans l'écriture %s: total tva = %s" % (self.cells['f_facnumber'],total_tva)
  203. def get_ledger(self):
  204. self.check()
  205. s = ""
  206. s += "%(date)s %(description)s\n" % {
  207. 'date': self.cells['f_datef'].strftime("%Y/%m/%d"),
  208. 'description': self.cells['f_facnumber'] + " - " + self.cells['s_nom'],
  209. }
  210. s_code = self.cells['s_code_compta']
  211. if s_code == "":
  212. s_code = self.pc_default_client
  213. s += " %(compte_tiers)s %(amount_ttc)s\n" % {
  214. 'compte_tiers': settings.get_ledger_account(s_code),
  215. 'amount_ttc': -self.cells['f_total_ttc'],
  216. }
  217. if float(self.cells['f_tva']) != 0:
  218. tva_account = settings.get('PC_REFS')['tva_collecte']
  219. s += " %(compte_tva_collecte)s %(amount_tva)s\n" % {
  220. 'compte_tva_collecte': settings.get_ledger_account(tva_account),
  221. 'amount_tva': self.cells['f_tva'],
  222. }
  223. for entry in self.entries.values():
  224. p_code = entry.get_product_account_code()
  225. s += " %(compte_produit)s %(amount_ht)s\n" % {
  226. 'compte_produit': settings.get_ledger_account(p_code),
  227. 'amount_ht': entry.cells['fd_total_ht']
  228. }
  229. return s
  230. class SellEntry(Entry):
  231. # ['f_date_lim_reglement',
  232. # 's_phone',
  233. # 'f_total_ttc',
  234. # 'c_code',
  235. # 's_zip',
  236. # 's_siren',
  237. # 's_tva_intra',
  238. # 'f_total',
  239. # 'f_note_public',
  240. # 's_siret',
  241. # 'fd_date_start',
  242. # 'fd_label',
  243. # 'f_facnumber',
  244. # 'p_accountancy_code_sell',
  245. # 'fd_date_end',
  246. # 'f_datec',
  247. # 's_idprof4',
  248. # 'fd_rowid',
  249. # 'fd_total_tva',
  250. # 'fd_total_ttc',
  251. # 's_nom',
  252. # 'f_paye',
  253. # 'fd_special_code',
  254. # 'f_datef',
  255. # 'p_ref',
  256. # 's_address',
  257. # 's_town',
  258. # 'fd_description',
  259. # 'fd_product_type',
  260. # 's_rowid',
  261. # 'fd_subprice',
  262. # 'fd_fk_product',
  263. # 's_ape',
  264. # 's_code_compta_fournisseur',
  265. # 'p_label',
  266. # 'fd_total_ht',
  267. # 'f_tva',
  268. # 'fd_qty',
  269. # 'fd_tva_tx',
  270. # 's_code_compta',
  271. # 'f_rowid',
  272. # 'f_fk_statut',
  273. # 'f_note_private']
  274. def get_product_account_code(self):
  275. p_code = self.cells['p_accountancy_code_sell']
  276. if p_code == "":
  277. p_code = self.cells['a_account_number']
  278. if p_code == "":
  279. p_code = self.pc_default_produit
  280. return p_code
  281. class Supplier(Entry):
  282. @staticmethod
  283. def clean(row):
  284. return True
  285. def __init__(self, row):
  286. super(Supplier, self).__init__(row)
  287. self.entries = {}
  288. def addEntry(self, row):
  289. id = row['fd_rowid']
  290. self.entries[id] = SupplierEntry(row)
  291. def check(self):
  292. total_ttc = self.cells['f_total_ttc']
  293. total_tva = self.cells['f_total_tva']
  294. total_ht = self.cells['f_total_ht']
  295. for entry in self.entries.values():
  296. total_ttc -= entry.cells['fd_total_ttc']
  297. total_tva -= entry.cells['fd_tva']
  298. total_ht -= entry.cells['fd_total_ht']
  299. if total_ttc > 1e-10:
  300. print "Erreur dans l'écriture %s: total ttc = %s" % (self.cells['f_ref_supplier'],total_ttc)
  301. if total_ht > 1e-10:
  302. print "Erreur dans l'écriture %s: total ht = %s" % (self.cells['f_ref_supplier'],total_ht)
  303. if total_tva > 1e-10:
  304. print "Erreur dans l'écriture %s: total tva = %s" % (self.cells['f_ref_supplier'],total_tva)
  305. def get_year(self):
  306. return self.get_accounting_year('f_datef')
  307. def getMissingPC(self):
  308. pc_missing = []
  309. if self.cells['s_code_supplier'] == "":
  310. pc_missing.append("tiers: %s %s" % (self.cells['s_nom'], self.cells['s_ape']))
  311. for entry in self.entries.values():
  312. if entry.get_product_account_code() == self.pc_default_charge:
  313. pc_missing.append("achat: %s - %s" % (self.cells['f_ref_supplier'], self.cells['fd_description'].splitlines()[0]))
  314. return pc_missing
  315. def get_ledger(self):
  316. self.check()
  317. s = ""
  318. s += "%(date)s %(description)s\n" % {
  319. 'date': self.cells['f_datef'].strftime("%Y/%m/%d"),
  320. 'description': self.cells['f_ref_supplier'] + " - " + self.cells['s_nom'],
  321. }
  322. s_code = self.cells['s_code_supplier']
  323. if s_code == "":
  324. s_code = self.pc_default_supplier
  325. s += " %(compte_tiers)s %(amount_ttc)s\n" % {
  326. 'compte_tiers': settings.get_ledger_account(s_code),
  327. 'amount_ttc': self.cells['f_total_ttc'],
  328. }
  329. if self.cells['f_total_tva'] != 0:
  330. if s_code.startswith("2"):
  331. tva_account = settings.get('PC_REFS')['tva_deductible']
  332. else:
  333. tva_account = settings.get('PC_REFS')['tva_deductible_immo']
  334. s += " %(compte_tva)s %(amount_tva)s\n" % {
  335. 'compte_tva': settings.get_ledger_account(tva_account),
  336. 'amount_tva': -self.cells['f_total_tva'],
  337. }
  338. for entry in self.entries.values():
  339. p_code = entry.get_product_account_code()
  340. s += " %(compte_produit)s %(amount_ht)s\n" % {
  341. 'compte_produit': settings.get_ledger_account(p_code),
  342. 'amount_ht': -entry.cells['fd_total_ht']
  343. }
  344. return s
  345. class SupplierEntry(Entry):
  346. # ['f_total_ttc',
  347. # 's_phone',
  348. # 'c_code',
  349. # 'f_total_tva',
  350. # 's_zip',
  351. # 's_siren',
  352. # 's_tva_intra',
  353. # 'f_ref',
  354. # 'f_note_public',
  355. # 's_siret',
  356. # 'f_ref_supplier',
  357. # 'f_datec',
  358. # 's_idprof5',
  359. # 's_idprof4',
  360. # 's_idprof6',
  361. # 'p_accountancy_code_buy',
  362. # 'fd_rowid',
  363. # 'f_total_ht',
  364. # 'fd_total_ttc',
  365. # 's_nom',
  366. # 'fd_tva',
  367. # 'f_paye',
  368. # 'f_datef',
  369. # 'p_ref',
  370. # 's_address',
  371. # 's_town',
  372. # 'fd_description',
  373. # 'fd_product_type',
  374. # 's_rowid',
  375. # 'fd_fk_product',
  376. # 's_ape',
  377. # 'p_label',
  378. # 'fd_total_ht',
  379. # 'f_fk_statut',
  380. # 'fd_qty',
  381. # 'fd_tva_tx',
  382. # 'f_rowid',
  383. # 'fd_remise_percent']
  384. def get_product_account_code(self):
  385. p_code = self.cells['p_accountancy_code_buy']
  386. if p_code == "":
  387. p_code = self.cells['a_account_number']
  388. if p_code == "":
  389. p_code = self.pc_default_charge
  390. return p_code
  391. class SocialEntry(Entry):
  392. @staticmethod
  393. def get_third_code(code):
  394. third_code = None
  395. if code in settings.get('SOCIAL_REFS'):
  396. third_code = settings.get('SOCIAL_REFS')[code]
  397. else:
  398. third_code = SocialEntry.pc_default_supplier
  399. return third_code
  400. @staticmethod
  401. def get_s_code(code):
  402. s_code = None
  403. if code is None:
  404. s_code = SocialEntry.pc_default_charge
  405. else:
  406. s_code = code
  407. return s_code
  408. @staticmethod
  409. def clean(row):
  410. return True
  411. def addEntry(self, entry):
  412. pass
  413. def get_year(self):
  414. return self.get_accounting_year('c_periode')
  415. def getMissingPC(self):
  416. pc_missing = []
  417. if self.get_s_code(self.cells['cc_acc_code']) == self.pc_default_charge:
  418. pc_missing.append("charges: %s" % (self.cells['cc_libelle']))
  419. if self.get_third_code(self.cells['cc_code']) == self.pc_default_supplier:
  420. pc_missing.append("tiers: %s (%s)" % (self.cells['c_libelle'], self.cells['cc_code']))
  421. return pc_missing
  422. def get_ledger(self):
  423. s = ""
  424. s += "%(date)s %(description)s\n" % {
  425. 'date': self.cells['c_periode'].strftime("%Y/%m/%d"),
  426. 'description': self.cells['c_libelle'] + " - " + self.cells['cc_libelle']
  427. }
  428. amount = self.cells['c_amount']
  429. third_code = self.get_third_code(self.cells['cc_code'])
  430. s_code = self.get_s_code(self.cells['cc_acc_code'])
  431. s += " %(account)s \t %(amount)s\n" % {
  432. 'account': settings.get_ledger_account(third_code),
  433. 'amount': amount
  434. }
  435. s += " %(account)s \t %(amount)s\n" % {
  436. 'account': settings.get_ledger_account(s_code),
  437. 'amount': -amount
  438. }
  439. return s
  440. class DolibarrSQL(object):
  441. def __init__(self, mysql_host, mysql_port, mysql_database, mysql_user, mysql_password):
  442. self.mysql_database = mysql_database
  443. self.mysql_host = mysql_host
  444. self.mysql_password = mysql_password
  445. self.mysql_user = mysql_user
  446. self.mysql_port = mysql_port
  447. self.queries = MYSQL_QUERIES
  448. def connect(self):
  449. try:
  450. self.cnx = mdb.connect(self.mysql_host, self.mysql_user, self.mysql_password, self.mysql_database, port = self.mysql_port)
  451. self.cursor = self.cnx.cursor()
  452. except mdb.Error, e:
  453. print "Error %d: %s" % (e.args[0], e.args[1])
  454. sys.exit(1)
  455. def disconnect(self):
  456. try:
  457. self.cnx.close()
  458. except mdb.Error, e:
  459. print "Error %d: %s" % (e.args[0], e.args[1])
  460. sys.exit(1)
  461. def get_bank_entries(self):
  462. return self.get_entries(self.queries['bank'], 'b_rowid', BankEntry)
  463. def get_sell_entries(self):
  464. return self.get_entries(self.queries['sells'], 'f_facnumber', Sell)
  465. def get_supplier_entries(self):
  466. return self.get_entries(self.queries['suppliers'], 'f_rowid', Supplier)
  467. def get_social_entries(self):
  468. return self.get_entries(self.queries['social'], 'c_rowid', SocialEntry)
  469. def get_entries(self, query, index, entry_class):
  470. cur = self.cnx.cursor(cursorclass=mdb.cursors.DictCursor)
  471. cur.execute(query)
  472. rows = cur.fetchall()
  473. collection = EntryCollection(index, entry_class)
  474. for row in rows:
  475. if entry_class.clean(row):
  476. collection.addCollectionEntry(row)
  477. return collection
  478. class Writer(object):
  479. output_files = settings.get('OUTPUT_FILES')
  480. output_dir = settings.get('OUTPUT_DIR')
  481. @staticmethod
  482. def write(journal, entries):
  483. filename = Writer.output_files[journal]
  484. output = os.path.join(Writer.output_dir, filename)
  485. entries_by_year = entries.get_by_year()
  486. for year in entries_by_year:
  487. output_file = output.replace("%year%", year)
  488. output_dir = os.path.dirname(output_file)
  489. if not os.path.exists(output_dir):
  490. os.makedirs(os.path.dirname(output_file))
  491. elif not os.path.isdir(output_dir):
  492. print "Error: %s is not a dir\n" % (output_dir)
  493. raise os.error()
  494. f = codecs.open(output_file, 'w', 'utf-8')
  495. for entry in entries_by_year[year]:
  496. f.write(entry.get_ledger())
  497. f.write("\n")
  498. f.close()
  499. @staticmethod
  500. def write_hreport_plan():
  501. pc_names = settings.get('PC_NAMES')
  502. pc_descriptions = settings.get('PC_DESCRIPTIONS')
  503. filename = Writer.output_files['pc']
  504. output_file = os.path.join(Writer.output_dir, filename)
  505. f = codecs.open(output_file, 'w', 'utf-8')
  506. for pc in sorted(pc_names.keys()):
  507. name = pc_names[pc]
  508. if pc in pc_descriptions:
  509. desc = pc_descriptions[pc]
  510. else:
  511. desc = name
  512. s = "%s %s %s\n" %(name.ljust(80), pc.ljust(12), desc)
  513. f.write(s)
  514. f.close()