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.

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