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.

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