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
325 lines
15 KiB
# -*- coding: utf-8 -*-
|
|
# Copyright 2019 Coop IT Easy SCRL fs
|
|
# Houssine Bakkali <houssine@coopiteasy.be>
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class operation_request(models.Model):
|
|
_name = 'operation.request'
|
|
_description = "Operation request"
|
|
|
|
def get_date_now(self):
|
|
# fixme odoo 12 uses date types
|
|
return datetime.strftime(datetime.now(), '%Y-%m-%d')
|
|
|
|
@api.multi
|
|
@api.depends('share_product_id', 'share_product_id.list_price', 'quantity')
|
|
def _compute_subscription_amount(self):
|
|
for operation_request in self:
|
|
operation_request.subscription_amount = (operation_request.
|
|
share_product_id.
|
|
list_price *
|
|
operation_request.
|
|
quantity)
|
|
|
|
request_date = fields.Date(string='Request date',
|
|
default=lambda self: self.get_date_now())
|
|
partner_id = fields.Many2one('res.partner',
|
|
string='Cooperator',
|
|
domain=[('member', '=', True)],
|
|
required=True)
|
|
partner_id_to = fields.Many2one('res.partner',
|
|
string='Transfered to',
|
|
domain=[('cooperator', '=', True)])
|
|
operation_type = fields.Selection([('subscription', 'Subscription'),
|
|
('transfer', 'Transfer'),
|
|
('sell_back', 'Sell Back'),
|
|
('convert', 'Conversion')],
|
|
string='Operation Type',
|
|
required=True)
|
|
share_product_id = fields.Many2one('product.product',
|
|
string='Share type',
|
|
domain=[('is_share', '=', True)],
|
|
required=True)
|
|
share_to_product_id = fields.Many2one('product.product',
|
|
string='Convert to this share type',
|
|
domain=[('is_share', '=', True)])
|
|
share_short_name = fields.Char(related='share_product_id.short_name',
|
|
string='Share type name')
|
|
share_to_short_name = fields.Char(related='share_to_product_id.short_name',
|
|
string='Share to type name')
|
|
share_unit_price = fields.Float(related='share_product_id.list_price',
|
|
string='Share price')
|
|
share_to_unit_price = fields.Float(related='share_to_product_id.list_price',
|
|
string='Share to price')
|
|
subscription_amount = fields.Float(compute='_compute_subscription_amount',
|
|
string='Operation amount')
|
|
quantity = fields.Integer(string='Number of share',
|
|
required=True)
|
|
state = fields.Selection([('draft', 'Draft'),
|
|
('waiting', 'Waiting'),
|
|
('approved', 'Approved'),
|
|
('done', 'Done'),
|
|
('cancelled', 'Cancelled'),
|
|
('refused', 'Refused')],
|
|
string='State',
|
|
required=True,
|
|
default='draft')
|
|
user_id = fields.Many2one('res.users',
|
|
string='Responsible',
|
|
readonly=True,
|
|
default=lambda self: self.env.user)
|
|
subscription_request = fields.One2many('subscription.request',
|
|
'operation_request_id',
|
|
string="Share Receiver Info",
|
|
help="In case on a transfer of"
|
|
" share. If the share receiver"
|
|
" isn't a effective member then a"
|
|
" subscription form should"
|
|
" be filled.")
|
|
receiver_not_member = fields.Boolean(string='Receiver is not a member')
|
|
company_id = fields.Many2one('res.company',
|
|
string='Company',
|
|
required=True,
|
|
change_default=True,
|
|
readonly=True,
|
|
default=lambda self: self.env['res.company']._company_default_get())
|
|
|
|
invoice = fields.Many2one('account.invoice',
|
|
string="Invoice")
|
|
|
|
@api.multi
|
|
def approve_operation(self):
|
|
for rec in self:
|
|
rec.write({'state': 'approved'})
|
|
|
|
@api.multi
|
|
def refuse_operation(self):
|
|
for rec in self:
|
|
rec.write({'state': 'refused'})
|
|
|
|
@api.multi
|
|
def submit_operation(self):
|
|
for rec in self:
|
|
rec.validate()
|
|
rec.write({'state': 'waiting'})
|
|
|
|
@api.multi
|
|
def cancel_operation(self):
|
|
for rec in self:
|
|
rec.write({'state': 'cancelled'})
|
|
|
|
@api.multi
|
|
def reset_to_draft(self):
|
|
for rec in self:
|
|
rec.write({'state': 'draft'})
|
|
|
|
def get_total_share_dic(self, partner):
|
|
total_share_dic = {}
|
|
share_products = self.env['product.product'].search([('is_share', '=', True)])
|
|
|
|
for share_product in share_products:
|
|
total_share_dic[share_product.id] = 0
|
|
|
|
for line in partner.share_ids:
|
|
total_share_dic[line.share_product_id.id] += line.share_number
|
|
|
|
return total_share_dic
|
|
|
|
# This function doesn't handle the case of a cooperator can own
|
|
# different kinds of share type
|
|
def hand_share_over(self, partner, share_product_id, quantity):
|
|
if not partner.member:
|
|
raise ValidationError(_("This operation can't be executed if the"
|
|
" cooperator is not an effective member"))
|
|
|
|
share_ind = len(partner.share_ids)
|
|
i = 1
|
|
while quantity > 0:
|
|
line = self.partner_id.share_ids[share_ind-i]
|
|
if line.share_product_id.id == share_product_id.id:
|
|
if quantity > line.share_number:
|
|
quantity -= line.share_number
|
|
line.unlink()
|
|
else:
|
|
share_left = line.share_number - quantity
|
|
quantity = 0
|
|
line.write({'share_number': share_left})
|
|
i += 1
|
|
# if the cooperator sold all his shares he's no more
|
|
# an effective member
|
|
remaning_share_dict = 0
|
|
for share_quant in self.get_total_share_dic(partner).values():
|
|
remaning_share_dict += share_quant
|
|
if remaning_share_dict == 0:
|
|
self.partner_id.write({'member': False, 'old_member': True})
|
|
|
|
def has_share_type(self):
|
|
for line in self.partner_id.share_ids:
|
|
if line.share_product_id.id == self.share_product_id.id:
|
|
return True
|
|
return False
|
|
|
|
def validate(self):
|
|
if not self.has_share_type() and \
|
|
self.operation_type in ['sell_back', 'transfer']:
|
|
raise ValidationError(_("The cooperator doesn't own this share"
|
|
" type. Please choose the appropriate"
|
|
" share type."))
|
|
|
|
if self.operation_type in ['sell_back', 'convert', 'transfer']:
|
|
total_share_dic = self.get_total_share_dic(self.partner_id)
|
|
|
|
if self.quantity > total_share_dic[self.share_product_id.id]:
|
|
raise ValidationError(_("The cooperator can't hand over more"
|
|
" shares that he/she owns."))
|
|
|
|
if self.operation_type == 'convert':
|
|
if self.company_id.unmix_share_type:
|
|
if self.share_product_id.code == self.share_to_product_id.code:
|
|
raise ValidationError(_("You can't convert the share to"
|
|
" the same share type."))
|
|
if self.subscription_amount != self.partner_id.total_value:
|
|
raise ValidationError(_("You must convert all the shares"
|
|
" to the selected type."))
|
|
else:
|
|
if self.subscription_amount != self.partner_id.total_value:
|
|
raise ValidationError(_("Converting just part of the"
|
|
" shares is not yet implemented"))
|
|
elif self.operation_type == 'transfer':
|
|
if not self.receiver_not_member and self.company_id.unmix_share_type \
|
|
and (self.partner_id_to.cooperator_type
|
|
and self.partner_id.cooperator_type != self.partner_id_to.cooperator_type):
|
|
raise ValidationError(_("This share type could not be"
|
|
" transfered to " +
|
|
self.partner_id_to.name))
|
|
if self.receiver_not_member and self.subscription_request \
|
|
and not self.subscription_request.validated:
|
|
raise ValidationError(_("The information of the receiver"
|
|
" are not correct. Please correct"
|
|
" the information before"
|
|
" submitting"))
|
|
|
|
def get_share_trans_mail_template(self):
|
|
return self.env.ref('easy_my_coop.email_template_share_transfer',
|
|
False)
|
|
|
|
def get_share_update_mail_template(self):
|
|
return self.env.ref('easy_my_coop.email_template_share_update',
|
|
False)
|
|
|
|
def send_share_trans_mail(self, sub_register_line): # Unused argument is used in synergie project. Do not remove.
|
|
cert_email_template = self.get_share_trans_mail_template()
|
|
cert_email_template.send_mail(self.partner_id_to.id, False)
|
|
|
|
def send_share_update_mail(self, sub_register_line): # Unused argument is used in synergie project. Do not remove.
|
|
cert_email_template = self.get_share_update_mail_template()
|
|
cert_email_template.send_mail(self.partner_id.id, False)
|
|
|
|
def get_subscription_register_vals(self, effective_date):
|
|
return {
|
|
'partner_id': self.partner_id.id, 'quantity': self.quantity,
|
|
'share_product_id': self.share_product_id.id,
|
|
'type': self.operation_type,
|
|
'share_unit_price': self.share_unit_price,
|
|
'date': effective_date,
|
|
}
|
|
|
|
@api.multi
|
|
def execute_operation(self):
|
|
self.ensure_one()
|
|
|
|
effective_date = self.get_date_now()
|
|
sub_request = self.env['subscription.request']
|
|
|
|
self.validate()
|
|
|
|
if self.state != 'approved':
|
|
raise ValidationError(_("This operation must be approved"
|
|
" before to be executed"))
|
|
|
|
values = self.get_subscription_register_vals(effective_date)
|
|
|
|
if self.operation_type == 'sell_back':
|
|
self.hand_share_over(self.partner_id, self.share_product_id,
|
|
self.quantity)
|
|
elif self.operation_type == 'convert':
|
|
amount_to_convert = self.share_unit_price * self.quantity
|
|
convert_quant = int(amount_to_convert / self.share_to_product_id.list_price)
|
|
remainder = amount_to_convert % self.share_to_product_id.list_price
|
|
|
|
if convert_quant > 0 and remainder == 0:
|
|
share_ids = self.partner_id.share_ids
|
|
line = share_ids[0]
|
|
if len(share_ids) > 1:
|
|
share_ids[1:len(share_ids)].unlink()
|
|
line.write({
|
|
'share_number': convert_quant,
|
|
'share_product_id': self.share_to_product_id.id,
|
|
'share_unit_price': self.share_to_unit_price,
|
|
'share_short_name': self.share_to_short_name
|
|
})
|
|
values['share_to_product_id'] = self.share_to_product_id.id
|
|
values['quantity_to'] = convert_quant
|
|
else:
|
|
raise ValidationError(_("Converting just part of the"
|
|
" shares is not yet implemented"))
|
|
elif self.operation_type == 'transfer':
|
|
sequence_id = self.env.ref('easy_my_coop.sequence_subscription', False)
|
|
partner_vals = {'member': True}
|
|
if self.receiver_not_member:
|
|
partner = self.subscription_request.create_coop_partner()
|
|
# get cooperator number
|
|
sub_reg_num = int(sequence_id.next_by_id())
|
|
partner_vals = sub_request.get_eater_vals(partner, self.share_product_id)
|
|
partner_vals['cooperator_register_number'] = sub_reg_num
|
|
partner.write(partner_vals)
|
|
self.partner_id_to = partner
|
|
else:
|
|
# means an old member or cooperator candidate
|
|
if not self.partner_id_to.member:
|
|
if self.partner_id_to.cooperator_register_number == 0:
|
|
sub_reg_num = int(sequence_id.next_by_id())
|
|
partner_vals['cooperator_register_number'] = sub_reg_num
|
|
partner_vals = sub_request.get_eater_vals(
|
|
self.partner_id_to,
|
|
self.share_product_id)
|
|
partner_vals['old_member'] = False
|
|
self.partner_id_to.write(partner_vals)
|
|
# remove the parts to the giver
|
|
self.hand_share_over(self.partner_id,
|
|
self.share_product_id,
|
|
self.quantity)
|
|
# give the share to the receiver
|
|
self.env['share.line'].create({
|
|
'share_number': self.quantity,
|
|
'partner_id': self.partner_id_to.id,
|
|
'share_product_id': self.share_product_id.id,
|
|
'share_unit_price': self.share_unit_price,
|
|
'effective_date': effective_date})
|
|
values['partner_id_to'] = self.partner_id_to.id
|
|
else:
|
|
raise ValidationError(_("This operation is not yet"
|
|
" implemented."))
|
|
|
|
sequence_operation = self.env.ref('easy_my_coop.sequence_register_operation', False) #noqa
|
|
sub_reg_operation = sequence_operation.next_by_id()
|
|
|
|
values['name'] = sub_reg_operation
|
|
values['register_number_operation'] = int(sub_reg_operation)
|
|
|
|
self.write({'state': 'done'})
|
|
|
|
sub_register_line = self.env['subscription.register'].create(values)
|
|
|
|
# send mail to the receiver
|
|
if self.operation_type == 'transfer':
|
|
self.send_share_trans_mail(sub_register_line)
|
|
|
|
self.send_share_update_mail(sub_register_line)
|