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.

325 lines
15 KiB

6 years ago
6 years ago
6 years ago
6 years ago
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2019 Coop IT Easy SCRL fs
  3. # Houssine Bakkali <houssine@coopiteasy.be>
  4. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
  5. from datetime import datetime
  6. from odoo import api, fields, models, _
  7. from odoo.exceptions import ValidationError
  8. class operation_request(models.Model):
  9. _name = 'operation.request'
  10. _description = "Operation request"
  11. def get_date_now(self):
  12. # fixme odoo 12 uses date types
  13. return datetime.strftime(datetime.now(), '%Y-%m-%d')
  14. @api.multi
  15. @api.depends('share_product_id', 'share_product_id.list_price', 'quantity')
  16. def _compute_subscription_amount(self):
  17. for operation_request in self:
  18. operation_request.subscription_amount = (operation_request.
  19. share_product_id.
  20. list_price *
  21. operation_request.
  22. quantity)
  23. request_date = fields.Date(string='Request date',
  24. default=lambda self: self.get_date_now())
  25. partner_id = fields.Many2one('res.partner',
  26. string='Cooperator',
  27. domain=[('member', '=', True)],
  28. required=True)
  29. partner_id_to = fields.Many2one('res.partner',
  30. string='Transfered to',
  31. domain=[('cooperator', '=', True)])
  32. operation_type = fields.Selection([('subscription', 'Subscription'),
  33. ('transfer', 'Transfer'),
  34. ('sell_back', 'Sell Back'),
  35. ('convert', 'Conversion')],
  36. string='Operation Type',
  37. required=True)
  38. share_product_id = fields.Many2one('product.product',
  39. string='Share type',
  40. domain=[('is_share', '=', True)],
  41. required=True)
  42. share_to_product_id = fields.Many2one('product.product',
  43. string='Convert to this share type',
  44. domain=[('is_share', '=', True)])
  45. share_short_name = fields.Char(related='share_product_id.short_name',
  46. string='Share type name')
  47. share_to_short_name = fields.Char(related='share_to_product_id.short_name',
  48. string='Share to type name')
  49. share_unit_price = fields.Float(related='share_product_id.list_price',
  50. string='Share price')
  51. share_to_unit_price = fields.Float(related='share_to_product_id.list_price',
  52. string='Share to price')
  53. subscription_amount = fields.Float(compute='_compute_subscription_amount',
  54. string='Operation amount')
  55. quantity = fields.Integer(string='Number of share',
  56. required=True)
  57. state = fields.Selection([('draft', 'Draft'),
  58. ('waiting', 'Waiting'),
  59. ('approved', 'Approved'),
  60. ('done', 'Done'),
  61. ('cancelled', 'Cancelled'),
  62. ('refused', 'Refused')],
  63. string='State',
  64. required=True,
  65. default='draft')
  66. user_id = fields.Many2one('res.users',
  67. string='Responsible',
  68. readonly=True,
  69. default=lambda self: self.env.user)
  70. subscription_request = fields.One2many('subscription.request',
  71. 'operation_request_id',
  72. string="Share Receiver Info",
  73. help="In case on a transfer of"
  74. " share. If the share receiver"
  75. " isn't a effective member then a"
  76. " subscription form should"
  77. " be filled.")
  78. receiver_not_member = fields.Boolean(string='Receiver is not a member')
  79. company_id = fields.Many2one('res.company',
  80. string='Company',
  81. required=True,
  82. change_default=True,
  83. readonly=True,
  84. default=lambda self: self.env['res.company']._company_default_get())
  85. invoice = fields.Many2one('account.invoice',
  86. string="Invoice")
  87. @api.multi
  88. def approve_operation(self):
  89. for rec in self:
  90. rec.write({'state': 'approved'})
  91. @api.multi
  92. def refuse_operation(self):
  93. for rec in self:
  94. rec.write({'state': 'refused'})
  95. @api.multi
  96. def submit_operation(self):
  97. for rec in self:
  98. rec.validate()
  99. rec.write({'state': 'waiting'})
  100. @api.multi
  101. def cancel_operation(self):
  102. for rec in self:
  103. rec.write({'state': 'cancelled'})
  104. @api.multi
  105. def reset_to_draft(self):
  106. for rec in self:
  107. rec.write({'state': 'draft'})
  108. def get_total_share_dic(self, partner):
  109. total_share_dic = {}
  110. share_products = self.env['product.product'].search([('is_share', '=', True)])
  111. for share_product in share_products:
  112. total_share_dic[share_product.id] = 0
  113. for line in partner.share_ids:
  114. total_share_dic[line.share_product_id.id] += line.share_number
  115. return total_share_dic
  116. # This function doesn't handle the case of a cooperator can own
  117. # different kinds of share type
  118. def hand_share_over(self, partner, share_product_id, quantity):
  119. if not partner.member:
  120. raise ValidationError(_("This operation can't be executed if the"
  121. " cooperator is not an effective member"))
  122. share_ind = len(partner.share_ids)
  123. i = 1
  124. while quantity > 0:
  125. line = self.partner_id.share_ids[share_ind-i]
  126. if line.share_product_id.id == share_product_id.id:
  127. if quantity > line.share_number:
  128. quantity -= line.share_number
  129. line.unlink()
  130. else:
  131. share_left = line.share_number - quantity
  132. quantity = 0
  133. line.write({'share_number': share_left})
  134. i += 1
  135. # if the cooperator sold all his shares he's no more
  136. # an effective member
  137. remaning_share_dict = 0
  138. for share_quant in self.get_total_share_dic(partner).values():
  139. remaning_share_dict += share_quant
  140. if remaning_share_dict == 0:
  141. self.partner_id.write({'member': False, 'old_member': True})
  142. def has_share_type(self):
  143. for line in self.partner_id.share_ids:
  144. if line.share_product_id.id == self.share_product_id.id:
  145. return True
  146. return False
  147. def validate(self):
  148. if not self.has_share_type() and \
  149. self.operation_type in ['sell_back', 'transfer']:
  150. raise ValidationError(_("The cooperator doesn't own this share"
  151. " type. Please choose the appropriate"
  152. " share type."))
  153. if self.operation_type in ['sell_back', 'convert', 'transfer']:
  154. total_share_dic = self.get_total_share_dic(self.partner_id)
  155. if self.quantity > total_share_dic[self.share_product_id.id]:
  156. raise ValidationError(_("The cooperator can't hand over more"
  157. " shares that he/she owns."))
  158. if self.operation_type == 'convert':
  159. if self.company_id.unmix_share_type:
  160. if self.share_product_id.code == self.share_to_product_id.code:
  161. raise ValidationError(_("You can't convert the share to"
  162. " the same share type."))
  163. if self.subscription_amount != self.partner_id.total_value:
  164. raise ValidationError(_("You must convert all the shares"
  165. " to the selected type."))
  166. else:
  167. if self.subscription_amount != self.partner_id.total_value:
  168. raise ValidationError(_("Converting just part of the"
  169. " shares is not yet implemented"))
  170. elif self.operation_type == 'transfer':
  171. if not self.receiver_not_member and self.company_id.unmix_share_type \
  172. and (self.partner_id_to.cooperator_type
  173. and self.partner_id.cooperator_type != self.partner_id_to.cooperator_type):
  174. raise ValidationError(_("This share type could not be"
  175. " transfered to " +
  176. self.partner_id_to.name))
  177. if self.receiver_not_member and self.subscription_request \
  178. and not self.subscription_request.validated:
  179. raise ValidationError(_("The information of the receiver"
  180. " are not correct. Please correct"
  181. " the information before"
  182. " submitting"))
  183. def get_share_trans_mail_template(self):
  184. return self.env.ref('easy_my_coop.email_template_share_transfer',
  185. False)
  186. def get_share_update_mail_template(self):
  187. return self.env.ref('easy_my_coop.email_template_share_update',
  188. False)
  189. def send_share_trans_mail(self, sub_register_line): # Unused argument is used in synergie project. Do not remove.
  190. cert_email_template = self.get_share_trans_mail_template()
  191. cert_email_template.send_mail(self.partner_id_to.id, False)
  192. def send_share_update_mail(self, sub_register_line): # Unused argument is used in synergie project. Do not remove.
  193. cert_email_template = self.get_share_update_mail_template()
  194. cert_email_template.send_mail(self.partner_id.id, False)
  195. def get_subscription_register_vals(self, effective_date):
  196. return {
  197. 'partner_id': self.partner_id.id, 'quantity': self.quantity,
  198. 'share_product_id': self.share_product_id.id,
  199. 'type': self.operation_type,
  200. 'share_unit_price': self.share_unit_price,
  201. 'date': effective_date,
  202. }
  203. @api.multi
  204. def execute_operation(self):
  205. self.ensure_one()
  206. effective_date = self.get_date_now()
  207. sub_request = self.env['subscription.request']
  208. self.validate()
  209. if self.state != 'approved':
  210. raise ValidationError(_("This operation must be approved"
  211. " before to be executed"))
  212. values = self.get_subscription_register_vals(effective_date)
  213. if self.operation_type == 'sell_back':
  214. self.hand_share_over(self.partner_id, self.share_product_id,
  215. self.quantity)
  216. elif self.operation_type == 'convert':
  217. amount_to_convert = self.share_unit_price * self.quantity
  218. convert_quant = int(amount_to_convert / self.share_to_product_id.list_price)
  219. remainder = amount_to_convert % self.share_to_product_id.list_price
  220. if convert_quant > 0 and remainder == 0:
  221. share_ids = self.partner_id.share_ids
  222. line = share_ids[0]
  223. if len(share_ids) > 1:
  224. share_ids[1:len(share_ids)].unlink()
  225. line.write({
  226. 'share_number': convert_quant,
  227. 'share_product_id': self.share_to_product_id.id,
  228. 'share_unit_price': self.share_to_unit_price,
  229. 'share_short_name': self.share_to_short_name
  230. })
  231. values['share_to_product_id'] = self.share_to_product_id.id
  232. values['quantity_to'] = convert_quant
  233. else:
  234. raise ValidationError(_("Converting just part of the"
  235. " shares is not yet implemented"))
  236. elif self.operation_type == 'transfer':
  237. sequence_id = self.env.ref('easy_my_coop.sequence_subscription', False)
  238. partner_vals = {'member': True}
  239. if self.receiver_not_member:
  240. partner = self.subscription_request.create_coop_partner()
  241. # get cooperator number
  242. sub_reg_num = int(sequence_id.next_by_id())
  243. partner_vals = sub_request.get_eater_vals(partner, self.share_product_id)
  244. partner_vals['cooperator_register_number'] = sub_reg_num
  245. partner.write(partner_vals)
  246. self.partner_id_to = partner
  247. else:
  248. # means an old member or cooperator candidate
  249. if not self.partner_id_to.member:
  250. if self.partner_id_to.cooperator_register_number == 0:
  251. sub_reg_num = int(sequence_id.next_by_id())
  252. partner_vals['cooperator_register_number'] = sub_reg_num
  253. partner_vals = sub_request.get_eater_vals(
  254. self.partner_id_to,
  255. self.share_product_id)
  256. partner_vals['old_member'] = False
  257. self.partner_id_to.write(partner_vals)
  258. # remove the parts to the giver
  259. self.hand_share_over(self.partner_id,
  260. self.share_product_id,
  261. self.quantity)
  262. # give the share to the receiver
  263. self.env['share.line'].create({
  264. 'share_number': self.quantity,
  265. 'partner_id': self.partner_id_to.id,
  266. 'share_product_id': self.share_product_id.id,
  267. 'share_unit_price': self.share_unit_price,
  268. 'effective_date': effective_date})
  269. values['partner_id_to'] = self.partner_id_to.id
  270. else:
  271. raise ValidationError(_("This operation is not yet"
  272. " implemented."))
  273. sequence_operation = self.env.ref('easy_my_coop.sequence_register_operation', False) #noqa
  274. sub_reg_operation = sequence_operation.next_by_id()
  275. values['name'] = sub_reg_operation
  276. values['register_number_operation'] = int(sub_reg_operation)
  277. self.write({'state': 'done'})
  278. sub_register_line = self.env['subscription.register'].create(values)
  279. # send mail to the receiver
  280. if self.operation_type == 'transfer':
  281. self.send_share_trans_mail(sub_register_line)
  282. self.send_share_update_mail(sub_register_line)