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.

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