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.

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