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.

371 lines
14 KiB

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