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.

398 lines
14 KiB

  1. # Copyright (C) 2018 - TODAY, Pavlov Media
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  3. from odoo import _, api, fields, models
  4. class Agreement(models.Model):
  5. _name = "agreement"
  6. _inherit = ["agreement", "mail.thread"]
  7. def _default_stage_id(self):
  8. return self.env.ref("agreement_legal.agreement_stage_new")
  9. # General
  10. name = fields.Char(string="Title", required=True)
  11. is_template = fields.Boolean(
  12. string="Is a Template?",
  13. default=False,
  14. copy=False,
  15. help="Make this agreement a template.",
  16. )
  17. version = fields.Integer(
  18. string="Version",
  19. default=1,
  20. copy=False,
  21. help="The versions are used to keep track of document history and "
  22. "previous versions can be referenced.",
  23. )
  24. revision = fields.Integer(
  25. string="Revision",
  26. default=0,
  27. copy=False,
  28. help="The revision will increase with every save event.",
  29. )
  30. description = fields.Text(
  31. string="Description",
  32. track_visibility="onchange",
  33. help="Description of the agreement",
  34. )
  35. dynamic_description = fields.Text(
  36. compute="_compute_dynamic_description",
  37. string="Dynamic Description",
  38. help="Compute dynamic description",
  39. )
  40. start_date = fields.Date(
  41. string="Start Date",
  42. track_visibility="onchange",
  43. help="When the agreement starts.",
  44. )
  45. end_date = fields.Date(
  46. string="End Date", track_visibility="onchange", help="When the agreement ends."
  47. )
  48. color = fields.Integer()
  49. active = fields.Boolean(
  50. string="Active",
  51. default=True,
  52. help="If unchecked, it will allow you to hide the agreement without "
  53. "removing it.",
  54. )
  55. company_signed_date = fields.Date(
  56. string="Signed on",
  57. track_visibility="onchange",
  58. help="Date the contract was signed by Company.",
  59. )
  60. partner_signed_date = fields.Date(
  61. string="Signed on",
  62. track_visibility="onchange",
  63. help="Date the contract was signed by the Partner.",
  64. )
  65. term = fields.Integer(
  66. string="Term (Months)",
  67. track_visibility="onchange",
  68. help="Number of months this agreement/contract is in effect with the "
  69. "partner.",
  70. )
  71. expiration_notice = fields.Integer(
  72. string="Exp. Notice (Days)",
  73. track_visibility="onchange",
  74. help="Number of Days before expiration to be notified.",
  75. )
  76. change_notice = fields.Integer(
  77. string="Change Notice (Days)",
  78. track_visibility="onchange",
  79. help="Number of Days to be notified before changes.",
  80. )
  81. special_terms = fields.Text(
  82. string="Special Terms",
  83. track_visibility="onchange",
  84. help="Any terms that you have agreed to and want to track on the "
  85. "agreement/contract.",
  86. )
  87. dynamic_special_terms = fields.Text(
  88. compute="_compute_dynamic_special_terms",
  89. string="Dynamic Special Terms",
  90. help="Compute dynamic special terms",
  91. )
  92. reference = fields.Char(
  93. string="Reference",
  94. copy=False,
  95. required=True,
  96. default=lambda self: _("New"),
  97. track_visibility="onchange",
  98. help="ID used for internal contract tracking.",
  99. )
  100. increase_type_id = fields.Many2one(
  101. "agreement.increasetype",
  102. string="Increase Type",
  103. track_visibility="onchange",
  104. help="The amount that certain rates may increase.",
  105. )
  106. termination_requested = fields.Date(
  107. string="Termination Requested Date",
  108. track_visibility="onchange",
  109. help="Date that a request for termination was received.",
  110. )
  111. termination_date = fields.Date(
  112. string="Termination Date",
  113. track_visibility="onchange",
  114. help="Date that the contract was terminated.",
  115. )
  116. reviewed_date = fields.Date(string="Reviewed Date", track_visibility="onchange")
  117. reviewed_user_id = fields.Many2one(
  118. "res.users", string="Reviewed By", track_visibility="onchange"
  119. )
  120. approved_date = fields.Date(string="Approved Date", track_visibility="onchange")
  121. approved_user_id = fields.Many2one(
  122. "res.users", string="Approved By", track_visibility="onchange"
  123. )
  124. currency_id = fields.Many2one("res.currency", string="Currency")
  125. partner_id = fields.Many2one(
  126. "res.partner",
  127. string="Partner",
  128. copy=True,
  129. help="The customer or vendor this agreement is related to.",
  130. )
  131. company_partner_id = fields.Many2one(
  132. "res.partner",
  133. string="Company",
  134. copy=True,
  135. default=lambda self: self.env.user.company_id.partner_id,
  136. )
  137. partner_contact_id = fields.Many2one(
  138. "res.partner",
  139. string="Partner Contact",
  140. copy=True,
  141. help="The primary partner contact (If Applicable).",
  142. )
  143. partner_contact_phone = fields.Char(
  144. related="partner_contact_id.phone", string="Phone"
  145. )
  146. partner_contact_email = fields.Char(
  147. related="partner_contact_id.email", string="Email"
  148. )
  149. company_contact_id = fields.Many2one(
  150. "res.partner",
  151. string="Company Contact",
  152. copy=True,
  153. help="The primary contact in the company.",
  154. )
  155. company_contact_phone = fields.Char(
  156. related="company_contact_id.phone", string="Phone"
  157. )
  158. company_contact_email = fields.Char(
  159. related="company_contact_id.email", string="Email"
  160. )
  161. agreement_type_id = fields.Many2one(
  162. "agreement.type",
  163. string="Agreement Type",
  164. track_visibility="onchange",
  165. help="Select the type of agreement.",
  166. )
  167. agreement_subtype_id = fields.Many2one(
  168. "agreement.subtype",
  169. string="Agreement Sub-type",
  170. track_visibility="onchange",
  171. help="Select the sub-type of this agreement. Sub-Types are related to "
  172. "agreement types.",
  173. )
  174. product_ids = fields.Many2many("product.template", string="Products & Services")
  175. payment_term_id = fields.Many2one(
  176. "account.payment.term",
  177. string="Payment Term",
  178. track_visibility="onchange",
  179. help="Terms of payments.",
  180. )
  181. assigned_user_id = fields.Many2one(
  182. "res.users",
  183. string="Assigned To",
  184. track_visibility="onchange",
  185. help="Select the user who manages this agreement.",
  186. )
  187. company_signed_user_id = fields.Many2one(
  188. "res.users",
  189. string="Signed By",
  190. track_visibility="onchange",
  191. help="The user at our company who authorized/signed the agreement or "
  192. "contract.",
  193. )
  194. partner_signed_user_id = fields.Many2one(
  195. "res.partner",
  196. string="Signed By",
  197. track_visibility="onchange",
  198. help="Contact on the account that signed the agreement/contract.",
  199. )
  200. parent_agreement_id = fields.Many2one(
  201. "agreement",
  202. string="Parent Agreement",
  203. help="Link this agreement to a parent agreement. For example if this "
  204. "agreement is an amendment to another agreement. This list will "
  205. "only show other agreements related to the same account.",
  206. )
  207. renewal_type_id = fields.Many2one(
  208. "agreement.renewaltype",
  209. string="Renewal Type",
  210. track_visibility="onchange",
  211. help="Describes what happens after the contract expires.",
  212. )
  213. recital_ids = fields.One2many(
  214. "agreement.recital", "agreement_id", string="Recitals", copy=True
  215. )
  216. sections_ids = fields.One2many(
  217. "agreement.section", "agreement_id", string="Sections", copy=True
  218. )
  219. clauses_ids = fields.One2many(
  220. "agreement.clause", "agreement_id", string="Clauses", copy=True
  221. )
  222. appendix_ids = fields.One2many(
  223. "agreement.appendix", "agreement_id", string="Appendices", copy=True
  224. )
  225. previous_version_agreements_ids = fields.One2many(
  226. "agreement",
  227. "parent_agreement_id",
  228. string="Child Agreements",
  229. copy=False,
  230. domain=[("active", "=", False)],
  231. )
  232. child_agreements_ids = fields.One2many(
  233. "agreement",
  234. "parent_agreement_id",
  235. string="Child Agreements",
  236. copy=False,
  237. domain=[("active", "=", True)],
  238. )
  239. line_ids = fields.One2many(
  240. "agreement.line", "agreement_id", string="Products/Services", copy=False
  241. )
  242. state = fields.Selection(
  243. [("draft", "Draft"), ("active", "Active"), ("inactive", "Inactive")],
  244. default="draft",
  245. track_visibility="always",
  246. )
  247. notification_address_id = fields.Many2one(
  248. "res.partner",
  249. string="Notification Address",
  250. help="The address to send notificaitons to, if different from "
  251. "customer address.(Address Type = Other)",
  252. )
  253. signed_contract_filename = fields.Char(string="Filename")
  254. signed_contract = fields.Binary(string="Signed Document", track_visibility="always")
  255. field_id = fields.Many2one(
  256. "ir.model.fields",
  257. string="Field",
  258. help="""Select target field from the related document model. If it is a
  259. relationship field you will be able to select a target field at the
  260. destination of the relationship.""",
  261. )
  262. sub_object_id = fields.Many2one(
  263. "ir.model",
  264. string="Sub-model",
  265. help="""When a relationship field is selected as first field, this
  266. field shows the document model the relationship goes to.""",
  267. )
  268. sub_model_object_field_id = fields.Many2one(
  269. "ir.model.fields",
  270. string="Sub-field",
  271. help="""When a relationship field is selected as first field, this
  272. field lets you select the target field within the destination document
  273. model (sub-model).""",
  274. )
  275. default_value = fields.Char(
  276. string="Default Value",
  277. help="Optional value to use if the target field is empty.",
  278. )
  279. copyvalue = fields.Char(
  280. string="Placeholder Expression",
  281. help="""Final placeholder expression, to be copy-pasted in the desired
  282. template field.""",
  283. )
  284. # compute the dynamic content for mako expression
  285. @api.multi
  286. def _compute_dynamic_description(self):
  287. MailTemplates = self.env["mail.template"]
  288. for agreement in self:
  289. lang = agreement.partner_id.lang or "en_US"
  290. description = MailTemplates.with_context(lang=lang)._render_template(
  291. agreement.description, "agreement", agreement.id
  292. )
  293. agreement.dynamic_description = description
  294. @api.multi
  295. def _compute_dynamic_special_terms(self):
  296. MailTemplates = self.env["mail.template"]
  297. for agreement in self:
  298. lang = agreement.partner_id.lang or "en_US"
  299. special_terms = MailTemplates.with_context(lang=lang)._render_template(
  300. agreement.special_terms, "agreement", agreement.id
  301. )
  302. agreement.dynamic_special_terms = special_terms
  303. @api.onchange("field_id", "sub_model_object_field_id", "default_value")
  304. def onchange_copyvalue(self):
  305. self.sub_object_id = False
  306. self.copyvalue = False
  307. self.sub_object_id = False
  308. if self.field_id and not self.field_id.relation:
  309. self.copyvalue = "${{object.{} or {}}}".format(
  310. self.field_id.name,
  311. self.default_value or "''",
  312. )
  313. self.sub_model_object_field_id = False
  314. if self.field_id and self.field_id.relation:
  315. self.sub_object_id = self.env["ir.model"].search(
  316. [("model", "=", self.field_id.relation)]
  317. )[0]
  318. if self.sub_model_object_field_id:
  319. self.copyvalue = "${{object.{}.{} or {}}}".format(
  320. self.field_id.name,
  321. self.sub_model_object_field_id.name,
  322. self.default_value or "''",
  323. )
  324. # Used for Kanban grouped_by view
  325. @api.model
  326. def _read_group_stage_ids(self, stages, domain, order):
  327. stage_ids = self.env["agreement.stage"].search([])
  328. return stage_ids
  329. stage_id = fields.Many2one(
  330. "agreement.stage",
  331. string="Stage",
  332. group_expand="_read_group_stage_ids",
  333. help="Select the current stage of the agreement.",
  334. track_visibility="onchange",
  335. index=True,
  336. # default=lambda self: self._default_stage_id(),
  337. )
  338. # Create New Version Button
  339. @api.multi
  340. def create_new_version(self, vals):
  341. for rec in self:
  342. if not rec.state == "draft":
  343. # Make sure status is draft
  344. rec.state = "draft"
  345. default_vals = {
  346. "name": "{} - OLD VERSION".format(rec.name),
  347. "active": False,
  348. "parent_agreement_id": rec.id,
  349. }
  350. # Make a current copy and mark it as old
  351. rec.copy(default=default_vals)
  352. # Increment the Version
  353. rec.version = rec.version + 1
  354. # Reset revision to 0 since it's a new version
  355. vals["revision"] = 0
  356. return super(Agreement, self).write(vals)
  357. def create_new_agreement(self):
  358. default_vals = {
  359. "name": "NEW",
  360. "active": True,
  361. "version": 1,
  362. "revision": 0,
  363. "state": "draft",
  364. }
  365. res = self.copy(default=default_vals)
  366. return {
  367. "res_model": "agreement",
  368. "type": "ir.actions.act_window",
  369. "view_mode": "form",
  370. "view_type": "form",
  371. "res_id": res.id,
  372. }
  373. @api.model
  374. def create(self, vals):
  375. if vals.get("reference", _("New")) == _("New"):
  376. vals["reference"] = self.env["ir.sequence"].next_by_code("agreement") or _(
  377. "New"
  378. )
  379. return super(Agreement, self).create(vals)
  380. # Increments the revision on each save action
  381. @api.multi
  382. def write(self, vals):
  383. vals["revision"] = self.revision + 1
  384. return super(Agreement, self).write(vals)