You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

674 lines
19 KiB

  1. # -*- coding: utf-8 -*-
  2. # © 2016 Julien Coux (Camptocamp)
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  4. from openerp import models, fields, api
  5. class OpenInvoiceReport(models.TransientModel):
  6. """ Here, we just define class fields.
  7. For methods, go more bottom at this file.
  8. """
  9. _name = 'report_open_invoice_qweb'
  10. date_at = fields.Date()
  11. only_posted_moves = fields.Boolean()
  12. hide_account_balance_at_0 = fields.Boolean()
  13. company_id = fields.Many2one(comodel_name='res.company')
  14. filter_account_ids = fields.Many2many(comodel_name='account.account')
  15. filter_partner_ids = fields.Many2many(comodel_name='res.partner')
  16. has_second_currency = fields.Boolean()
  17. account_ids = fields.One2many(
  18. comodel_name='report_open_invoice_qweb_account',
  19. inverse_name='report_id'
  20. )
  21. class OpenInvoiceReportAccount(models.TransientModel):
  22. _name = 'report_open_invoice_qweb_account'
  23. _order = 'code ASC'
  24. report_id = fields.Many2one(
  25. comodel_name='report_open_invoice_qweb',
  26. ondelete='cascade',
  27. index=True
  28. )
  29. account_id = fields.Many2one(
  30. 'account.account',
  31. index=True
  32. )
  33. code = fields.Char()
  34. name = fields.Char()
  35. final_amount_residual = fields.Float(digits=(16, 2))
  36. partner_ids = fields.One2many(
  37. comodel_name='report_open_invoice_qweb_partner',
  38. inverse_name='report_account_id'
  39. )
  40. class OpenInvoiceReportPartner(models.TransientModel):
  41. _name = 'report_open_invoice_qweb_partner'
  42. report_account_id = fields.Many2one(
  43. comodel_name='report_open_invoice_qweb_account',
  44. ondelete='cascade',
  45. index=True
  46. )
  47. partner_id = fields.Many2one(
  48. 'res.partner',
  49. index=True
  50. )
  51. name = fields.Char()
  52. final_amount_residual = fields.Float(digits=(16, 2))
  53. move_line_ids = fields.One2many(
  54. comodel_name='report_open_invoice_qweb_move_line',
  55. inverse_name='report_partner_id'
  56. )
  57. @api.model
  58. def _generate_order_by(self, order_spec, query):
  59. return """
  60. ORDER BY
  61. CASE
  62. WHEN "report_open_invoice_qweb_partner"."partner_id" IS NOT NULL
  63. THEN 0
  64. ELSE 1
  65. END,
  66. "report_open_invoice_qweb_partner"."name"
  67. """
  68. class OpenInvoiceReportMoveLine(models.TransientModel):
  69. _name = 'report_open_invoice_qweb_move_line'
  70. report_partner_id = fields.Many2one(
  71. comodel_name='report_open_invoice_qweb_partner',
  72. ondelete='cascade',
  73. index=True
  74. )
  75. move_line_id = fields.Many2one('account.move.line')
  76. date = fields.Date()
  77. date_due = fields.Date()
  78. entry = fields.Char()
  79. journal = fields.Char()
  80. account = fields.Char()
  81. partner = fields.Char()
  82. label = fields.Char()
  83. amount_total_due = fields.Float(digits=(16, 2))
  84. amount_residual = fields.Float(digits=(16, 2))
  85. currency_name = fields.Char()
  86. amount_total_due_currency = fields.Float(digits=(16, 2))
  87. amount_residual_currency = fields.Float(digits=(16, 2))
  88. class OpenInvoiceReportCompute(models.TransientModel):
  89. _inherit = 'report_open_invoice_qweb'
  90. @api.model
  91. def print_report(self):
  92. self.ensure_one()
  93. self.compute_data_for_report()
  94. return {
  95. 'type': 'ir.actions.report.xml',
  96. 'report_name':
  97. 'account_financial_report_qweb.report_open_invoice_qweb',
  98. 'datas': {'ids': [self.id]},
  99. }
  100. @api.model
  101. def compute_data_for_report(self):
  102. self.ensure_one()
  103. self.inject_account_values()
  104. self.inject_partner_values()
  105. self.inject_line_values()
  106. self.inject_line_values(only_empty_partner_line=True)
  107. self.clean_partners_and_accounts()
  108. self.compute_partners_and_accounts_cumul()
  109. if self.hide_account_balance_at_0:
  110. self.clean_partners_and_accounts(
  111. only_delete_account_balance_at_0=True
  112. )
  113. self.compute_has_second_currency()
  114. def inject_account_values(self):
  115. query_inject_account = """
  116. WITH
  117. accounts AS
  118. (
  119. SELECT
  120. a.id,
  121. a.code,
  122. a.name,
  123. a.user_type_id
  124. FROM
  125. account_account a
  126. INNER JOIN
  127. account_move_line ml ON a.id = ml.account_id AND ml.date <= %s
  128. """
  129. if self.filter_partner_ids:
  130. query_inject_account += """
  131. INNER JOIN
  132. res_partner p ON ml.partner_id = p.id
  133. """
  134. if self.only_posted_moves:
  135. query_inject_account += """
  136. INNER JOIN
  137. account_move m ON ml.move_id = m.id AND m.state = 'posted'
  138. """
  139. query_inject_account += """
  140. WHERE
  141. a.company_id = %s
  142. AND a.internal_type IN ('payable', 'receivable')
  143. """
  144. if self.filter_account_ids:
  145. query_inject_account += """
  146. AND
  147. a.id IN %s
  148. """
  149. if self.filter_partner_ids:
  150. query_inject_account += """
  151. AND
  152. p.id IN %s
  153. """
  154. query_inject_account += """
  155. GROUP BY
  156. a.id
  157. )
  158. INSERT INTO
  159. report_open_invoice_qweb_account
  160. (
  161. report_id,
  162. create_uid,
  163. create_date,
  164. account_id,
  165. code,
  166. name
  167. )
  168. SELECT
  169. %s AS report_id,
  170. %s AS create_uid,
  171. NOW() AS create_date,
  172. a.id AS account_id,
  173. a.code,
  174. a.name
  175. FROM
  176. accounts a
  177. """
  178. query_inject_account_params = (
  179. self.date_at,
  180. self.company_id.id,
  181. )
  182. if self.filter_account_ids:
  183. query_inject_account_params += (
  184. tuple(self.filter_account_ids.ids),
  185. )
  186. if self.filter_partner_ids:
  187. query_inject_account_params += (
  188. tuple(self.filter_partner_ids.ids),
  189. )
  190. query_inject_account_params += (
  191. self.id,
  192. self.env.uid,
  193. )
  194. self.env.cr.execute(query_inject_account, query_inject_account_params)
  195. def inject_partner_values(self):
  196. query_inject_partner = """
  197. WITH
  198. accounts_partners AS
  199. (
  200. SELECT
  201. ra.id AS report_account_id,
  202. a.id AS account_id,
  203. at.include_initial_balance AS include_initial_balance,
  204. p.id AS partner_id,
  205. COALESCE(
  206. CASE
  207. WHEN
  208. NULLIF(p.name, '') IS NOT NULL
  209. AND NULLIF(p.ref, '') IS NOT NULL
  210. THEN p.name || ' (' || p.ref || ')'
  211. ELSE p.name
  212. END,
  213. 'No partner allocated'
  214. ) AS partner_name
  215. FROM
  216. report_open_invoice_qweb_account ra
  217. INNER JOIN
  218. account_account a ON ra.account_id = a.id
  219. INNER JOIN
  220. account_account_type at ON a.user_type_id = at.id
  221. INNER JOIN
  222. account_move_line ml ON a.id = ml.account_id AND ml.date <= %s
  223. """
  224. if self.only_posted_moves:
  225. query_inject_partner += """
  226. INNER JOIN
  227. account_move m ON ml.move_id = m.id AND m.state = 'posted'
  228. """
  229. query_inject_partner += """
  230. LEFT JOIN
  231. res_partner p ON ml.partner_id = p.id
  232. WHERE
  233. ra.report_id = %s
  234. """
  235. if self.filter_partner_ids:
  236. query_inject_partner += """
  237. AND
  238. p.id IN %s
  239. """
  240. query_inject_partner += """
  241. GROUP BY
  242. ra.id,
  243. a.id,
  244. p.id,
  245. at.include_initial_balance
  246. )
  247. INSERT INTO
  248. report_open_invoice_qweb_partner
  249. (
  250. report_account_id,
  251. create_uid,
  252. create_date,
  253. partner_id,
  254. name
  255. )
  256. SELECT
  257. ap.report_account_id,
  258. %s AS create_uid,
  259. NOW() AS create_date,
  260. ap.partner_id,
  261. ap.partner_name
  262. FROM
  263. accounts_partners ap
  264. """
  265. query_inject_partner_params = (
  266. self.date_at,
  267. self.id,
  268. )
  269. if self.filter_partner_ids:
  270. query_inject_partner_params += (
  271. tuple(self.filter_partner_ids.ids),
  272. )
  273. query_inject_partner_params += (
  274. self.env.uid,
  275. )
  276. self.env.cr.execute(query_inject_partner, query_inject_partner_params)
  277. def inject_line_values(self, only_empty_partner_line=False):
  278. query_inject_move_line = """
  279. WITH
  280. move_lines_amount AS
  281. (
  282. SELECT
  283. ml.id,
  284. ml.balance,
  285. SUM(
  286. CASE
  287. WHEN ml_past.id IS NOT NULL
  288. THEN pr.amount
  289. ELSE NULL
  290. END
  291. ) AS partial_amount,
  292. ml.amount_currency,
  293. SUM(
  294. CASE
  295. WHEN ml_past.id IS NOT NULL
  296. THEN pr.amount_currency
  297. ELSE NULL
  298. END
  299. ) AS partial_amount_currency
  300. FROM
  301. report_open_invoice_qweb_partner rp
  302. INNER JOIN
  303. report_open_invoice_qweb_account ra
  304. ON rp.report_account_id = ra.id
  305. INNER JOIN
  306. account_move_line ml
  307. ON ra.account_id = ml.account_id
  308. """
  309. if not only_empty_partner_line:
  310. query_inject_move_line += """
  311. AND rp.partner_id = ml.partner_id
  312. """
  313. elif only_empty_partner_line:
  314. query_inject_move_line += """
  315. AND ml.partner_id IS NULL
  316. """
  317. query_inject_move_line += """
  318. LEFT JOIN
  319. account_partial_reconcile pr
  320. ON ml.balance < 0 AND pr.credit_move_id = ml.id
  321. OR ml.balance > 0 AND pr.debit_move_id = ml.id
  322. LEFT JOIN
  323. account_move_line ml_future
  324. ON (
  325. ml.balance < 0 AND pr.debit_move_id = ml_future.id
  326. OR ml.balance > 0 AND pr.credit_move_id = ml_future.id
  327. )
  328. AND ml_future.date >= %s
  329. LEFT JOIN
  330. account_move_line ml_past
  331. ON (
  332. ml.balance < 0 AND pr.debit_move_id = ml_past.id
  333. OR ml.balance > 0 AND pr.credit_move_id = ml_past.id
  334. )
  335. AND ml_past.date < %s
  336. WHERE
  337. ra.report_id = %s
  338. GROUP BY
  339. ml.id,
  340. ml.balance,
  341. ml.amount_currency
  342. HAVING
  343. (
  344. ml.full_reconcile_id IS NULL
  345. OR MAX(ml_future.id) IS NOT NULL
  346. )
  347. ),
  348. move_lines AS
  349. (
  350. SELECT
  351. id,
  352. CASE
  353. WHEN SUM(partial_amount) > 0
  354. THEN
  355. CASE
  356. WHEN balance > 0
  357. THEN balance - SUM(partial_amount)
  358. ELSE balance + SUM(partial_amount)
  359. END
  360. ELSE balance
  361. END AS amount_residual,
  362. CASE
  363. WHEN SUM(partial_amount_currency) > 0
  364. THEN
  365. CASE
  366. WHEN amount_currency > 0
  367. THEN amount_currency - SUM(partial_amount_currency)
  368. ELSE amount_currency + SUM(partial_amount_currency)
  369. END
  370. ELSE amount_currency
  371. END AS amount_residual_currency
  372. FROM
  373. move_lines_amount
  374. GROUP BY
  375. id,
  376. balance,
  377. amount_currency
  378. )
  379. INSERT INTO
  380. report_open_invoice_qweb_move_line
  381. (
  382. report_partner_id,
  383. create_uid,
  384. create_date,
  385. move_line_id,
  386. date,
  387. date_due,
  388. entry,
  389. journal,
  390. account,
  391. partner,
  392. label,
  393. amount_total_due,
  394. amount_residual,
  395. currency_name,
  396. amount_total_due_currency,
  397. amount_residual_currency
  398. )
  399. SELECT
  400. rp.id AS report_partner_id,
  401. %s AS create_uid,
  402. NOW() AS create_date,
  403. ml.id AS move_line_id,
  404. ml.date,
  405. ml.date_maturity,
  406. m.name AS entry,
  407. j.code AS journal,
  408. a.code AS account,
  409. """
  410. if not only_empty_partner_line:
  411. query_inject_move_line += """
  412. CASE
  413. WHEN
  414. NULLIF(p.name, '') IS NOT NULL
  415. AND NULLIF(p.ref, '') IS NOT NULL
  416. THEN p.name || ' (' || p.ref || ')'
  417. ELSE p.name
  418. END AS partner,
  419. """
  420. elif only_empty_partner_line:
  421. query_inject_move_line += """
  422. 'No partner allocated' AS partner,
  423. """
  424. query_inject_move_line += """
  425. CONCAT_WS(' - ', NULLIF(ml.ref, ''), NULLIF(ml.name, '')) AS label,
  426. ml.balance,
  427. ml2.amount_residual,
  428. c.name AS currency_name,
  429. ml.amount_currency,
  430. ml2.amount_residual_currency
  431. FROM
  432. report_open_invoice_qweb_partner rp
  433. INNER JOIN
  434. report_open_invoice_qweb_account ra ON rp.report_account_id = ra.id
  435. INNER JOIN
  436. account_move_line ml ON ra.account_id = ml.account_id
  437. INNER JOIN
  438. move_lines ml2
  439. ON ml.id = ml2.id
  440. AND ml2.amount_residual IS NOT NULL
  441. AND ml2.amount_residual != 0
  442. INNER JOIN
  443. account_move m ON ml.move_id = m.id
  444. INNER JOIN
  445. account_journal j ON ml.journal_id = j.id
  446. INNER JOIN
  447. account_account a ON ml.account_id = a.id
  448. """
  449. if not only_empty_partner_line:
  450. query_inject_move_line += """
  451. INNER JOIN
  452. res_partner p
  453. ON ml.partner_id = p.id AND rp.partner_id = p.id
  454. """
  455. query_inject_move_line += """
  456. LEFT JOIN
  457. account_full_reconcile fr ON ml.full_reconcile_id = fr.id
  458. LEFT JOIN
  459. res_currency c ON a.currency_id = c.id
  460. WHERE
  461. ra.report_id = %s
  462. AND
  463. ml.date <= %s
  464. """
  465. if self.only_posted_moves:
  466. query_inject_move_line += """
  467. AND
  468. m.state = 'posted'
  469. """
  470. if only_empty_partner_line:
  471. query_inject_move_line += """
  472. AND
  473. ml.partner_id IS NULL
  474. AND
  475. rp.partner_id IS NULL
  476. """
  477. if not only_empty_partner_line:
  478. query_inject_move_line += """
  479. ORDER BY
  480. a.code, p.name, ml.date, ml.id
  481. """
  482. elif only_empty_partner_line:
  483. query_inject_move_line += """
  484. ORDER BY
  485. a.code, ml.date, ml.id
  486. """
  487. self.env.cr.execute(
  488. query_inject_move_line,
  489. (self.date_at,
  490. self.date_at,
  491. self.id,
  492. self.env.uid,
  493. self.id,
  494. self.date_at,)
  495. )
  496. def compute_partners_and_accounts_cumul(self):
  497. query_compute_partners_cumul = """
  498. UPDATE
  499. report_open_invoice_qweb_partner
  500. SET
  501. final_amount_residual =
  502. (
  503. SELECT
  504. SUM(rml.amount_residual) AS final_amount_residual
  505. FROM
  506. report_open_invoice_qweb_move_line rml
  507. WHERE
  508. rml.report_partner_id = report_open_invoice_qweb_partner.id
  509. )
  510. WHERE
  511. id IN
  512. (
  513. SELECT
  514. rp.id
  515. FROM
  516. report_open_invoice_qweb_account ra
  517. INNER JOIN
  518. report_open_invoice_qweb_partner rp
  519. ON ra.id = rp.report_account_id
  520. WHERE
  521. ra.report_id = %s
  522. )
  523. """
  524. params_compute_partners_cumul = (self.id,)
  525. self.env.cr.execute(query_compute_partners_cumul,
  526. params_compute_partners_cumul)
  527. query_compute_accounts_cumul = """
  528. UPDATE
  529. report_open_invoice_qweb_account
  530. SET
  531. final_amount_residual =
  532. (
  533. SELECT
  534. SUM(rp.final_amount_residual) AS final_amount_residual
  535. FROM
  536. report_open_invoice_qweb_partner rp
  537. WHERE
  538. rp.report_account_id = report_open_invoice_qweb_account.id
  539. )
  540. WHERE
  541. report_id = %s
  542. """
  543. params_compute_accounts_cumul = (self.id,)
  544. self.env.cr.execute(query_compute_accounts_cumul,
  545. params_compute_accounts_cumul)
  546. def clean_partners_and_accounts(self,
  547. only_delete_account_balance_at_0=False):
  548. query_clean_partners = """
  549. DELETE FROM
  550. report_open_invoice_qweb_partner
  551. WHERE
  552. id IN
  553. (
  554. SELECT
  555. DISTINCT rp.id
  556. FROM
  557. report_open_invoice_qweb_account ra
  558. INNER JOIN
  559. report_open_invoice_qweb_partner rp
  560. ON ra.id = rp.report_account_id
  561. LEFT JOIN
  562. report_open_invoice_qweb_move_line rml
  563. ON rp.id = rml.report_partner_id
  564. WHERE
  565. ra.report_id = %s
  566. """
  567. if not only_delete_account_balance_at_0:
  568. query_clean_partners += """
  569. AND rml.id IS NULL
  570. """
  571. elif only_delete_account_balance_at_0:
  572. query_clean_partners += """
  573. AND (
  574. rp.final_amount_residual IS NULL
  575. OR rp.final_amount_residual = 0
  576. )
  577. """
  578. query_clean_partners += """
  579. )
  580. """
  581. params_clean_partners = (self.id,)
  582. self.env.cr.execute(query_clean_partners, params_clean_partners)
  583. query_clean_accounts = """
  584. DELETE FROM
  585. report_open_invoice_qweb_account
  586. WHERE
  587. id IN
  588. (
  589. SELECT
  590. DISTINCT ra.id
  591. FROM
  592. report_open_invoice_qweb_account ra
  593. LEFT JOIN
  594. report_open_invoice_qweb_partner rp
  595. ON ra.id = rp.report_account_id
  596. WHERE
  597. ra.report_id = %s
  598. """
  599. if not only_delete_account_balance_at_0:
  600. query_clean_accounts += """
  601. AND rp.id IS NULL
  602. """
  603. elif only_delete_account_balance_at_0:
  604. query_clean_accounts += """
  605. AND (
  606. ra.final_amount_residual IS NULL
  607. OR ra.final_amount_residual = 0
  608. )
  609. """
  610. query_clean_accounts += """
  611. )
  612. """
  613. params_clean_accounts = (self.id,)
  614. self.env.cr.execute(query_clean_accounts, params_clean_accounts)
  615. def compute_has_second_currency(self):
  616. query_update_has_second_currency = """
  617. UPDATE
  618. report_open_invoice_qweb
  619. SET
  620. has_second_currency =
  621. (
  622. SELECT
  623. TRUE
  624. FROM
  625. report_open_invoice_qweb_move_line l
  626. INNER JOIN
  627. report_open_invoice_qweb_partner p
  628. ON l.report_partner_id = p.id
  629. INNER JOIN
  630. report_open_invoice_qweb_account a
  631. ON p.report_account_id = a.id
  632. WHERE
  633. a.report_id = %s
  634. AND l.currency_name IS NOT NULL
  635. LIMIT 1
  636. )
  637. WHERE id = %s
  638. """
  639. params = (self.id,) * 2
  640. self.env.cr.execute(query_update_has_second_currency, params)