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
15 KiB

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