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.

228 lines
7.8 KiB

  1. # Copyright 2019 Coop IT Easy SCRL fs
  2. # Houssine BAKKALI <houssine@coopiteasy.be>
  3. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
  4. import logging
  5. from odoo import _, api, fields, models
  6. _logger = logging.getLogger(__name__)
  7. class LoanIssue(models.Model):
  8. _name = "loan.issue"
  9. _description = "Loan Issue"
  10. @api.multi
  11. def _compute_subscribed_amount(self):
  12. for issue in self:
  13. susbscribed_amount = 0.0
  14. for line in issue.loan_issue_lines.filtered(
  15. lambda record: record.state != "cancelled"
  16. ):
  17. susbscribed_amount += line.amount
  18. issue.subscribed_amount = susbscribed_amount
  19. name = fields.Char(string="Name", translate=True)
  20. default_issue = fields.Boolean(string="Default issue")
  21. subscription_start_date = fields.Date(
  22. string="Start date subscription period"
  23. )
  24. subscription_end_date = fields.Date(string="End date subscription period")
  25. user_id = fields.Many2one("res.users", string="Responsible")
  26. loan_start_date = fields.Date(string="Loan start date")
  27. term_date = fields.Date(string="Term date")
  28. loan_term = fields.Float(string="Duration of the loan in month")
  29. rate = fields.Float(string="Interest rate")
  30. face_value = fields.Monetary(
  31. string="Facial value",
  32. currency_field="company_currency_id",
  33. required=True,
  34. )
  35. minimum_amount = fields.Monetary(
  36. string="Minimum amount of issue", currency_field="company_currency_id"
  37. )
  38. maximum_amount = fields.Monetary(
  39. string="Maximum amount of issue", currency_field="company_currency_id"
  40. )
  41. min_amount_company = fields.Monetary(
  42. string="Minimum amount for a company",
  43. currency_field="company_currency_id",
  44. )
  45. max_amount_company = fields.Monetary(
  46. string="Maximum amount for a company",
  47. currency_field="company_currency_id",
  48. )
  49. min_amount_person = fields.Monetary(
  50. string="Minimum amount for a person",
  51. currency_field="company_currency_id",
  52. )
  53. max_amount_person = fields.Monetary(
  54. string="Maximum amount for a person",
  55. currency_field="company_currency_id",
  56. )
  57. subscribed_amount = fields.Monetary(
  58. string="Subscribed amount",
  59. compute="_compute_subscribed_amount",
  60. currency_field="company_currency_id",
  61. )
  62. interest_payment = fields.Selection(
  63. [("end", "End"), ("yearly", "Yearly")], string="Interest payment"
  64. )
  65. interest_payment_info = fields.Char(string="Yearly payment on")
  66. loan_issue_lines = fields.One2many(
  67. "loan.issue.line", "loan_issue_id", string="Loan issue lines"
  68. )
  69. state = fields.Selection(
  70. [
  71. ("draft", "Draft"),
  72. ("confirmed", "Confirmed"),
  73. ("cancelled", "Cancelled"),
  74. ("ongoing", "Ongoing"),
  75. ("closed", "Closed"),
  76. ],
  77. string="State",
  78. default="draft",
  79. )
  80. company_currency_id = fields.Many2one(
  81. "res.currency",
  82. related="company_id.currency_id",
  83. string="Company Currency",
  84. readonly=True,
  85. )
  86. company_id = fields.Many2one(
  87. "res.company",
  88. string="Company",
  89. required=True,
  90. readonly=True,
  91. default=lambda self: self.env["res.company"]._company_default_get(),
  92. ) # noqa
  93. by_company = fields.Boolean(string="By company")
  94. by_individual = fields.Boolean(string="By individuals")
  95. display_on_website = fields.Boolean(sting="Display on website")
  96. taxes_rate = fields.Float(string="Taxes on interest", required=True)
  97. @api.multi
  98. def get_max_amount(self, partner):
  99. """
  100. Return the maximum amount that partner can buy.
  101. A negative value means that there is no maximum.
  102. """
  103. self.ensure_one()
  104. lines = self.loan_issue_lines.filtered(
  105. lambda r: r.partner_id == partner and r.state != "cancelled"
  106. )
  107. already_subscribed = sum(line.amount for line in lines)
  108. max_amount = -1 # No max amount
  109. if partner.is_company and self.max_amount_company > 0:
  110. max_amount = max(0, self.max_amount_company - already_subscribed)
  111. if not partner.is_company and self.max_amount_person > 0:
  112. max_amount = max(0, self.max_amount_person - already_subscribed)
  113. return max_amount
  114. @api.multi
  115. def get_min_amount(self, partner):
  116. """
  117. Return the minimum amount that a partner must buy.
  118. A zero value means that there is no minimum amount.
  119. """
  120. self.ensure_one()
  121. lines = self.loan_issue_lines.filtered(
  122. lambda r: r.partner_id == partner and r.state != "cancelled"
  123. )
  124. amount_subscribed = sum(line.amount for line in lines)
  125. if partner.is_company:
  126. min_amount = self.min_amount_company - amount_subscribed
  127. else:
  128. min_amount = self.min_amount_person - amount_subscribed
  129. return max(0, min_amount)
  130. @api.multi
  131. def get_web_issues(self, is_company):
  132. bond_issues = self.search(
  133. [("display_on_website", "=", True), ("state", "=", "ongoing")]
  134. )
  135. if is_company is True:
  136. return bond_issues.filtered("by_company")
  137. else:
  138. return bond_issues.filtered("by_company")
  139. @api.multi
  140. def action_confirm(self):
  141. self.ensure_one()
  142. self.write({"state": "confirmed"})
  143. @api.multi
  144. def action_open(self):
  145. self.ensure_one()
  146. self.write({"state": "ongoing"})
  147. @api.multi
  148. def action_draft(self):
  149. self.ensure_one()
  150. self.write({"state": "draft"})
  151. @api.multi
  152. def action_cancel(self):
  153. self.ensure_one()
  154. self.write({"state": "cancelled"})
  155. @api.multi
  156. def action_close(self):
  157. self.ensure_one()
  158. self.write({"state": "closed"})
  159. def get_interest_vals(self, line, vals):
  160. interest_obj = self.env["loan.interest.line"]
  161. accrued_amount = line.amount
  162. accrued_interest = 0
  163. accrued_net_interest = 0
  164. accrued_taxes = 0
  165. for year in range(1, int(self.loan_term) + 1):
  166. interest = accrued_amount * (line.loan_issue_id.rate / 100)
  167. accrued_amount += interest
  168. taxes_amount = interest * (self.taxes_rate / 100)
  169. net_interest = interest - taxes_amount
  170. accrued_interest += interest
  171. accrued_net_interest += net_interest
  172. accrued_taxes += taxes_amount
  173. vals["interest"] = interest
  174. vals["net_interest"] = net_interest
  175. vals["taxes_amount"] = taxes_amount
  176. vals["accrued_amount"] = accrued_amount
  177. vals["accrued_interest"] = accrued_interest
  178. vals["accrued_net_interest"] = accrued_net_interest
  179. vals["accrued_taxes"] = accrued_taxes
  180. vals["name"] = year
  181. interest_obj.create(vals)
  182. @api.multi
  183. def compute_loan_interest(self):
  184. self.ensure_one()
  185. if self.interest_payment == "end":
  186. due_date = self.term_date
  187. else:
  188. raise NotImplementedError(
  189. _("Interest payment by year hasn't been " "implemented yet")
  190. )
  191. for line in self.loan_issue_lines:
  192. # TODO remove this line
  193. line.interest_lines.unlink()
  194. # Please Do not Forget
  195. vals = {
  196. "issue_line": line.id,
  197. "due_date": due_date,
  198. "taxes_rate": self.taxes_rate,
  199. }
  200. self.get_interest_vals(line, vals)
  201. rounded_term = int(self.loan_term)
  202. if self.loan_term - rounded_term > 0:
  203. # TODO Handle this case
  204. raise NotImplementedError(
  205. _(
  206. "Calculation on non entire year "
  207. "hasn't been implemented yet"
  208. )
  209. )