dolibarrAlchemyHledger.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import settings
  4. from himports.dolibarrAlchemy import *
  5. class HledgerEntry(object):
  6. accounting_years = settings.get('ACCOUNTING_YEARS')
  7. pc_default_tiers = settings.get('PC_REFS')['default_tiers']
  8. pc_default_client = settings.get('PC_REFS')['default_client']
  9. pc_default_supplier = settings.get('PC_REFS')['default_supplier']
  10. pc_default_produit = settings.get('PC_REFS')['default_produit']
  11. pc_default_charge = settings.get('PC_REFS')['default_charge']
  12. pc_default_bank = settings.get('PC_REFS')['default_bank']
  13. sql_class = None
  14. # Date permettant de déterminer dans quel exercice comptable
  15. # l'écriture doit se trouver
  16. k_accounting_date = None
  17. def __init__(self, e):
  18. super(HledgerEntry, self).__init__()
  19. self.e = e
  20. self.accounting_date = e
  21. for attr in self.k_accounting_date.split('.'):
  22. self.accounting_date = getattr(self.accounting_date, attr)
  23. @classmethod
  24. def get_entries(cls, session):
  25. return [cls(i) for i in session.query(cls.sql_class).all()]
  26. def get_ledger(self):
  27. print "WARNING: get_ledger not done"
  28. return u""
  29. def check_pc(self):
  30. return ()
  31. def get_year(self):
  32. raise Exception("TODO: get_year not implemented for class %s" % (self.__class__))
  33. def get_accounting_year(self):
  34. date = self.accounting_date
  35. if isinstance(date, datetime.datetime):
  36. date = date.date()
  37. for (year, dbegin, dend) in HledgerEntry.accounting_years:
  38. if date >= dbegin and date <= dend:
  39. return year
  40. return str(date.year)
  41. class HledgerJournal(object):
  42. def __init__(self, session, cls_entry):
  43. self.entries = cls_entry.get_entries(session)
  44. def get_entries(self):
  45. return self.entries
  46. def get_by_year(self):
  47. by_year = {}
  48. for entry in self.get_entries():
  49. entry_year = entry.get_accounting_year()
  50. if entry_year not in by_year:
  51. by_year[entry_year] = []
  52. by_year[entry_year].append(entry)
  53. return by_year
  54. def check_pc(self):
  55. pc_missing = set()
  56. for entry in self.get_entries():
  57. pc_missing.update(entry.check_pc())
  58. return pc_missing
  59. class HledgerBankEntry(HledgerEntry):
  60. sql_class = Bank
  61. k_accounting_date = 'datev'
  62. def get_third_code(self):
  63. e = self.e
  64. third_code = ""
  65. if e.url_payment_supplier:
  66. if e.url_company:
  67. third_code = e.url_company.societe.code_compta_fournisseur
  68. if e.url_payment_sc:
  69. third_code = e.url_payment_sc.payment_sc.cotisation_sociale.type.accountancy_code
  70. if e.url_payment:
  71. if e.url_company:
  72. third_code = e.url_company.societe.code_compta
  73. if third_code == "":
  74. fn = settings.get('PC_REFS')['fn_custom_code']
  75. third_code = fn(self.e)
  76. return third_code
  77. def get_description(self):
  78. e = self.e
  79. s_nom = ""
  80. s_description = ""
  81. if e.url_company:
  82. s_nom = e.url_company.societe.nom
  83. if e.url_payment_supplier:
  84. f_ids = [f.facture.ref_supplier for f in e.url_payment_supplier.payment_supplier.factures]
  85. s_description = "Règlement facture fournisseur - %s - %s" % (
  86. s_nom,
  87. "|".join(f_ids),
  88. )
  89. if e.url_payment:
  90. f_ids = [f.facture.facnumber for f in e.url_payment.payment.factures]
  91. s_description = "Règlement facture client - %s - %s" % (
  92. s_nom,
  93. "|".join(f_ids),
  94. )
  95. if s_description == "":
  96. s_description = s_nom + " - " + e.label
  97. return s_description
  98. def get_ledger(self):
  99. e = self.e
  100. s = ""
  101. s_description = self.get_description()
  102. s += "%(date)s %(description)s\n" % {
  103. 'date': e.datev.strftime("%Y/%m/%d"),
  104. 'description': s_description
  105. }
  106. third_code = self.get_third_code()
  107. if third_code == "":
  108. third_code = self.pc_default_tiers
  109. s += " %(account)s \t %(amount)s\n" % {
  110. 'account': settings.get_ledger_account(third_code),
  111. 'amount': e.amount
  112. }
  113. ba_code = e.account.account_number
  114. if ba_code == "":
  115. ba_code = self.pc_default_bank
  116. s += " %(account)s \t %(amount)s\n" % {
  117. 'account': settings.get_ledger_account(ba_code),
  118. 'amount': -e.amount
  119. }
  120. return s
  121. @classmethod
  122. def get_entries(cls, session):
  123. return [cls(e) for e in session.query(cls.sql_class).order_by(Bank.datev, Bank.num_releve).filter(Bank.num_releve != "").all()]
  124. class HledgerSupplierEntry(HledgerEntry):
  125. sql_class = FactureFourn
  126. k_accounting_date = 'datef'
  127. @classmethod
  128. def get_entries(cls, session):
  129. return [cls(e) for e in session.query(cls.sql_class).order_by(FactureFourn.datef).all()]
  130. def check(self):
  131. e = self.e
  132. total_ttc = e.total_ttc
  133. total_tva = e.total_tva
  134. total_ht = e.total_ht
  135. for ed in e.details:
  136. total_ttc -= ed.total_ttc
  137. total_tva -= ed.tva
  138. total_ht -= ed.total_ht
  139. if total_ttc > 1e-10:
  140. print "Erreur dans l'écriture %s: total ttc = %s" % (e.ref_supplier, total_ttc)
  141. if total_ht > 1e-10:
  142. print "Erreur dans l'écriture %s: total ht = %s" % (e.ref_supplier, total_ht)
  143. if total_tva > 1e-10:
  144. print "Erreur dans l'écriture %s: total tva = %s" % (e.ref_supplier, total_tva)
  145. def getMissingPC(self):
  146. pc_missing = []
  147. if e.societe.code_compta_fournisseur == "":
  148. pc_missing.append("tiers:fournisseur: %s %s" % (e.societe.nom, s.societe.ape))
  149. for ed in e.details:
  150. if self.get_product_account_code(ed) == self.pc_default_charge:
  151. pc_missing.append("achat: %s - %s" % (e.ref_supplier, ed.description.splitlines()[0]))
  152. return pc_missing
  153. def get_ledger(self):
  154. e = self.e
  155. self.check()
  156. s = ""
  157. s += "%(date)s %(description)s\n" % {
  158. 'date': e.datef.strftime("%Y/%m/%d"),
  159. 'description': e.ref_supplier + " - " + e.societe.nom,
  160. }
  161. s_code = self.get_supplier_code()
  162. s += " %(compte_tiers)s %(amount_ttc)s\n" % {
  163. 'compte_tiers': settings.get_ledger_account(s_code),
  164. 'amount_ttc': e.total_ttc,
  165. }
  166. if e.total_tva != 0:
  167. if s_code.startswith("2"):
  168. tva_account = settings.get('PC_REFS')['tva_deductible']
  169. else:
  170. tva_account = settings.get('PC_REFS')['tva_deductible_immo']
  171. s += " %(compte_tva)s %(amount_tva)s\n" % {
  172. 'compte_tva': settings.get_ledger_account(tva_account),
  173. 'amount_tva': -e.total_tva,
  174. }
  175. for ed in e.details:
  176. p_code = self.get_product_account_code(ed)
  177. s += " %(compte_produit)s %(amount_ht)s\n" % {
  178. 'compte_produit': settings.get_ledger_account(p_code),
  179. 'amount_ht': -ed.total_ht
  180. }
  181. return s
  182. def get_product_account_code(self, ed):
  183. p_code = ""
  184. if ed.accounting_account:
  185. p_code = ed.accounting_account.account_number
  186. elif ed.product:
  187. p_code = ed.product.accountancy_code_buy
  188. else:
  189. p_code = self.pc_default_charge
  190. return p_code
  191. def get_supplier_code(self):
  192. e = self.e
  193. s_code = e.societe.code_compta_fournisseur
  194. if s_code == "":
  195. s_code = self.pc_default_supplier
  196. return s_code
  197. class HledgerSellEntry(HledgerEntry):
  198. sql_class = Facture
  199. k_accounting_date = 'datef'
  200. @classmethod
  201. def get_entries(cls, session):
  202. return [cls(e) for e in session.query(cls.sql_class).order_by(Facture.datef).all()]
  203. def get_ledger(self):
  204. e = self.e
  205. self.check()
  206. s = ""
  207. s += "%(date)s %(description)s\n" % {
  208. 'date': e.datef.strftime("%Y/%m/%d"),
  209. 'description': e.facnumber + " - " + e.societe.nom,
  210. }
  211. s_code = self.get_client_code()
  212. s += " %(compte_tiers)s %(amount_ttc)s\n" % {
  213. 'compte_tiers': settings.get_ledger_account(s_code),
  214. 'amount_ttc': -e.total_ttc,
  215. }
  216. if float(e.tva) != 0:
  217. tva_account = settings.get('PC_REFS')['tva_collecte']
  218. s += " %(compte_tva_collecte)s %(amount_tva)s\n" % {
  219. 'compte_tva_collecte': settings.get_ledger_account(tva_account),
  220. 'amount_tva': e.tva,
  221. }
  222. for ed in e.details:
  223. p_code = self.get_product_account_code(ed)
  224. s += " %(compte_produit)s %(amount_ht)s\n" % {
  225. 'compte_produit': settings.get_ledger_account(p_code),
  226. 'amount_ht': ed.total_ht
  227. }
  228. return s
  229. def getMissingPC(self):
  230. e = self.e
  231. pc_missing = []
  232. if e.societe.code_compta == "":
  233. pc_missing.append("tiers: %s %s" % (e.societe.nom, s.societe.ape))
  234. for ed in e.details:
  235. if self.get_product_account_code(ed) == self.pc_default_produit:
  236. if ed.description != "":
  237. description = ed.description.splitlines()[0]
  238. else:
  239. description = ed.description
  240. pc_missing.append("produit: %s - %s - %s" % (e.societe.nom, e.facnumber, description))
  241. return pc_missing
  242. def get_product_account_code(self, ed):
  243. p_code = ""
  244. if ed.accounting_account:
  245. p_code = ed.accounting_account.account_number
  246. elif ed.product:
  247. p_code = ed.product.accountancy_code_sell
  248. else:
  249. p_code = self.pc_default_produit
  250. return p_code
  251. def get_client_code(self):
  252. e = self.e
  253. s_code = e.societe.code_compta
  254. if s_code == "":
  255. s_code = self.pc_default_client
  256. return s_code
  257. def check(self):
  258. e = self.e
  259. total_ttc = e.total_ttc
  260. total_tva = e.tva
  261. total_ht = e.total
  262. for ed in e.details:
  263. total_ttc -= ed.total_ttc
  264. total_tva -= ed.total_tva
  265. total_ht -= ed.total_ht
  266. if total_ttc > 1e-10:
  267. print "Erreur dans l'écriture %s: total ttc = %s" % (e.facnumber, total_ttc)
  268. if total_ht > 1e-10:
  269. print "Erreur dans l'écriture %s: total ht = %s" % (e.facnumber, total_ht)
  270. if total_tva > 1e-10:
  271. print "Erreur dans l'écriture %s: total tva = %s" % (e.facnumber, total_tva)
  272. class HledgerSocialEntry(HledgerEntry):
  273. sql_class = CotisationsSociales
  274. k_accounting_date = 'date_ech'
  275. @classmethod
  276. def get_entries(cls, session):
  277. return [cls(e) for e in session.query(cls.sql_class).order_by(CotisationsSociales.date_ech).all()]
  278. def get_third_code(self):
  279. e = self.e
  280. third_code = ""
  281. if e.type.code in settings.get('SOCIAL_REFS'):
  282. third_code = settings.get('SOCIAL_REFS')[e.type.code]
  283. if third_code == "":
  284. third_code = self.pc_default_supplier
  285. return third_code
  286. def get_social_code(self):
  287. e = self.e
  288. s_code = ""
  289. if e.type:
  290. s_code = e.type.accountancy_code
  291. if s_code == "":
  292. s_code = self.pc_default_charge
  293. return s_code
  294. def getMissingPC(self):
  295. pc_missing = []
  296. if self.get_social_code() == self.pc_default_charge:
  297. pc_missing.append("charges: %s" % (e.libelle))
  298. if self.get_third_code() == self.pc_default_supplier:
  299. pc_missing.append("tiers: %s (%s)" % (e.libelle, e.type.code))
  300. return pc_missing
  301. def get_ledger(self):
  302. e = self.e
  303. s = ""
  304. s += "%(date)s %(description)s\n" % {
  305. 'date': e.date_ech.strftime("%Y/%m/%d"),
  306. 'description': e.libelle + " - " + e.type.libelle
  307. }
  308. third_code = self.get_third_code()
  309. s_code = self.get_social_code()
  310. s += " %(account)s \t %(amount)s\n" % {
  311. 'account': settings.get_ledger_account(third_code),
  312. 'amount': e.amount
  313. }
  314. s += " %(account)s \t %(amount)s\n" % {
  315. 'account': settings.get_ledger_account(s_code),
  316. 'amount': -e.amount
  317. }
  318. return s
  319. def check(self):
  320. e = self.e
  321. class HledgerDolibarrSQLAlchemy(DolibarrSQLAlchemy):
  322. def get_bank_journal(self):
  323. return HledgerJournal(self.session, HledgerBankEntry)
  324. def get_supplier_journal(self):
  325. return HledgerJournal(self.session, HledgerSupplierEntry)
  326. def get_sell_journal(self):
  327. return HledgerJournal(self.session, HledgerSellEntry)
  328. def get_social_journal(self):
  329. return HledgerJournal(self.session, HledgerSocialEntry)