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.

172 lines
7.8 KiB

  1. # -*- coding: utf-8 -*-
  2. # © 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. from datetime import datetime
  5. from dateutil.relativedelta import relativedelta
  6. from openerp import api, fields, models
  7. class ResPartner(models.Model):
  8. _inherit = 'res.partner'
  9. risk_invoice_draft_include = fields.Boolean(
  10. string='Include Draft Invoices', help='Full risk computation')
  11. risk_invoice_draft_limit = fields.Monetary(
  12. string='Limit In Draft Invoices', help='Set 0 if it is not locked')
  13. risk_invoice_draft = fields.Monetary(
  14. compute='_compute_risk_invoice', store=True,
  15. string='Total Draft Invoices',
  16. help='Total amount of invoices in Draft or Pro-forma state')
  17. risk_invoice_open_include = fields.Boolean(
  18. string='Include Open Invoices', help='Full risk computation')
  19. risk_invoice_open_limit = fields.Monetary(
  20. string='Limit In Open Invoices', help='Set 0 if it is not locked')
  21. risk_invoice_open = fields.Monetary(
  22. compute='_compute_risk_invoice', store=True,
  23. string='Total Open Invoices',
  24. help='Residual amount of invoices in Open state and the date due is '
  25. 'not exceeded, considering Due Margin set in account '
  26. 'settings')
  27. risk_invoice_unpaid_include = fields.Boolean(
  28. string='Include Unpaid Invoices', help='Full risk computation')
  29. risk_invoice_unpaid_limit = fields.Monetary(
  30. string='Limit In Unpaid Invoices', help='Set 0 if it is not locked')
  31. risk_invoice_unpaid = fields.Monetary(
  32. compute='_compute_risk_invoice', store=True,
  33. string='Total Unpaid Invoices',
  34. help='Residual amount of invoices in Open state and the date due is '
  35. 'exceeded, considering Unpaid Margin set in account settings')
  36. risk_account_amount_include = fields.Boolean(
  37. string='Include Other Account Amount', help='Full risk computation')
  38. risk_account_amount_limit = fields.Monetary(
  39. string='Limit Other Account Amount', help='Set 0 if it is not locked')
  40. risk_account_amount = fields.Monetary(
  41. compute='_compute_risk_account_amount',
  42. string='Other Account Amount',
  43. help='Difference between accounting credit and rest of totals')
  44. risk_total = fields.Monetary(
  45. compute='_compute_risk_exception',
  46. string='Total Risk', help='Sum of total risk included')
  47. risk_exception = fields.Boolean(
  48. compute='_compute_risk_exception',
  49. string='Risk Exception',
  50. help='It Indicate if partner risk exceeded')
  51. credit_policy = fields.Char()
  52. risk_allow_edit = fields.Boolean(compute='_compute_risk_allow_edit')
  53. credit_limit = fields.Float(track_visibility='onchange')
  54. @api.multi
  55. def _compute_risk_allow_edit(self):
  56. is_editable = self.env.user.has_group(
  57. 'base.group_sale_manager') or self.env.user.has_group(
  58. 'account.group_account_manager')
  59. for partner in self.filtered('customer'):
  60. partner.risk_allow_edit = is_editable
  61. @api.multi
  62. @api.depends('invoice_ids', 'invoice_ids.state',
  63. 'invoice_ids.amount_total', 'invoice_ids.residual',
  64. 'invoice_ids.company_id.invoice_unpaid_margin',
  65. 'child_ids.invoice_ids', 'child_ids.invoice_ids.state',
  66. 'child_ids.invoice_ids.amount_total',
  67. 'child_ids.invoice_ids.residual',
  68. 'child_ids.invoice_ids.company_id.invoice_unpaid_margin')
  69. def _compute_risk_invoice(self):
  70. def sum_group(group, field):
  71. return sum([x[field] for x in group if
  72. x['partner_id'][0] in partner_ids])
  73. customers = self.filtered('customer')
  74. if not customers:
  75. return # pragma: no cover
  76. max_date = self._max_risk_date_due()
  77. AccountInvoice = self.env['account.invoice']
  78. partners = customers | customers.mapped('child_ids')
  79. domain = [('type', 'in', ['out_invoice', 'out_refund']),
  80. ('partner_id', 'in', partners.ids)]
  81. draft_group = AccountInvoice.read_group(
  82. domain + [('state', 'in', ['draft', 'proforma', 'proforma2'])],
  83. ['partner_id', 'amount_total'],
  84. ['partner_id'])
  85. open_group = AccountInvoice.read_group(
  86. domain + [('state', '=', 'open'), ('date_due', '>=', max_date)],
  87. ['partner_id', 'residual'],
  88. ['partner_id'])
  89. unpaid_group = AccountInvoice.read_group(
  90. domain + [('state', '=', 'open'), '|',
  91. ('date_due', '=', False), ('date_due', '<', max_date)],
  92. ['partner_id', 'residual'],
  93. ['partner_id'])
  94. for partner in customers:
  95. partner_ids = (partner | partner.child_ids).ids
  96. partner.risk_invoice_draft = sum_group(draft_group, 'amount_total')
  97. partner.risk_invoice_open = sum_group(open_group, 'residual')
  98. partner.risk_invoice_unpaid = sum_group(unpaid_group, 'residual')
  99. @api.multi
  100. @api.depends('credit', 'risk_invoice_open', 'risk_invoice_unpaid',
  101. 'child_ids.credit', 'child_ids.risk_invoice_open',
  102. 'child_ids.risk_invoice_unpaid')
  103. def _compute_risk_account_amount(self):
  104. for partner in self.filtered('customer'):
  105. partner.risk_account_amount = (
  106. partner.credit - partner.risk_invoice_open -
  107. partner.risk_invoice_unpaid)
  108. @api.multi
  109. @api.depends(lambda x: x._get_depends_compute_risk_exception())
  110. def _compute_risk_exception(self):
  111. risk_field_list = self._risk_field_list()
  112. for partner in self.filtered('customer'):
  113. amount = 0.0
  114. for risk_field in risk_field_list:
  115. field_value = getattr(partner, risk_field[0], 0.0)
  116. max_value = getattr(partner, risk_field[1], 0.0)
  117. if max_value and field_value > max_value:
  118. partner.risk_exception = True
  119. if getattr(partner, risk_field[2], False):
  120. amount += field_value
  121. partner.risk_total = amount
  122. if partner.credit_limit and amount > partner.credit_limit:
  123. partner.risk_exception = True
  124. @api.model
  125. def _max_risk_date_due(self):
  126. return fields.Date.to_string(datetime.today().date() - relativedelta(
  127. days=self.env.user.company_id.invoice_unpaid_margin))
  128. @api.model
  129. def _risk_field_list(self):
  130. return [
  131. ('risk_invoice_draft', 'risk_invoice_draft_limit',
  132. 'risk_invoice_draft_include'),
  133. ('risk_invoice_open', 'risk_invoice_open_limit',
  134. 'risk_invoice_open_include'),
  135. ('risk_invoice_unpaid', 'risk_invoice_unpaid_limit',
  136. 'risk_invoice_unpaid_include'),
  137. ('risk_account_amount', 'risk_account_amount_limit',
  138. 'risk_account_amount_include'),
  139. ]
  140. @api.model
  141. def _get_depends_compute_risk_exception(self):
  142. res = []
  143. for x in self._risk_field_list():
  144. res.extend((x[0], x[1], x[2], 'child_ids.%s' % x[0],
  145. 'child_ids.%s' % x[1], 'child_ids.%s' % x[2]))
  146. res.extend(('credit_limit', 'child_ids.credit_limit'))
  147. return res
  148. @api.model
  149. def process_unpaid_invoices(self):
  150. today = fields.Date.today()
  151. ConfigParameter = self.env['ir.config_parameter']
  152. last_check = ConfigParameter.get_param(
  153. 'partner_financial_risk.last_check', default='2016-01-01')
  154. invoices = self.env['account.invoice'].search([
  155. ('date_due', '>=', last_check), ('date_due', '<', today)])
  156. invoices.mapped('partner_id')._compute_risk_invoice()
  157. ConfigParameter.set_param('partner_financial_risk.last_check', today)
  158. return True