Browse Source

[REF] OCA pre-commit compliance

pull/84/head
robin.keunen 4 years ago
parent
commit
4065207d2c
  1. 2
      .isort.cfg
  2. 42
      README.md
  3. 100
      easy_my_coop/__manifest__.py
  4. 27
      easy_my_coop/migrations/8.0.1.0/pre-migration.py
  5. 140
      easy_my_coop/models/account_invoice.py
  6. 5
      easy_my_coop/models/account_journal.py
  7. 80
      easy_my_coop/models/company.py
  8. 1053
      easy_my_coop/models/coop.py
  9. 455
      easy_my_coop/models/operation_request.py
  10. 185
      easy_my_coop/models/partner.py
  11. 28
      easy_my_coop/models/product.py
  12. 5
      easy_my_coop/models/res_partner_bank.py
  13. 10
      easy_my_coop/report/account_invoice_report.py
  14. 10
      easy_my_coop/wizard/account_invoice_refund.py
  15. 216
      easy_my_coop/wizard/create_subscription_from_partner.py
  16. 49
      easy_my_coop/wizard/update_partner_info.py
  17. 44
      easy_my_coop/wizard/update_share_line.py
  18. 8
      easy_my_coop/wizard/validate_subscription_request.py
  19. 19
      easy_my_coop_be/__manifest__.py
  20. 19
      easy_my_coop_be/models/coop.py
  21. 14
      easy_my_coop_be/models/partner.py
  22. 46
      easy_my_coop_ch/__manifest__.py
  23. 27
      easy_my_coop_ch/models/coop.py
  24. 24
      easy_my_coop_ch/models/partner.py
  25. 63
      easy_my_coop_ch/views/certificate_template.xml
  26. 37
      easy_my_coop_dividend/__manifest__.py
  27. 237
      easy_my_coop_dividend/models/dividend.py
  28. 31
      easy_my_coop_export_xlsx/__manifest__.py
  29. 211
      easy_my_coop_export_xlsx/wizard/export_global_wizard.py
  30. 17
      easy_my_coop_fr/__manifest__.py
  31. 20
      easy_my_coop_fr/models/coop.py
  32. 16
      easy_my_coop_fr/models/partner.py
  33. 28
      easy_my_coop_loan/__manifest__.py
  34. 124
      easy_my_coop_loan/models/interest_line.py
  35. 196
      easy_my_coop_loan/models/loan.py
  36. 120
      easy_my_coop_loan/models/loan_issue_line.py
  37. 6
      easy_my_coop_loan/models/partner.py
  38. 7
      easy_my_coop_loan/tests/test_emc_loan.py
  39. 19
      easy_my_coop_loan_website/__manifest__.py
  40. 74
      easy_my_coop_loan_website/controllers/main.py
  41. 2
      easy_my_coop_taxshelter_report/__manifest__.py
  42. 6
      easy_my_coop_taxshelter_report/models/mail_template.py
  43. 82
      easy_my_coop_taxshelter_report/models/tax_shelter_declaration.py
  44. 22
      easy_my_coop_website/__manifest__.py
  45. 408
      easy_my_coop_website/controllers/main.py
  46. 23
      easy_my_coop_website_portal/__manifest__.py
  47. 303
      easy_my_coop_website_portal/controllers/main.py
  48. 33
      easy_my_coop_website_taxshelter/__manifest__.py
  49. 122
      easy_my_coop_website_taxshelter/controllers/main.py
  50. 16
      partner_age/__manifest__.py
  51. 39
      partner_age/models/partner.py
  52. 28
      theme_light/__manifest__.py
  53. 32
      website_recaptcha_reloaded/__manifest__.py
  54. 18
      website_recaptcha_reloaded/models/res_config.py
  55. 39
      website_recaptcha_reloaded/website.py

2
.isort.cfg

@ -9,4 +9,4 @@ line_length=79
known_odoo=odoo known_odoo=odoo
known_odoo_addons=odoo.addons known_odoo_addons=odoo.addons
sections=FUTURE,STDLIB,THIRDPARTY,ODOO,ODOO_ADDONS,FIRSTPARTY,LOCALFOLDER sections=FUTURE,STDLIB,THIRDPARTY,ODOO,ODOO_ADDONS,FIRSTPARTY,LOCALFOLDER
known_third_party=dateutil,phonenumbers
known_third_party=addons,cStringIO,openerp,requests,werkzeug,xlsxwriter

42
README.md

@ -1,2 +1,44 @@
# vertical-cooperative # vertical-cooperative
This repository gather odoo modules for cooperatives This repository gather odoo modules for cooperatives
# MAKE TRAVIS GREEN AGAIN
pre-commit still issues these messages. They need to be fixed.
```
************* Module easy_my_coop.models.partner
easy_my_coop/models/partner.py:56: [E8103(sql-injection), ResPartner._invoice_total] SQL injection risk. Use parameters if you can. - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#no-sql-injection
************* Module partner_age.models.partner
partner_age/models/partner.py:13: [E8103(sql-injection), ResPartner._search_age] SQL injection risk. Use parameters if you can. - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#no-sql-injection
************* Module easy_my_coop_taxshelter_report.models.tax_shelter_declaration
easy_my_coop_taxshelter_report/models/tax_shelter_declaration.py:325: [E8102(invalid-commit), TaxShelterCertificate.send_certificates] Use of cr.commit() directly - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#never-commit-the-transaction
************* Module easy_my_coop.models.account_invoice
easy_my_coop/models/account_invoice.py:11: [C8104(class-camelcase), account_invoice] Use `CamelCase` "AccountInvoice" in class name "account_invoice". You can use oca-autopep8 of https://github.com/OCA/maintainer-tools to auto fix it.
************* Module easy_my_coop.models.operation_request
easy_my_coop/models/operation_request.py:12: [C8104(class-camelcase), operation_request] Use `CamelCase` "OperationRequest" in class name "operation_request". You can use oca-autopep8 of https://github.com/OCA/maintainer-tools to auto fix it.
************* Module easy_my_coop.models.coop
easy_my_coop/models/coop.py:287: [C8108(method-compute), SubscriptionRequest] Name of compute method should start with "_compute_"
************* Module website_recaptcha_reloaded.models.res_config
website_recaptcha_reloaded/models/res_config.py:7: [C8104(class-camelcase), website_config_settings] Use `CamelCase` "WebsiteConfigSettings" in class name "website_config_settings". You can use oca-autopep8 of https://github.com/OCA/maintainer-tools to auto fix it.
************* Module easy_my_coop.models.company
easy_my_coop/models/company.py:61: [C8108(method-compute), ResCompany] Name of compute method should start with "_compute_"
pylint with mandatory checks.............................................Failed
- hook id: pylint
- exit code: 18
************* Module easy_my_coop.models.partner
easy_my_coop/models/partner.py:56: [E8103(sql-injection), ResPartner._invoice_total] SQL injection risk. Use parameters if you can. - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#no-sql-injection
************* Module partner_age.models.partner
partner_age/models/partner.py:13: [E8103(sql-injection), ResPartner._search_age] SQL injection risk. Use parameters if you can. - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#no-sql-injection
************* Module easy_my_coop.models.account_invoice
easy_my_coop/models/account_invoice.py:11: [C8104(class-camelcase), account_invoice] Use `CamelCase` "AccountInvoice" in class name "account_invoice". You can use oca-autopep8 of https://github.com/OCA/maintainer-tools to auto fix it.
************* Module easy_my_coop.models.operation_request
easy_my_coop/models/operation_request.py:12: [C8104(class-camelcase), operation_request] Use `CamelCase` "OperationRequest" in class name "operation_request". You can use oca-autopep8 of https://github.com/OCA/maintainer-tools to auto fix it.
************* Module easy_my_coop.models.coop
easy_my_coop/models/coop.py:287: [C8108(method-compute), SubscriptionRequest] Name of compute method should start with "_compute_"
************* Module website_recaptcha_reloaded.models.res_config
website_recaptcha_reloaded/models/res_config.py:7: [C8104(class-camelcase), website_config_settings] Use `CamelCase` "WebsiteConfigSettings" in class name "website_config_settings". You can use oca-autopep8 of https://github.com/OCA/maintainer-tools to auto fix it.
************* Module easy_my_coop.models.company
easy_my_coop/models/company.py:61: [C8108(method-compute), ResCompany] Name of compute method should start with "_compute_"
```

100
easy_my_coop/__manifest__.py

@ -4,59 +4,53 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{ {
'name': 'Easy My Coop',
'version': '12.0.3.0.1',
'depends': [
'base',
'web',
'sale',
'account',
'base_iban',
'product',
'partner_firstname',
'partner_contact_birthdate',
'partner_contact_address',
'email_template_config',
"name": "Easy My Coop",
"summary": "Manage your cooperative shares",
"version": "12.0.3.0.1",
"depends": [
"base",
"web",
"sale",
"account",
"base_iban",
"product",
"partner_firstname",
"partner_contact_birthdate",
"partner_contact_address",
"email_template_config",
], ],
'author': 'Coop IT Easy SCRLfs',
'category': 'Cooperative management',
'website': 'https://www.coopiteasy.be',
'license': 'AGPL-3',
'description': """
This module allows to manage the cooperator subscription and all the
cooperative business processes.
""",
'data': [
'data/easy_my_coop_data.xml',
'data/paperformat.xml',
'security/res_groups.xml',
'security/ir.model.access.csv',
'wizard/create_subscription_from_partner.xml',
'wizard/update_partner_info.xml',
'wizard/validate_subscription_request.xml',
'wizard/update_share_line.xml',
'views/subscription_request_view.xml',
'views/email_template_view.xml',
'views/res_partner_view.xml',
'views/cooperator_register_view.xml',
'views/operation_request_view.xml',
'views/account_invoice_view.xml',
'views/product_view.xml',
'views/res_company_view.xml',
'views/account_journal_view.xml',
'views/menus.xml',
'report/easy_my_coop_report.xml',
'report/layout.xml',
'report/cooperator_invoice_G002.xml',
'report/cooperator_certificat_G001.xml',
'report/cooperator_subscription_G001.xml',
'report/cooperator_register_G001.xml',
'data/mail_template_data.xml', # Must be loaded after reports
"author": "Coop IT Easy SCRLfs",
"category": "Cooperative management",
"website": "https://www.coopiteasy.be",
"license": "AGPL-3",
"data": [
"data/easy_my_coop_data.xml",
"data/paperformat.xml",
"security/res_groups.xml",
"security/ir.model.access.csv",
"wizard/create_subscription_from_partner.xml",
"wizard/update_partner_info.xml",
"wizard/validate_subscription_request.xml",
"wizard/update_share_line.xml",
"views/subscription_request_view.xml",
"views/email_template_view.xml",
"views/res_partner_view.xml",
"views/cooperator_register_view.xml",
"views/operation_request_view.xml",
"views/account_invoice_view.xml",
"views/product_view.xml",
"views/res_company_view.xml",
"views/account_journal_view.xml",
"views/menus.xml",
"report/easy_my_coop_report.xml",
"report/layout.xml",
"report/cooperator_invoice_G002.xml",
"report/cooperator_certificat_G001.xml",
"report/cooperator_subscription_G001.xml",
"report/cooperator_register_G001.xml",
"data/mail_template_data.xml", # Must be loaded after reports
], ],
'demo': [
'demo/coop.xml',
'demo/users.xml',
],
'installable': True,
'application': True,
"demo": ["demo/coop.xml", "demo/users.xml"],
"installable": True,
"application": True,
} }

27
easy_my_coop/migrations/8.0.1.0/pre-migration.py

@ -1,25 +1,25 @@
# -*- coding: utf-8 -*-
import logging
from openerp.openupgrade import openupgrade from openerp.openupgrade import openupgrade
import logging
logger = logging.getLogger('OpenUpgrade')
logger = logging.getLogger("OpenUpgrade")
column_renames = { column_renames = {
'job_sync_line': [
('adresse', 'address'),
('ville', 'city'),
('codepostal', 'zip'),
('sync_date','date'),
],
}
"job_sync_line": [
("adresse", "address"),
("ville", "city"),
("codepostal", "zip"),
("sync_date", "date"),
]
}
tables_renames = [ tables_renames = [
('job_sync_line','subscription_request'),
('job_sync',None),
('external_db',None),
("job_sync_line", "subscription_request"),
("job_sync", None),
("external_db", None),
] ]
@openupgrade.migrate() @openupgrade.migrate()
def migrate(cr, version): def migrate(cr, version):
if not version: if not version:
@ -27,4 +27,3 @@ def migrate(cr, version):
openupgrade.rename_columns(cr, column_renames) openupgrade.rename_columns(cr, column_renames)
openupgrade.rename_tables(cr, tables_renames) openupgrade.rename_tables(cr, tables_renames)

140
easy_my_coop/models/account_invoice.py

@ -8,86 +8,101 @@ from datetime import datetime
from odoo import api, fields, models from odoo import api, fields, models
class account_invoice(models.Model):
_inherit = 'account.invoice'
class AccountInvoice(models.Model):
_inherit = "account.invoice"
subscription_request = fields.Many2one('subscription.request',
string='Subscription request')
subscription_request = fields.Many2one(
"subscription.request", string="Subscription request"
)
release_capital_request = fields.Boolean( release_capital_request = fields.Boolean(
string='Release of capital request')
string="Release of capital request"
)
@api.model @api.model
def _prepare_refund(self, invoice, date_invoice=None, date=None,
description=None, journal_id=None):
values = super(account_invoice, self)._prepare_refund(
invoice, date_invoice, date,
description, journal_id)
values['release_capital_request'] = self.release_capital_request
def _prepare_refund(
self,
invoice,
date_invoice=None,
date=None,
description=None,
journal_id=None,
):
values = super(AccountInvoice, self)._prepare_refund(
invoice, date_invoice, date, description, journal_id
)
values["release_capital_request"] = self.release_capital_request
return values return values
def create_user(self, partner): def create_user(self, partner):
user_obj = self.env['res.users']
user_obj = self.env["res.users"]
email = partner.email email = partner.email
user = user_obj.search([('login', '=', email)])
user = user_obj.search([("login", "=", email)])
if not user: if not user:
user = user_obj.search([('login', '=', email),
('active', '=', False)])
user = user_obj.search(
[("login", "=", email), ("active", "=", False)]
)
if user: if user:
user.sudo().write({'active': True})
user.sudo().write({"active": True})
else: else:
user_values = {'partner_id': partner.id, 'login': email}
user_values = {"partner_id": partner.id, "login": email}
user = user_obj.sudo()._signup_create_user(user_values) user = user_obj.sudo()._signup_create_user(user_values)
user.sudo().with_context({'create_user': True}).action_reset_password()
user.sudo().with_context(
{"create_user": True}
).action_reset_password()
return user return user
def get_mail_template_certificate(self): def get_mail_template_certificate(self):
if self.partner_id.member: if self.partner_id.member:
mail_template = 'easy_my_coop.email_template_certificat_increase'
mail_template = "easy_my_coop.email_template_certificat_increase"
else: else:
mail_template = 'easy_my_coop.email_template_certificat'
mail_template = "easy_my_coop.email_template_certificat"
return self.env.ref(mail_template) return self.env.ref(mail_template)
def get_sequence_register(self): def get_sequence_register(self):
return self.env.ref('easy_my_coop.sequence_subscription', False)
return self.env.ref("easy_my_coop.sequence_subscription", False)
def get_sequence_operation(self): def get_sequence_operation(self):
return self.env.ref('easy_my_coop.sequence_register_operation', False)
return self.env.ref("easy_my_coop.sequence_register_operation", False)
def get_share_line_vals(self, line, effective_date): def get_share_line_vals(self, line, effective_date):
return { return {
'share_number': line.quantity,
'share_product_id': line.product_id.id,
'partner_id': self.partner_id.id,
'share_unit_price': line.price_unit,
'effective_date': effective_date
}
"share_number": line.quantity,
"share_product_id": line.product_id.id,
"partner_id": self.partner_id.id,
"share_unit_price": line.price_unit,
"effective_date": effective_date,
}
def get_subscription_register_vals(self, line, effective_date): def get_subscription_register_vals(self, line, effective_date):
return { return {
'partner_id': self.partner_id.id,
'quantity': line.quantity,
'share_product_id': line.product_id.id,
'share_unit_price': line.price_unit,
'date': effective_date,
'type': 'subscription'
}
"partner_id": self.partner_id.id,
"quantity": line.quantity,
"share_product_id": line.product_id.id,
"share_unit_price": line.price_unit,
"date": effective_date,
"type": "subscription",
}
def get_membership_vals(self): def get_membership_vals(self):
# flag the partner as an effective member # flag the partner as an effective member
# if not yet cooperator we generate a cooperator number # if not yet cooperator we generate a cooperator number
vals = {} vals = {}
if self.partner_id.member is False \
and self.partner_id.old_member is False:
if (
self.partner_id.member is False
and self.partner_id.old_member is False
):
sequence_id = self.get_sequence_register() sequence_id = self.get_sequence_register()
sub_reg_num = sequence_id.next_by_id() sub_reg_num = sequence_id.next_by_id()
vals = {'member': True, 'old_member': False,
'cooperator_register_number': int(sub_reg_num)
}
vals = {
"member": True,
"old_member": False,
"cooperator_register_number": int(sub_reg_num),
}
elif self.partner_id.old_member: elif self.partner_id.old_member:
vals = {'member': True, 'old_member': False}
vals = {"member": True, "old_member": False}
return vals return vals
@ -102,8 +117,8 @@ class account_invoice(models.Model):
certificate_email_template.sudo().send_mail(self.partner_id.id, False) certificate_email_template.sudo().send_mail(self.partner_id.id, False)
def set_cooperator_effective(self, effective_date): def set_cooperator_effective(self, effective_date):
sub_register_obj = self.env['subscription.register']
share_line_obj = self.env['share.line']
sub_register_obj = self.env["subscription.register"]
share_line_obj = self.env["share.line"]
certificate_email_template = self.get_mail_template_certificate() certificate_email_template = self.get_mail_template_certificate()
@ -113,10 +128,11 @@ class account_invoice(models.Model):
sub_reg_operation = sequence_operation.next_by_id() sub_reg_operation = sequence_operation.next_by_id()
for line in self.invoice_line_ids: for line in self.invoice_line_ids:
sub_reg_vals = self.get_subscription_register_vals(line,
effective_date)
sub_reg_vals['name'] = sub_reg_operation
sub_reg_vals['register_number_operation'] = int(sub_reg_operation)
sub_reg_vals = self.get_subscription_register_vals(
line, effective_date
)
sub_reg_vals["name"] = sub_reg_operation
sub_reg_vals["register_number_operation"] = int(sub_reg_operation)
sub_reg_line = sub_register_obj.create(sub_reg_vals) sub_reg_line = sub_register_obj.create(sub_reg_vals)
@ -140,13 +156,13 @@ class account_invoice(models.Model):
def get_refund_domain(self, invoice): def get_refund_domain(self, invoice):
return [ return [
('type', '=', 'out_refund'),
('origin', '=', invoice.move_name)
]
("type", "=", "out_refund"),
("origin", "=", invoice.move_name),
]
@api.multi @api.multi
def action_invoice_paid(self): def action_invoice_paid(self):
super(account_invoice, self).action_invoice_paid()
super(AccountInvoice, self).action_invoice_paid()
for invoice in self: for invoice in self:
# we check if there is an open refund for this invoice. in this # we check if there is an open refund for this invoice. in this
# case we don't run the process_subscription function as the # case we don't run the process_subscription function as the
@ -154,9 +170,12 @@ class account_invoice(models.Model):
domain = self.get_refund_domain(invoice) domain = self.get_refund_domain(invoice)
refund = self.search(domain) refund = self.search(domain)
if invoice.partner_id.cooperator \
and invoice.release_capital_request \
and invoice.type == 'out_invoice' and not refund:
if (
invoice.partner_id.cooperator
and invoice.release_capital_request
and invoice.type == "out_invoice"
and not refund
):
# take the effective date from the payment. # take the effective date from the payment.
# by default the confirmation date is the payment date # by default the confirmation date is the payment date
effective_date = datetime.now().strftime("%d/%m/%Y") effective_date = datetime.now().strftime("%d/%m/%Y")
@ -165,11 +184,14 @@ class account_invoice(models.Model):
move_line = invoice.payment_move_line_ids[0] move_line = invoice.payment_move_line_ids[0]
effective_date = move_line.date effective_date = move_line.date
invoice.subscription_request.state = 'paid'
invoice.subscription_request.state = "paid"
invoice.post_process_confirm_paid(effective_date) invoice.post_process_confirm_paid(effective_date)
# if there is a open refund we mark the subscription as cancelled # if there is a open refund we mark the subscription as cancelled
elif invoice.partner_id.cooperator \
and invoice.release_capital_request \
and invoice.type == 'out_invoice' and refund:
invoice.subscription_request.state = 'cancelled'
elif (
invoice.partner_id.cooperator
and invoice.release_capital_request
and invoice.type == "out_invoice"
and refund
):
invoice.subscription_request.state = "cancelled"
return True return True

5
easy_my_coop/models/account_journal.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Coop IT Easy SCRL fs # Copyright 2019 Coop IT Easy SCRL fs
# Houssine Bakkali <houssine@coopiteasy.be> # Houssine Bakkali <houssine@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
@ -10,5 +9,5 @@ from odoo import fields, models
class AccountJournal(models.Model): class AccountJournal(models.Model):
_inherit = "account.journal" _inherit = "account.journal"
get_cooperator_payment = fields.Boolean('Get cooperator payments?')
get_general_payment = fields.Boolean(string='Get general payments?')
get_cooperator_payment = fields.Boolean("Get cooperator payments?")
get_general_payment = fields.Boolean(string="Get general payments?")

80
easy_my_coop/models/company.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Coop IT Easy SCRL fs # Copyright 2019 Coop IT Easy SCRL fs
# Houssine Bakkali <houssine@coopiteasy.be> # Houssine Bakkali <houssine@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
@ -8,47 +7,58 @@ from odoo import api, fields, models
class ResCompany(models.Model): class ResCompany(models.Model):
_inherit = 'res.company'
_inherit = "res.company"
def _get_base_logo(self): def _get_base_logo(self):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
base_url = (
self.env["ir.config_parameter"].sudo().get_param("web.base.url")
)
self.logo_url = base_url + "/logo.png" self.logo_url = base_url + "/logo.png"
coop_email_contact = fields.Char(string="Contact email address for the"
" cooperator")
subscription_maximum_amount = fields.Float(string="Maximum authorised"
" subscription amount")
default_country_id = fields.Many2one('res.country',
string="Default country",
default=lambda self: self.country_id)
default_lang_id = fields.Many2one('res.lang',
string="Default lang")
coop_email_contact = fields.Char(
string="Contact email address for the" " cooperator"
)
subscription_maximum_amount = fields.Float(
string="Maximum authorised" " subscription amount"
)
default_country_id = fields.Many2one(
"res.country",
string="Default country",
default=lambda self: self.country_id,
)
default_lang_id = fields.Many2one("res.lang", string="Default lang")
allow_id_card_upload = fields.Boolean(string="Allow ID Card upload") allow_id_card_upload = fields.Boolean(string="Allow ID Card upload")
create_user = fields.Boolean(string="Create user for cooperator",
default=False)
create_user = fields.Boolean(
string="Create user for cooperator", default=False
)
board_representative = fields.Char(string="Board representative name") board_representative = fields.Char(string="Board representative name")
signature_scan = fields.Binary(string="Board representative signature") signature_scan = fields.Binary(string="Board representative signature")
property_cooperator_account = fields.Many2one('account.account',
company_dependent=True,
string="Cooperator Account",
domain=[('internal_type', '=', 'receivable'),
('deprecated', '=', False)],
help="This account will be"
" the default one as the"
" receivable account for the"
" cooperators",
required=True)
unmix_share_type = fields.Boolean(string="Unmix share type",
default=True,
help="If checked, A cooperator will be"
" authorised to have only one type"
" of share")
property_cooperator_account = fields.Many2one(
"account.account",
company_dependent=True,
string="Cooperator Account",
domain=[
("internal_type", "=", "receivable"),
("deprecated", "=", False),
],
help="This account will be"
" the default one as the"
" receivable account for the"
" cooperators",
required=True,
)
unmix_share_type = fields.Boolean(
string="Unmix share type",
default=True,
help="If checked, A cooperator will be"
" authorised to have only one type"
" of share",
)
display_logo1 = fields.Boolean(string="Display logo 1") display_logo1 = fields.Boolean(string="Display logo 1")
display_logo2 = fields.Boolean(string="Display logo 2") display_logo2 = fields.Boolean(string="Display logo 2")
bottom_logo1 = fields.Binary(string="Bottom logo 1") bottom_logo1 = fields.Binary(string="Bottom logo 1")
bottom_logo2 = fields.Binary(string="Bottom logo 2") bottom_logo2 = fields.Binary(string="Bottom logo 2")
logo_url = fields.Char(string="logo url",
compute="_get_base_logo")
logo_url = fields.Char(string="logo url", compute="_get_base_logo")
display_data_policy_approval = fields.Boolean( display_data_policy_approval = fields.Boolean(
help="Choose to display a data policy checkbox on the cooperator" help="Choose to display a data policy checkbox on the cooperator"
" website form." " website form."
@ -58,7 +68,7 @@ class ResCompany(models.Model):
) )
data_policy_approval_text = fields.Html( data_policy_approval_text = fields.Html(
translate=True, translate=True,
help="Text to display aside the checkbox to approve data policy."
help="Text to display aside the checkbox to approve data policy.",
) )
display_internal_rules_approval = fields.Boolean( display_internal_rules_approval = fields.Boolean(
help="Choose to display an internal rules checkbox on the" help="Choose to display an internal rules checkbox on the"
@ -69,15 +79,15 @@ class ResCompany(models.Model):
) )
internal_rules_approval_text = fields.Html( internal_rules_approval_text = fields.Html(
translate=True, translate=True,
help="Text to display aside the checkbox to approve internal rules."
help="Text to display aside the checkbox to approve internal rules.",
) )
@api.onchange('data_policy_approval_required')
@api.onchange("data_policy_approval_required")
def onchange_data_policy_approval_required(self): def onchange_data_policy_approval_required(self):
if self.data_policy_approval_required: if self.data_policy_approval_required:
self.display_data_policy_approval = True self.display_data_policy_approval = True
@api.onchange('internal_rules_approval_required')
@api.onchange("internal_rules_approval_required")
def onchange_internal_rules_approval_required(self): def onchange_internal_rules_approval_required(self):
if self.internal_rules_approval_required: if self.internal_rules_approval_required:
self.display_internal_rules_approval = True self.display_internal_rules_approval = True

1053
easy_my_coop/models/coop.py
File diff suppressed because it is too large
View File

455
easy_my_coop/models/operation_request.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Coop IT Easy SCRL fs # Copyright 2019 Coop IT Easy SCRL fs
# Houssine Bakkali <houssine@coopiteasy.be> # Houssine Bakkali <houssine@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
@ -6,123 +5,150 @@
from datetime import datetime from datetime import datetime
from odoo import api, fields, models, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
class operation_request(models.Model):
_name = 'operation.request'
class OperationRequest(models.Model):
_name = "operation.request"
_description = "Operation request" _description = "Operation request"
def get_date_now(self): def get_date_now(self):
# fixme odoo 12 uses date types # fixme odoo 12 uses date types
return datetime.strftime(datetime.now(), '%Y-%m-%d')
return datetime.strftime(datetime.now(), "%Y-%m-%d")
@api.multi @api.multi
@api.depends('share_product_id', 'share_product_id.list_price', 'quantity')
@api.depends("share_product_id", "share_product_id.list_price", "quantity")
def _compute_subscription_amount(self): def _compute_subscription_amount(self):
for operation_request in 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")
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 @api.multi
def approve_operation(self): def approve_operation(self):
for rec in self: for rec in self:
rec.write({'state': 'approved'})
rec.write({"state": "approved"})
@api.multi @api.multi
def refuse_operation(self): def refuse_operation(self):
for rec in self: for rec in self:
rec.write({'state': 'refused'})
rec.write({"state": "refused"})
@api.multi @api.multi
def submit_operation(self): def submit_operation(self):
for rec in self: for rec in self:
rec.validate() rec.validate()
rec.write({'state': 'waiting'})
rec.write({"state": "waiting"})
@api.multi @api.multi
def cancel_operation(self): def cancel_operation(self):
for rec in self: for rec in self:
rec.write({'state': 'cancelled'})
rec.write({"state": "cancelled"})
@api.multi @api.multi
def reset_to_draft(self): def reset_to_draft(self):
for rec in self: for rec in self:
rec.write({'state': 'draft'})
rec.write({"state": "draft"})
def get_total_share_dic(self, partner): def get_total_share_dic(self, partner):
total_share_dic = {} total_share_dic = {}
share_products = self.env['product.product'].search([('is_share', '=', True)])
share_products = self.env["product.product"].search(
[("is_share", "=", True)]
)
for share_product in share_products: for share_product in share_products:
total_share_dic[share_product.id] = 0 total_share_dic[share_product.id] = 0
@ -136,13 +162,17 @@ class operation_request(models.Model):
# different kinds of share type # different kinds of share type
def hand_share_over(self, partner, share_product_id, quantity): def hand_share_over(self, partner, share_product_id, quantity):
if not partner.member: if not partner.member:
raise ValidationError(_("This operation can't be executed if the"
" cooperator is not an effective member"))
raise ValidationError(
_(
"This operation can't be executed if the"
" cooperator is not an effective member"
)
)
share_ind = len(partner.share_ids) share_ind = len(partner.share_ids)
i = 1 i = 1
while quantity > 0: while quantity > 0:
line = self.partner_id.share_ids[share_ind-i]
line = self.partner_id.share_ids[share_ind - i]
if line.share_product_id.id == share_product_id.id: if line.share_product_id.id == share_product_id.id:
if quantity > line.share_number: if quantity > line.share_number:
quantity -= line.share_number quantity -= line.share_number
@ -150,7 +180,7 @@ class operation_request(models.Model):
else: else:
share_left = line.share_number - quantity share_left = line.share_number - quantity
quantity = 0 quantity = 0
line.write({'share_number': share_left})
line.write({"share_number": share_left})
i += 1 i += 1
# if the cooperator sold all his shares he's no more # if the cooperator sold all his shares he's no more
# an effective member # an effective member
@ -158,7 +188,7 @@ class operation_request(models.Model):
for share_quant in self.get_total_share_dic(partner).values(): for share_quant in self.get_total_share_dic(partner).values():
remaning_share_dict += share_quant remaning_share_dict += share_quant
if remaning_share_dict == 0: if remaning_share_dict == 0:
self.partner_id.write({'member': False, 'old_member': True})
self.partner_id.write({"member": False, "old_member": True})
def has_share_type(self): def has_share_type(self):
for line in self.partner_id.share_ids: for line in self.partner_id.share_ids:
@ -167,120 +197,181 @@ class operation_request(models.Model):
return False return False
def validate(self): 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']:
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) total_share_dic = self.get_total_share_dic(self.partner_id)
if self.quantity > total_share_dic[self.share_product_id.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':
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.company_id.unmix_share_type:
if self.share_product_id.code == self.share_to_product_id.code: 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."))
raise ValidationError(
_(
"You can't convert the share to"
" the same share type."
)
)
if self.subscription_amount != self.partner_id.total_value: if self.subscription_amount != self.partner_id.total_value:
raise ValidationError(_("You must convert all the shares"
" to the selected type."))
raise ValidationError(
_(
"You must convert all the shares"
" to the selected type."
)
)
else: else:
if self.subscription_amount != self.partner_id.total_value: 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.partner_id_to.is_company \
and not self.share_product_id.by_company:
raise ValidationError(_("This share can not be"
" subscribed by a company"))
if not self.partner_id_to.is_company \
and not self.share_product_id.by_individual:
raise ValidationError(_("This share can not be"
" subscribed an individual"))
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"))
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.partner_id_to.is_company
and not self.share_product_id.by_company
):
raise ValidationError(
_("This share can not be" " subscribed by a company")
)
if (
not self.partner_id_to.is_company
and not self.share_product_id.by_individual
):
raise ValidationError(
_("This share can not be" " subscribed an individual")
)
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): def get_share_trans_mail_template(self):
return self.env.ref('easy_my_coop.email_template_share_transfer',
False)
return self.env.ref(
"easy_my_coop.email_template_share_transfer", False
)
def get_share_update_mail_template(self): def get_share_update_mail_template(self):
return self.env.ref('easy_my_coop.email_template_share_update',
False)
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.
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 = self.get_share_trans_mail_template()
cert_email_template.send_mail(self.partner_id_to.id, False) 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.
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 = self.get_share_update_mail_template()
cert_email_template.send_mail(self.partner_id.id, False) cert_email_template.send_mail(self.partner_id.id, False)
def get_subscription_register_vals(self, effective_date): def get_subscription_register_vals(self, effective_date):
return { 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,
}
"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 @api.multi
def execute_operation(self): def execute_operation(self):
self.ensure_one() self.ensure_one()
effective_date = self.get_date_now() effective_date = self.get_date_now()
sub_request = self.env['subscription.request']
sub_request = self.env["subscription.request"]
self.validate() self.validate()
if self.state != 'approved':
raise ValidationError(_("This operation must be approved"
" before to be executed"))
if self.state != "approved":
raise ValidationError(
_("This operation must be approved" " before to be executed")
)
values = self.get_subscription_register_vals(effective_date) 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':
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 amount_to_convert = self.share_unit_price * self.quantity
convert_quant = int(amount_to_convert / self.share_to_product_id.list_price)
convert_quant = int(
amount_to_convert / self.share_to_product_id.list_price
)
remainder = 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: if convert_quant > 0 and remainder == 0:
share_ids = self.partner_id.share_ids share_ids = self.partner_id.share_ids
line = share_ids[0] line = share_ids[0]
if len(share_ids) > 1: 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
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: 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}
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: if self.receiver_not_member:
partner = self.subscription_request.create_coop_partner() partner = self.subscription_request.create_coop_partner()
# get cooperator number # get cooperator number
@ -303,33 +394,39 @@ class operation_request(models.Model):
partner_vals['old_member'] = False partner_vals['old_member'] = False
self.partner_id_to.write(partner_vals) self.partner_id_to.write(partner_vals)
# remove the parts to the giver # remove the parts to the giver
self.hand_share_over(self.partner_id,
self.share_product_id,
self.quantity)
self.hand_share_over(
self.partner_id, self.share_product_id, self.quantity
)
# give the share to the receiver # 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
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: else:
raise ValidationError(_("This operation is not yet"
" implemented."))
raise ValidationError(
_("This operation is not yet" " implemented.")
)
sequence_operation = self.env.ref('easy_my_coop.sequence_register_operation', False) #noqa
sequence_operation = self.env.ref(
"easy_my_coop.sequence_register_operation", False
) # noqa
sub_reg_operation = sequence_operation.next_by_id() sub_reg_operation = sequence_operation.next_by_id()
values['name'] = sub_reg_operation
values['register_number_operation'] = int(sub_reg_operation)
values["name"] = sub_reg_operation
values["register_number_operation"] = int(sub_reg_operation)
self.write({'state': 'done'})
self.write({"state": "done"})
sub_register_line = self.env['subscription.register'].create(values)
sub_register_line = self.env["subscription.register"].create(values)
# send mail to the receiver # send mail to the receiver
if self.operation_type == 'transfer':
if self.operation_type == "transfer":
self.send_share_trans_mail(sub_register_line) self.send_share_trans_mail(sub_register_line)
self.send_share_update_mail(sub_register_line) self.send_share_update_mail(sub_register_line)

185
easy_my_coop/models/partner.py

@ -7,7 +7,7 @@ from odoo import api, fields, models
class ResPartner(models.Model): class ResPartner(models.Model):
_inherit = 'res.partner'
_inherit = "res.partner"
@api.multi @api.multi
def _get_report_base_filename(self): def _get_report_base_filename(self):
@ -15,11 +15,11 @@ class ResPartner(models.Model):
if self.member: if self.member:
return "Cooperator Certificate - %s" % self.name return "Cooperator Certificate - %s" % self.name
else: else:
return 'unknown'
return "unknown"
@api.multi @api.multi
def _invoice_total(self): def _invoice_total(self):
account_invoice_report = self.env['account.invoice.report']
account_invoice_report = self.env["account.invoice.report"]
if not self.ids: if not self.ids:
self.total_invoiced = 0.0 self.total_invoiced = 0.0
return True return True
@ -28,7 +28,9 @@ class ResPartner(models.Model):
all_partner_ids = [] all_partner_ids = []
for partner in self: for partner in self:
# price_total is in the company currency # price_total is in the company currency
all_partners_and_children[partner] = self.search([('id', 'child_of', partner.id)]).ids
all_partners_and_children[partner] = self.search(
[("id", "child_of", partner.id)]
).ids
all_partner_ids += all_partners_and_children[partner] all_partner_ids += all_partners_and_children[partner]
# searching account.invoice.report via the orm is comparatively # searching account.invoice.report via the orm is comparatively
@ -38,30 +40,39 @@ class ResPartner(models.Model):
# the user's company access directly these elements # the user's company access directly these elements
# generate where clause to include multicompany rules # generate where clause to include multicompany rules
where_query = account_invoice_report._where_calc([
('partner_id', 'in', all_partner_ids),
('state', 'not in', ['draft', 'cancel']),
('company_id', '=', self.env.user.company_id.id),
('type', 'in', ('out_invoice', 'out_refund')),
('release_capital_request', '=', False),
])
account_invoice_report._apply_ir_rules(where_query, 'read')
where_query = account_invoice_report._where_calc(
[
("partner_id", "in", all_partner_ids),
("state", "not in", ["draft", "cancel"]),
("company_id", "=", self.env.user.company_id.id),
("type", "in", ("out_invoice", "out_refund")),
("release_capital_request", "=", False),
]
)
account_invoice_report._apply_ir_rules(where_query, "read")
from_clause, where_clause, where_clause_params = where_query.get_sql() from_clause, where_clause, where_clause_params = where_query.get_sql()
# price_total is in the company currency # price_total is in the company currency
query = """
query = (
"""
SELECT SUM(price_total) as total, partner_id SELECT SUM(price_total) as total, partner_id
FROM account_invoice_report account_invoice_report FROM account_invoice_report account_invoice_report
WHERE %s WHERE %s
GROUP BY partner_id GROUP BY partner_id
""" % where_clause
"""
% where_clause
)
self.env.cr.execute(query, where_clause_params) self.env.cr.execute(query, where_clause_params)
price_totals = self.env.cr.dictfetchall() price_totals = self.env.cr.dictfetchall()
for partner, child_ids in all_partners_and_children.items(): for partner, child_ids in all_partners_and_children.items():
partner.total_invoiced = sum(price['total'] for price in price_totals if price['partner_id'] in child_ids)
partner.total_invoiced = sum(
price["total"]
for price in price_totals
if price["partner_id"] in child_ids
)
@api.multi @api.multi
@api.depends('share_ids')
@api.depends("share_ids")
def _compute_effective_date(self): def _compute_effective_date(self):
# TODO change it to compute it from the share register # TODO change it to compute it from the share register
for partner in self: for partner in self:
@ -70,22 +81,20 @@ class ResPartner(models.Model):
@api.multi @api.multi
def _get_share_type(self): def _get_share_type(self):
shares = (
self.env['product.product']
.search([('is_share', '=', True)])
)
share_types = [
(share.default_code, share.short_name) for share in shares
]
return [('', '')] + share_types
shares = self.env["product.product"].search([("is_share", "=", True)])
share_types = [(s.default_code, s.short_name) for s in shares]
return [("", "")] + share_types
@api.multi @api.multi
@api.depends('share_ids', 'share_ids.share_product_id',
'share_ids.share_product_id.default_code',
'share_ids.share_number')
@api.depends(
"share_ids",
"share_ids.share_product_id",
"share_ids.share_product_id.default_code",
"share_ids.share_number",
)
def _compute_cooperator_type(self): def _compute_cooperator_type(self):
for partner in self: for partner in self:
share_type = ''
share_type = ""
for line in partner.share_ids: for line in partner.share_ids:
if line.share_number > 0: if line.share_number > 0:
share_type = line.share_product_id.default_code share_type = line.share_product_id.default_code
@ -93,7 +102,7 @@ class ResPartner(models.Model):
partner.cooperator_type = share_type partner.cooperator_type = share_type
@api.multi @api.multi
@api.depends('share_ids')
@api.depends("share_ids")
def _compute_share_info(self): def _compute_share_info(self):
for partner in self: for partner in self:
number_of_share = 0 number_of_share = 0
@ -104,62 +113,75 @@ class ResPartner(models.Model):
partner.number_of_share = number_of_share partner.number_of_share = number_of_share
partner.total_value = total_value partner.total_value = total_value
cooperator = fields.Boolean(string='Cooperator',
help="Check this box if this contact is a"
" cooperator (effective or not).")
member = fields.Boolean(string='Effective cooperator',
help="Check this box if this cooperator"
" is an effective member.")
coop_candidate = fields.Boolean(string="Cooperator candidate",
compute="_compute_coop_candidate",
store=True,
readonly=True)
old_member = fields.Boolean(string='Old cooperator',
help="Check this box if this cooperator is"
" no more an effective member.")
cooperator = fields.Boolean(
string="Cooperator",
help="Check this box if this contact is a"
" cooperator (effective or not).",
)
member = fields.Boolean(
string="Effective cooperator",
help="Check this box if this cooperator" " is an effective member.",
)
coop_candidate = fields.Boolean(
string="Cooperator candidate",
compute="_compute_coop_candidate",
store=True,
readonly=True,
)
old_member = fields.Boolean(
string="Old cooperator",
help="Check this box if this cooperator is"
" no more an effective member.",
)
# todo use oca partner_contact_gender # todo use oca partner_contact_gender
gender = fields.Selection([('male', 'Male'),
('female', 'Female'),
('other', 'Other')],
string='Gender')
share_ids = fields.One2many('share.line',
'partner_id',
string='Share Lines')
cooperator_register_number = fields.Integer(string='Cooperator Number')
number_of_share = fields.Integer(compute="_compute_share_info",
multi='share',
string='Number of share',
readonly=True)
total_value = fields.Float(compute="_compute_share_info",
multi='share',
string='Total value of shares',
readonly=True)
company_register_number = fields.Char(string='Company Register Number')
cooperator_type = fields.Selection(selection='_get_share_type',
compute=_compute_cooperator_type,
string='Cooperator Type',
store=True)
effective_date = fields.Date(sting="Effective Date",
compute=_compute_effective_date,
store=True)
gender = fields.Selection(
[("male", "Male"), ("female", "Female"), ("other", "Other")],
string="Gender",
)
share_ids = fields.One2many(
"share.line", "partner_id", string="Share Lines"
)
cooperator_register_number = fields.Integer(string="Cooperator Number")
number_of_share = fields.Integer(
compute="_compute_share_info",
multi="share",
string="Number of share",
readonly=True,
)
total_value = fields.Float(
compute="_compute_share_info",
multi="share",
string="Total value of shares",
readonly=True,
)
company_register_number = fields.Char(string="Company Register Number")
cooperator_type = fields.Selection(
selection="_get_share_type",
compute=_compute_cooperator_type,
string="Cooperator Type",
store=True,
)
effective_date = fields.Date(
sting="Effective Date", compute=_compute_effective_date, store=True
)
representative = fields.Boolean(string="Legal Representative") representative = fields.Boolean(string="Legal Representative")
subscription_request_ids = fields.One2many('subscription.request',
'partner_id',
string="Subscription request")
legal_form = fields.Selection([('', '')],
string="Legal form")
subscription_request_ids = fields.One2many(
"subscription.request", "partner_id", string="Subscription request"
)
legal_form = fields.Selection([("", "")], string="Legal form")
data_policy_approved = fields.Boolean(string="Approved Data Policy") data_policy_approved = fields.Boolean(string="Approved Data Policy")
internal_rules_approved = fields.Boolean(string="Approved Internal Rules") internal_rules_approved = fields.Boolean(string="Approved Internal Rules")
@api.multi @api.multi
@api.depends('subscription_request_ids.state')
@api.depends("subscription_request_ids.state")
def _compute_coop_candidate(self): def _compute_coop_candidate(self):
for partner in self: for partner in self:
if partner.member: if partner.member:
is_candidate = False is_candidate = False
else: else:
sub_requests = partner.subscription_request_ids.filtered( sub_requests = partner.subscription_request_ids.filtered(
lambda record: record.state == 'done')
lambda record: record.state == "done"
)
is_candidate = bool(sub_requests) is_candidate = bool(sub_requests)
partner.coop_candidate = is_candidate partner.coop_candidate = is_candidate
@ -167,19 +189,24 @@ class ResPartner(models.Model):
@api.multi @api.multi
def has_representative(self): def has_representative(self):
self.ensure_one() self.ensure_one()
if self.child_ids.filtered('representative'):
if self.child_ids.filtered("representative"):
return True return True
return False return False
@api.multi @api.multi
def get_representative(self): def get_representative(self):
self.ensure_one() self.ensure_one()
return self.child_ids.filtered('representative')
return self.child_ids.filtered("representative")
def get_cooperator_from_email(self, email): def get_cooperator_from_email(self, email):
return self.env['res.partner'].search([('cooperator', '=', True),
('email', '=', email)])
return self.env["res.partner"].search(
[("cooperator", "=", True), ("email", "=", email)]
)
def get_cooperator_from_crn(self, company_register_number): def get_cooperator_from_crn(self, company_register_number):
return self.env['res.partner'].search([('cooperator', '=', True),
('company_register_number', '=', company_register_number)])
return self.env["res.partner"].search(
[
("cooperator", "=", True),
("company_register_number", "=", company_register_number),
]
)

28
easy_my_coop/models/product.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Coop IT Easy SCRL fs # Copyright 2019 Coop IT Easy SCRL fs
# Houssine Bakkali <houssine@coopiteasy.be> # Houssine Bakkali <houssine@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
@ -8,7 +7,7 @@ from odoo import api, fields, models
class ProductTemplate(models.Model): class ProductTemplate(models.Model):
_inherit = 'product.template'
_inherit = "product.template"
is_share = fields.Boolean(string="Is share?") is_share = fields.Boolean(string="Is share?")
short_name = fields.Char(string="Short name") short_name = fields.Char(string="Short name")
@ -19,19 +18,24 @@ class ProductTemplate(models.Model):
by_company = fields.Boolean(string="Can be subscribed by companies?") by_company = fields.Boolean(string="Can be subscribed by companies?")
by_individual = fields.Boolean(string="Can be subscribed by individuals?") by_individual = fields.Boolean(string="Can be subscribed by individuals?")
customer = fields.Boolean(string="Become customer") customer = fields.Boolean(string="Become customer")
mail_template = fields.Many2one('mail.template',
string="Mail template")
mail_template = fields.Many2one("mail.template", string="Mail template")
@api.multi @api.multi
def get_web_share_products(self, is_company): def get_web_share_products(self, is_company):
if is_company is True: if is_company is True:
product_templates = self.env['product.template'].search([
('is_share', '=', True),
('display_on_website', '=', True),
('by_company', '=', True)])
product_templates = self.env["product.template"].search(
[
("is_share", "=", True),
("display_on_website", "=", True),
("by_company", "=", True),
]
)
else: else:
product_templates = self.env['product.template'].search([
('is_share', '=', True),
('display_on_website', '=', True),
('by_individual', '=', True)])
product_templates = self.env["product.template"].search(
[
("is_share", "=", True),
("display_on_website", "=", True),
("by_individual", "=", True),
]
)
return product_templates return product_templates

5
easy_my_coop/models/res_partner_bank.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Coop IT Easy SCRL fs # Copyright 2019 Coop IT Easy SCRL fs
# Houssine Bakkali <houssine@coopiteasy.be> # Houssine Bakkali <houssine@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
@ -8,8 +7,8 @@ from odoo import models
class ResPartnerBank(models.Model): class ResPartnerBank(models.Model):
_inherit = 'res.partner.bank'
_inherit = "res.partner.bank"
_sql_constraints = [ _sql_constraints = [
('unique_number', 'Check(1=1)', 'Account Number must be unique!'),
("unique_number", "Check(1=1)", "Account Number must be unique!")
] ]

10
easy_my_coop/report/account_invoice_report.py

@ -7,7 +7,13 @@ class AccountInvoiceReport(models.Model):
release_capital_request = fields.Boolean(string="Release capital request") release_capital_request = fields.Boolean(string="Release capital request")
def _select(self): def _select(self):
return super(AccountInvoiceReport, self)._select() + ", sub.release_capital_request as release_capital_request"
return (
super(AccountInvoiceReport, self)._select()
+ ", sub.release_capital_request as release_capital_request"
)
def _sub_select(self): def _sub_select(self):
return super(AccountInvoiceReport, self)._sub_select() + ", ai.release_capital_request as release_capital_request"
return (
super(AccountInvoiceReport, self)._sub_select()
+ ", ai.release_capital_request as release_capital_request"
)

10
easy_my_coop/wizard/account_invoice_refund.py

@ -6,14 +6,14 @@ class AccountInvoiceRefund(models.TransientModel):
_inherit = "account.invoice.refund" _inherit = "account.invoice.refund"
@api.multi @api.multi
def compute_refund(self, mode='refund'):
def compute_refund(self, mode="refund"):
result = super(AccountInvoiceRefund, self).compute_refund(mode) result = super(AccountInvoiceRefund, self).compute_refund(mode)
context = dict(self._context or {}) context = dict(self._context or {})
inv = self.env['account.invoice'].browse(context.get('active_ids'))
inv = self.env["account.invoice"].browse(context.get("active_ids"))
if inv.release_capital_request: if inv.release_capital_request:
domain = result['domain']
t = ('release_capital_request', '=', True)
domain = result["domain"]
t = ("release_capital_request", "=", True)
out = [t if e[0] == t[0] else e for e in domain] out = [t if e[0] == t[0] else e for e in domain]
result['domain'] = out
result["domain"] = out
return result return result

216
easy_my_coop/wizard/create_subscription_from_partner.py

@ -1,36 +1,40 @@
from odoo import api, fields, models, _
import odoo.addons.decimal_precision as dp
from odoo import _, api, fields, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
import odoo.addons.decimal_precision as dp
class PartnerCreateSubscription(models.TransientModel): class PartnerCreateSubscription(models.TransientModel):
_name = "partner.create.subscription" _name = "partner.create.subscription"
_description = "Create Subscription From Partner" _description = "Create Subscription From Partner"
@api.multi @api.multi
@api.onchange('share_product')
@api.onchange("share_product")
def on_change_share_type(self): def on_change_share_type(self):
self.share_qty = self.share_product.minimum_quantity self.share_qty = self.share_product.minimum_quantity
@api.model @api.model
def _default_product_id(self): def _default_product_id(self):
domain = [('is_share', '=', True),
('default_share_product', '=', True)]
active_id = self.env.context.get('active_id')
domain = [
("is_share", "=", True),
("default_share_product", "=", True),
]
active_id = self.env.context.get("active_id")
if active_id: if active_id:
partner = self.env['res.partner'].browse(active_id)
partner = self.env["res.partner"].browse(active_id)
if partner.is_company: if partner.is_company:
domain.append(('by_company', '=', True))
domain.append(("by_company", "=", True))
else: else:
domain.append(('by_individual', '=', True))
domain.append(("by_individual", "=", True))
return self.env['product.product'].search(domain)[0]
return self.env["product.product"].search(domain)[0]
def _get_representative(self): def _get_representative(self):
partner = self._get_partner() partner = self._get_partner()
if partner.is_company: if partner.is_company:
return partner.search([('parent_id', '=', partner.id),
('representative', '=', True)])
return partner.search(
[("parent_id", "=", partner.id), ("representative", "=", True)]
)
return False return False
@api.model @api.model
@ -49,8 +53,8 @@ class PartnerCreateSubscription(models.TransientModel):
@api.model @api.model
def _get_partner(self): def _get_partner(self):
active_id = self.env.context.get('active_id')
return self.env['res.partner'].browse(active_id)
active_id = self.env.context.get("active_id")
return self.env["res.partner"].browse(active_id)
@api.model @api.model
def _get_is_company(self): def _get_is_company(self):
@ -75,124 +79,140 @@ class PartnerCreateSubscription(models.TransientModel):
@api.model @api.model
def _get_possible_share(self): def _get_possible_share(self):
domain = [('is_share', '=', True)]
domain = [("is_share", "=", True)]
partner = self._get_partner() partner = self._get_partner()
if partner.is_company: if partner.is_company:
domain.append(('by_company', '=', True))
domain.append(("by_company", "=", True))
else: else:
domain.append(('by_individual', '=', True))
domain.append(("by_individual", "=", True))
return domain return domain
@api.multi @api.multi
@api.depends('share_product', 'share_qty')
@api.depends("share_product", "share_qty")
def _compute_subscription_amount(self): def _compute_subscription_amount(self):
for sub_request in self: for sub_request in self:
sub_request.subscription_amount = (sub_request.
share_product.list_price *
sub_request.share_qty)
is_company = fields.Boolean(String="Is company?",
default=_get_is_company)
cooperator = fields.Many2one('res.partner',
string="Cooperator",
default=_get_partner)
register_number = fields.Char(string="Register Company Number",
default=_get_register_number)
email = fields.Char(string="Email",
required=True,
default=_get_email)
bank_account = fields.Char(string="Bank account",
required=True,
default=_get_bank_account)
share_product = fields.Many2one('product.product',
string='Share Type',
domain=_get_possible_share,
default=_default_product_id,
required=True)
share_qty = fields.Integer(string="Share Quantity",
required=True)
share_unit_price = fields.Float(related='share_product.list_price',
string='Share price',
readonly=True)
subscription_amount = fields.Float(compute='_compute_subscription_amount',
string='Subscription amount',
digits=dp.get_precision('Account'),
readonly=True)
representative_name = fields.Char(string='Representative name',
default=_get_representative_name)
representative_email = fields.Char(string='Representative email',
default=_get_representative_email)
sub_request.subscription_amount = (
sub_request.share_product.list_price * sub_request.share_qty
)
is_company = fields.Boolean(String="Is company?", default=_get_is_company)
cooperator = fields.Many2one(
"res.partner", string="Cooperator", default=_get_partner
)
register_number = fields.Char(
string="Register Company Number", default=_get_register_number
)
email = fields.Char(string="Email", required=True, default=_get_email)
bank_account = fields.Char(
string="Bank account", required=True, default=_get_bank_account
)
share_product = fields.Many2one(
"product.product",
string="Share Type",
domain=_get_possible_share,
default=_default_product_id,
required=True,
)
share_qty = fields.Integer(string="Share Quantity", required=True)
share_unit_price = fields.Float(
related="share_product.list_price", string="Share price", readonly=True
)
subscription_amount = fields.Float(
compute="_compute_subscription_amount",
string="Subscription amount",
digits=dp.get_precision("Account"),
readonly=True,
)
representative_name = fields.Char(
string="Representative name", default=_get_representative_name
)
representative_email = fields.Char(
string="Representative email", default=_get_representative_email
)
@api.multi @api.multi
def create_subscription(self): def create_subscription(self):
sub_req = self.env['subscription.request']
partner_obj = self.env['res.partner']
sub_req = self.env["subscription.request"]
partner_obj = self.env["res.partner"]
cooperator = self.cooperator cooperator = self.cooperator
vals = {'partner_id': cooperator.id,
'share_product_id': self.share_product.id,
'ordered_parts': self.share_qty,
'cooperator': True,
'user_id': self.env.uid,
'email': self.email,
'source': 'crm',
'address': self.cooperator.street,
'zip_code': self.cooperator.zip,
'city': self.cooperator.city,
'country_id': self.cooperator.country_id.id
}
vals = {
"partner_id": cooperator.id,
"share_product_id": self.share_product.id,
"ordered_parts": self.share_qty,
"cooperator": True,
"user_id": self.env.uid,
"email": self.email,
"source": "crm",
"address": self.cooperator.street,
"zip_code": self.cooperator.zip,
"city": self.cooperator.city,
"country_id": self.cooperator.country_id.id,
}
if self.is_company: if self.is_company:
vals['company_name'] = cooperator.name
vals['company_email'] = cooperator.email
vals['name'] = '/'
vals['company_register_number'] = self.register_number
vals['is_company'] = True
vals["company_name"] = cooperator.name
vals["company_email"] = cooperator.email
vals["name"] = "/"
vals["company_register_number"] = self.register_number
vals["is_company"] = True
else: else:
vals['name'] = cooperator.name
vals["name"] = cooperator.name
coop_vals = {} coop_vals = {}
if not self._get_email(): if not self._get_email():
coop_vals['email'] = self.email
coop_vals["email"] = self.email
if not self._get_register_number(): if not self._get_register_number():
if self.is_company: if self.is_company:
coop_vals['company_register_number'] = self.register_number
coop_vals["company_register_number"] = self.register_number
if self.is_company and not self._get_representative(): if self.is_company and not self._get_representative():
representative = False representative = False
if self.representative_email: if self.representative_email:
representative = partner_obj.search( representative = partner_obj.search(
[('email', '=', self.representative_email)])
[("email", "=", self.representative_email)]
)
if representative: if representative:
if len(representative) > 1: if len(representative) > 1:
raise UserError(_('There is two different persons with '
'the same national register number. '
'Please proceed to a merge before to '
'continue'))
raise UserError(
_(
"There is two different persons with "
"the same national register number. "
"Please proceed to a merge before to "
"continue"
)
)
if representative.parent_id: if representative.parent_id:
raise UserError(_("A person can't be representative of "
"two different companies."))
raise UserError(
_(
"A person can't be representative of "
"two different companies."
)
)
representative.parent_id = cooperator.id representative.parent_id = cooperator.id
else: else:
if self.representative_email: if self.representative_email:
represent_vals = {'name': self.representative_name,
'cooperator': True,
'email': self.representative_email,
'parent_id': cooperator.id,
'representative': True}
represent_vals = {
"name": self.representative_name,
"cooperator": True,
"email": self.representative_email,
"parent_id": cooperator.id,
"representative": True,
}
partner_obj.create(represent_vals) partner_obj.create(represent_vals)
if not self._get_bank_account(): if not self._get_bank_account():
partner_bank = self.env['res.partner.bank']
partner_bank.create({'partner_id': cooperator.id,
'acc_number': self.bank_account})
vals['iban'] = self.bank_account
partner_bank = self.env["res.partner.bank"]
partner_bank.create(
{"partner_id": cooperator.id, "acc_number": self.bank_account}
)
vals["iban"] = self.bank_account
if self.is_company: if self.is_company:
representative = self._get_representative() representative = self._get_representative()
vals['name'] = representative.name
vals["name"] = representative.name
if coop_vals: if coop_vals:
cooperator.write(coop_vals) cooperator.write(coop_vals)
@ -200,10 +220,10 @@ class PartnerCreateSubscription(models.TransientModel):
new_sub_req = sub_req.create(vals) new_sub_req = sub_req.create(vals)
return { return {
'type': 'ir.actions.act_window',
'view_type': 'form, tree',
'view_mode': 'form',
'res_model': 'subscription.request',
'res_id': new_sub_req.id,
'target': 'current',
"type": "ir.actions.act_window",
"view_type": "form, tree",
"view_mode": "form",
"res_model": "subscription.request",
"res_id": new_sub_req.id,
"target": "current",
} }

49
easy_my_coop/wizard/update_partner_info.py

@ -7,8 +7,8 @@ class PartnerUpdateInfo(models.TransientModel):
@api.model @api.model
def _get_partner(self): def _get_partner(self):
active_id = self.env.context.get('active_id')
return self.env['res.partner'].browse(active_id)
active_id = self.env.context.get("active_id")
return self.env["res.partner"].browse(active_id)
@api.model @api.model
def _get_register_number(self): def _get_register_number(self):
@ -20,13 +20,13 @@ class PartnerUpdateInfo(models.TransientModel):
def _get_is_company(self): def _get_is_company(self):
return self._get_partner().is_company return self._get_partner().is_company
is_company = fields.Boolean(string="Is company",
default=_get_is_company)
register_number = fields.Char(string="Register Company Number",
default=_get_register_number)
cooperator = fields.Many2one('res.partner',
string="Cooperator",
default=_get_partner)
is_company = fields.Boolean(string="Is company", default=_get_is_company)
register_number = fields.Char(
string="Register Company Number", default=_get_register_number
)
cooperator = fields.Many2one(
"res.partner", string="Cooperator", default=_get_partner
)
all = fields.Boolean(string="Update from subscription request") all = fields.Boolean(string="Update from subscription request")
birthdate = fields.Boolean(string="Set missing birth date") birthdate = fields.Boolean(string="Set missing birth date")
legal_form = fields.Boolean(string="Set legal form") legal_form = fields.Boolean(string="Set legal form")
@ -34,41 +34,50 @@ class PartnerUpdateInfo(models.TransientModel):
@api.multi @api.multi
def update(self): def update(self):
partner_obj = self.env['res.partner']
partner_obj = self.env["res.partner"]
cooperator = self.cooperator cooperator = self.cooperator
coop_vals = {} coop_vals = {}
if self.all: if self.all:
if self.legal_form or self.representative_function: if self.legal_form or self.representative_function:
coops = partner_obj.search([('cooperator', '=', True),
('is_company', '=', True)])
coops = partner_obj.search(
[("cooperator", "=", True), ("is_company", "=", True)]
)
for coop in coops: for coop in coops:
coop_vals = {} coop_vals = {}
sub_reqs = coop.subscription_request_ids.filtered(lambda r: r.state in ['done', 'paid'])
sub_reqs = coop.subscription_request_ids.filtered(
lambda r: r.state in ["done", "paid"]
)
if sub_reqs: if sub_reqs:
sub_req = sub_reqs[0] sub_req = sub_reqs[0]
if self.legal_form: if self.legal_form:
coop_vals['legal_form'] = sub_req.company_type
coop_vals["legal_form"] = sub_req.company_type
coop.write(coop_vals) coop.write(coop_vals)
if self.representative_function: if self.representative_function:
contact = coop.get_representative() contact = coop.get_representative()
contact.function = sub_req.contact_person_function contact.function = sub_req.contact_person_function
else: else:
coops = partner_obj.search([('cooperator', '=', True),
('birthdate_date', '=', False),
('is_company', '=', False)])
coops = partner_obj.search(
[
("cooperator", "=", True),
("birthdate_date", "=", False),
("is_company", "=", False),
]
)
for coop in coops: for coop in coops:
coop_vals = {} coop_vals = {}
sub_reqs = coop.subscription_request_ids.filtered(lambda r: r.state in ['done', 'paid'])
sub_reqs = coop.subscription_request_ids.filtered(
lambda r: r.state in ["done", "paid"]
)
if sub_reqs: if sub_reqs:
sub_req = sub_reqs[0] sub_req = sub_reqs[0]
if self.birthdate: if self.birthdate:
coop_vals['birthdate_date'] = sub_req.birthdate
coop_vals["birthdate_date"] = sub_req.birthdate
coop.write(coop_vals) coop.write(coop_vals)
else: else:
if cooperator: if cooperator:
if cooperator.is_company: if cooperator.is_company:
coop_vals['company_register_number'] = self.register_number
coop_vals["company_register_number"] = self.register_number
if coop_vals: if coop_vals:
cooperator.write(coop_vals) cooperator.write(coop_vals)

44
easy_my_coop/wizard/update_share_line.py

@ -1,4 +1,4 @@
from odoo import api, fields, models, _
from odoo import _, api, fields, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
@ -8,8 +8,8 @@ class ShareLineUpdateInfo(models.TransientModel):
@api.model @api.model
def _get_share_line(self): def _get_share_line(self):
active_id = self.env.context.get('active_id')
return self.env['share.line'].browse(active_id)
active_id = self.env.context.get("active_id")
return self.env["share.line"].browse(active_id)
@api.model @api.model
def _get_effective_date(self): def _get_effective_date(self):
@ -17,14 +17,15 @@ class ShareLineUpdateInfo(models.TransientModel):
return share_line.effective_date return share_line.effective_date
effective_date = fields.Date(string="effective date",
required=True,
default=_get_effective_date)
cooperator = fields.Many2one(related='share_line.partner_id',
string="Cooperator")
share_line = fields.Many2one('share.line',
string="Share line",
default=_get_share_line)
effective_date = fields.Date(
string="effective date", required=True, default=_get_effective_date
)
cooperator = fields.Many2one(
related="share_line.partner_id", string="Cooperator"
)
share_line = fields.Many2one(
"share.line", string="Share line", default=_get_share_line
)
@api.multi @api.multi
def update(self): def update(self):
@ -32,15 +33,22 @@ class ShareLineUpdateInfo(models.TransientModel):
line = self.share_line line = self.share_line
cooperator = line.partner_id cooperator = line.partner_id
sub_reg = self.env['subscription.register'].search(
[('partner_id', '=', cooperator.id),
('share_product_id', '=', line.share_product_id.id),
('quantity', '=', line.share_number),
('date', '=', line.effective_date)])
sub_reg = self.env["subscription.register"].search(
[
("partner_id", "=", cooperator.id),
("share_product_id", "=", line.share_product_id.id),
("quantity", "=", line.share_number),
("date", "=", line.effective_date),
]
)
if sub_reg: if sub_reg:
if len(sub_reg) > 1: if len(sub_reg) > 1:
raise UserError(_("Error the update return more than one"
" subscription register lines."))
raise UserError(
_(
"Error the update return more than one"
" subscription register lines."
)
)
else: else:
line.effective_date = self.effective_date line.effective_date = self.effective_date
sub_reg.date = self.effective_date sub_reg.date = self.effective_date

8
easy_my_coop/wizard/validate_subscription_request.py

@ -7,10 +7,12 @@ class ValidateSubscriptionRequest(models.TransientModel):
@api.multi @api.multi
def validate(self): def validate(self):
selected_requests = self.env['subscription.request'].browse(
self._context.get('active_ids'))
selected_requests = self.env["subscription.request"].browse(
self._context.get("active_ids")
)
subscription_requests = selected_requests.filtered( subscription_requests = selected_requests.filtered(
lambda record: record.state in ['draft', 'waiting'])
lambda record: record.state in ["draft", "waiting"]
)
for subscription_request in subscription_requests: for subscription_request in subscription_requests:
subscription_request.validate_subscription_request() subscription_request.validate_subscription_request()

19
easy_my_coop_be/__manifest__.py

@ -3,20 +3,15 @@
# - Houssine BAKKALI - <houssine@coopiteasy.be> # - Houssine BAKKALI - <houssine@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).# # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).#
{ {
"name": "Easy My Coop Be",
"name": "Easy My Coop Belgium",
"summary": "Easy My Coop Belgium Localization",
"version": "12.0.1.2.0", "version": "12.0.1.2.0",
"depends": ["easy_my_coop",
"l10n_be",
"l10n_be_invoice_bba",
],
"author": "Houssine BAKKALI <houssine@coopiteasy.be>",
"depends": ["easy_my_coop", "l10n_be", "l10n_be_invoice_bba"],
"author": "Coop IT Easy SCRLfs",
"category": "Cooperative management", "category": "Cooperative management",
"website": "www.coopiteasy.be", "website": "www.coopiteasy.be",
"license": "AGPL-3", "license": "AGPL-3",
"description": """
This is the belgian localization for the easy my coop module.
""",
'data': [],
'installable': True,
'application': False,
"data": [],
"installable": True,
"application": False,
} }

19
easy_my_coop_be/models/coop.py

@ -2,26 +2,25 @@ from odoo import fields, models
class SubscriptionRequest(models.Model): class SubscriptionRequest(models.Model):
_inherit = 'subscription.request'
_inherit = "subscription.request"
company_type = fields.Selection([('scrl', 'SCRL'),
('asbl', 'ASBL'),
('sprl', 'SPRL'),
('sa', 'SA')])
company_type = fields.Selection(
[("scrl", "SCRL"), ("asbl", "ASBL"), ("sprl", "SPRL"), ("sa", "SA")]
)
def get_partner_company_vals(self): def get_partner_company_vals(self):
vals = super(SubscriptionRequest, self).get_partner_company_vals() vals = super(SubscriptionRequest, self).get_partner_company_vals()
vals['out_inv_comm_algorithm'] = 'random'
vals["out_inv_comm_algorithm"] = "random"
return vals return vals
def get_partner_vals(self): def get_partner_vals(self):
vals = super(SubscriptionRequest, self).get_partner_vals() vals = super(SubscriptionRequest, self).get_partner_vals()
vals['out_inv_comm_type'] = 'bba'
vals['out_inv_comm_algorithm'] = 'random'
vals["out_inv_comm_type"] = "bba"
vals["out_inv_comm_algorithm"] = "random"
return vals return vals
def get_representative_valst(self): def get_representative_valst(self):
vals = super(SubscriptionRequest, self).get_representative_vals() vals = super(SubscriptionRequest, self).get_representative_vals()
vals['out_inv_comm_type'] = 'bba'
vals['out_inv_comm_algorithm'] = 'random'
vals["out_inv_comm_type"] = "bba"
vals["out_inv_comm_algorithm"] = "random"
return vals return vals

14
easy_my_coop_be/models/partner.py

@ -2,9 +2,13 @@ from odoo import fields, models
class ResPartner(models.Model): class ResPartner(models.Model):
_inherit = 'res.partner'
_inherit = "res.partner"
legal_form = fields.Selection(selection_add=[('scrl', 'SCRL'),
('asbl', 'ASBL'),
('sprl', 'SPRL'),
('sa', 'SA')])
legal_form = fields.Selection(
selection_add=[
("scrl", "SCRL"),
("asbl", "ASBL"),
("sprl", "SPRL"),
("sa", "SA"),
]
)

46
easy_my_coop_ch/__manifest__.py

@ -1,37 +1,19 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2013-2017 Open Architects Consulting SPRL.
# Copyright (C) 2018- Coop IT Easy SCRLfs.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# Copyright 2013-2018 Open Architects Consulting SPRL.
# Copyright 2018 Coop IT Easy SCRLfs (<http://www.coopiteasy.be>)
# - Houssine BAKKALI - <houssine@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{ {
"name": "Easy My Coop CH",
"name": "Easy My Coop Switzerland",
"summary": "Easy My Coop Switzerland localization",
"version": "12.0.1.0.2", "version": "12.0.1.0.2",
"depends": ["easy_my_coop",
"l10n_ch"],
"author": "Houssine BAKKALI <houssine@coopiteasy.be>",
"license": "AGPL-3",
"depends": ["easy_my_coop", "l10n_ch"],
"author": "Coop IT Easy SCRLfs",
"category": "Cooperative management", "category": "Cooperative management",
'webstite': "www.coopiteasy.be",
"description": """
This is the swiss localization for the easy my coop module
""",
'data': [
'views/subscription_template.xml',
'views/subscription_request_view.xml'
"webstite": "www.coopiteasy.be",
"data": [
"views/subscription_template.xml",
"views/subscription_request_view.xml",
], ],
'installable': True,
"installable": True,
} }

27
easy_my_coop_ch/models/coop.py

@ -2,21 +2,24 @@ from odoo import fields, models
class SubscriptionRequest(models.Model): class SubscriptionRequest(models.Model):
_inherit = 'subscription.request'
_inherit = "subscription.request"
company_type = fields.Selection(selection_add=[
('ei', 'Individual company'),
('snc', 'Partnership'),
('sa', 'Limited company (SA)'),
('sarl', 'Limited liability company (Ltd)'), #noqa
('sc', 'Cooperative'),
('asso', 'Association'),
('fond', 'Foundation'),
('edp', 'Company under public law')])
company_type = fields.Selection(
selection_add=[
("ei", "Individual company"),
("snc", "Partnership"),
("sa", "Limited company (SA)"),
("sarl", "Limited liability company (Ltd)"), # noqa
("sc", "Cooperative"),
("asso", "Association"),
("fond", "Foundation"),
("edp", "Company under public law"),
]
)
def get_required_field(self): def get_required_field(self):
req_fields = super(SubscriptionRequest, self).get_required_field() req_fields = super(SubscriptionRequest, self).get_required_field()
if 'iban' in req_fields:
req_fields.remove('iban')
if "iban" in req_fields:
req_fields.remove("iban")
return req_fields return req_fields

24
easy_my_coop_ch/models/partner.py

@ -2,15 +2,17 @@ from odoo import fields, models
class ResPartner(models.Model): class ResPartner(models.Model):
_inherit = 'res.partner'
_inherit = "res.partner"
legal_form = fields.Selection(selection_add=[
('ei', 'Individual company'),
('snc', 'Partnership'),
('sa', 'Limited company (SA)'),
('sarl', 'Limited liability company (Ltd)'),
('sc', 'Cooperative'),
('asso', 'Association'),
('fond', 'Foundation'),
('edp', 'Company under public law')
])
legal_form = fields.Selection(
selection_add=[
("ei", "Individual company"),
("snc", "Partnership"),
("sa", "Limited company (SA)"),
("sarl", "Limited liability company (Ltd)"),
("sc", "Cooperative"),
("asso", "Association"),
("fond", "Foundation"),
("edp", "Company under public law"),
]
)

63
easy_my_coop_ch/views/certificate_template.xml

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="certificate_i18n_fr" inherit_id="easy_my_coop.cooperator_certificat_G001_document" name="French Layout Certificate">
<xpath expr="//div[@name='label_coop_number']" position="replace">
<div name="label_coop_number" style="position:relative;top:35px;font-size:16;">
<span>Ce document atteste de la souscription de parts sociales au capital de la SAS Coopérative à Capital Variable SuperQuinquin par </span>
<b><span t-field="o.name"></span></b>
<span>, enregistré(e) sous le <b>numéro de coopérateur </b></span>
<span t-field="o.cooperator_register_number"></span>
</div>
</xpath>
<xpath expr="//div[@name='total_table']" position="after">
<div name="legal_text" style="position:relative;top:145px;font-size:12;">
<div>Ce document atteste d’une souscription en numéraire au capital d’une société, répondant à la définition communautaire de la Petite et Moyenne Entreprise, dont les titres ne sont pas admis aux négociations sur un marché d’instruments financiers français ou étranger en application de l’article 199 terdecies 0A du CGI.<br/>
Conformément aux statuts, les souscriptions de parts sociales de type A et B n’ouvre pas droit à rémunération.<br/>
La société remplit les conditions mentionnées aux c, d et e du 2° du I de l’article 199 terdecies-0 A du code général des impôts : <br/>
c) La société est soumise à l’impôt sur les sociétés dans les conditions de droit commun ;<br/>
<br/>
c bis) La société compte au moins deux salariés à la clôture de son premier exercice ou un salarié si elle est soumise à l’obligation de s’inscrire à la chambre de métiers et de l’artisanat ;<br/>
<br/>
d) La société exerce une activité commerciale, industrielle, artisanale, libérale ou agricole, à l’exclusion des activités procurant des revenus garantis en raison de l’existence d’un tarif réglementé de rachat de la production, des activités financières, des activités de gestion de patrimoine mobilier définie à l’article 885 O quater et des activités immobilières. Toutefois, les exclusions relatives à l’exercice d’une activité financière ou immobilière ne sont pas applicables aux entreprises solidaires mentionnées à l’article L. 3332-17-1 du code du travail.<br/>
La société n’exerce pas une activité de production d’électricité utilisant l’énergie radiative du soleil ;<br/>
<br/>
d bis) Les actifs de la société ne sont pas constitués de façon prépondérante de métaux précieux, d’œuvres d’art, d’objets de collection, d’antiquités, de chevaux de course ou de concours ou, sauf si l’objet même de son activité consiste en leur consommation ou en leur vente au détail, de vins ou d’alcools ;<br/>
<br/>
d ter) Les souscriptions au capital de la société confèrent aux souscripteurs les seuls droits résultant de la qualité d’actionnaire ou d’associé, à l’exclusion de toute autre contrepartie notamment sous la forme de tarifs préférentiels ou d’accès prioritaire aux biens produits ou aux services rendus par la société ;<br/>
<br/>
e) La société doit être une petite et moyenne entreprise qui satisfait à la définition des petites et moyennes entreprises qui figure à l’annexe I au règlement (CE) n° 800/2008 de la Commission du 6 août 2008 déclarant certaines catégories d’aide compatibles avec le marché commun en application des articles 87 et 88 du traité (Règlement général d’exemption par catégorie) ;<br/>
</div>
</div>
</xpath>
<xpath expr="//div[@name='board_commitee']" position="replace">
<div name="" class="col-xs-6 pull-left" style="position:relative;top:105px;font-size:20;color:black;font-family:Roboto-Regular;">
<div style="position:relative;top:105px;">
Pour le Conseil d'administration de <span t-field="o.company_id.name"/>.
</div>
<div style="position:relative;top:110px;">
<strong><span t-field="o.company_id.board_representative"/></strong>
</div>
<div style="position:relative;top:115px;">
<img t-if="o.company_id.signature_scan" t-att-src="'data:image/png;base64,%s' % o.company_id.signature_scan" style="width:240px;height:180px;padding-bottom:5px;"/>
</div>
</div>
</xpath>
</template>
<template id="capital_release_request_i18n_fr" inherit_id="easy_my_coop.theme_invoice_G002_document" name="French Layout Certificate">
<xpath expr="//p[@t-if='o.comment']" position="before">
<div class="row">
<div style="position:relative;top:225px;font-size:16;">
Votre demande de souscription de parts sociales, détaillé dans le tableau ci-dessus, a bien été prise en compte.<br/>
<br/>
Afin de valider votre enregistrement en tant que coopérateur, vous devez tout d’abord procéder au paiement de celles-ci.<br/>
<br/>
Un email contenant les instructions de paiement vous a également été envoyé.<br/>
</div>
</div>
</xpath>
</template>
</data>
</odoo>

37
easy_my_coop_dividend/__manifest__.py

@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2013-2018 Open Architects Consulting SPRL. # Copyright (C) 2013-2018 Open Architects Consulting SPRL.
# Copyright (C) 2013-2018 Coop IT Easy SCRLfs. # Copyright (C) 2013-2018 Coop IT Easy SCRLfs.
# #
@ -20,29 +18,16 @@
{ {
'name': 'Easy My Coop Dividend Engine',
'summary': """
Manage the dividend calculation for a fiscal year.
"name": "Easy My Coop Dividend Engine",
"summary": """
Manage the dividend computation for a fiscal year.
""", """,
'summary': """
This module allows to calculate the dividend of the cooperative.
""",
'author': 'Houssine BAKKALI, <houssine@coopiteasy.be>',
'license': 'AGPL-3',
'version': '9.0.1.0',
'website': "www.coopiteasy.be",
'category': 'Cooperative Management',
'depends': [
'easy_my_coop',
],
'data': [
'security/ir.model.access.csv',
'views/dividend_views.xml',
],
'installable': False,
"author": "Houssine BAKKALI, <houssine@coopiteasy.be>",
"license": "AGPL-3",
"version": "12.0.0.0.1",
"website": "www.coopiteasy.be",
"category": "Cooperative Management",
"depends": ["easy_my_coop"],
"data": ["security/ir.model.access.csv", "views/dividend_views.xml"],
"installable": False,
} }

237
easy_my_coop_dividend/models/dividend.py

@ -1,68 +1,78 @@
# -*- coding: utf-8 -*-
from __future__ import division from __future__ import division
from datetime import datetime from datetime import datetime
import openerp.addons.decimal_precision as dp
from openerp import fields, models, api
import openerp.addons.decimal_precision as dp
from openerp import api, fields, models
class dividend_year(models.Model):
_name = 'dividend.year'
class DividendYear(models.Model):
_name = "dividend.year"
@api.multi @api.multi
def _compute_dividend_info(self): def _compute_dividend_info(self):
res = {} res = {}
for dividend in self: for dividend in self:
res[dividend.id] = {'grand_total_dividend': 0.0,
'grand_total_taxes': 0.0}
res[dividend.id] = {
"grand_total_dividend": 0.0,
"grand_total_taxes": 0.0,
}
for line in dividend.dividend_ids: for line in dividend.dividend_ids:
res[dividend.id]['grand_total_dividend'] += line.dividend_amount
res[dividend.id]['grand_total_taxes'] += line.dividend_taxes
res[dividend.id][
"grand_total_dividend"
] += line.dividend_amount
res[dividend.id]["grand_total_taxes"] += line.dividend_taxes
return res return res
name = fields.Char(string='Code')
date_from = fields.Date(string='Date from')
date_to = fields.Date(string='Date to')
# fiscal_year_id = fields.Many2one('account.fiscalyear',
# string='Fiscal year')
percentage = fields.Float(string='Percentage')
withholding_tax = fields.Float(string='Withholding tax')
detailed_dividend_ids = fields.One2many('detailed.dividend.line',
'dividend_year_id',
string='Dividend lines')
dividend_ids = fields.One2many('dividend.line',
'dividend_year_id',
string='Dividend lines')
name = fields.Char(string="Code")
date_from = fields.Date(string="Date from")
date_to = fields.Date(string="Date to")
# fiscal_year_id = fields.Many2one('account.fiscalyear',
# string='Fiscal year')
percentage = fields.Float(string="Percentage")
withholding_tax = fields.Float(string="Withholding tax")
detailed_dividend_ids = fields.One2many(
"detailed.dividend.line", "dividend_year_id", string="Dividend lines"
)
dividend_ids = fields.One2many(
"dividend.line", "dividend_year_id", string="Dividend lines"
)
grand_total_dividend = fields.Float( grand_total_dividend = fields.Float(
compute=_compute_dividend_info,
string='Grand total dividend',
digits_compute=dp.get_precision('Account'))
compute=_compute_dividend_info,
string="Grand total dividend",
digits_compute=dp.get_precision("Account"),
)
grand_total_taxes = fields.Float( grand_total_taxes = fields.Float(
compute=_compute_dividend_info,
string='Grand total taxes',
digits_compute=dp.get_precision('Account'))
compute=_compute_dividend_info,
string="Grand total taxes",
digits_compute=dp.get_precision("Account"),
)
@api.multi @api.multi
def compute_dividend(self): def compute_dividend(self):
self.ensure_one() self.ensure_one()
det_div_line_obj = self.env['detailed.dividend.line']
div_line_obj = self.env['dividend.line']
res_partner_obj = self.env['res.partner']
det_div_line_obj = self.env["detailed.dividend.line"]
div_line_obj = self.env["dividend.line"]
res_partner_obj = self.env["res.partner"]
# delete lines if any # delete lines if any
detailed_dividend_ids = det_div_line_obj.search([('dividend_year_id', '=', self.id)])
detailed_dividend_ids = det_div_line_obj.search(
[("dividend_year_id", "=", self.id)]
)
detailed_dividend_ids.unlink() detailed_dividend_ids.unlink()
dividend_ids = div_line_obj.search([('dividend_year_id', '=', self.id)])
dividend_ids = div_line_obj.search(
[("dividend_year_id", "=", self.id)]
)
dividend_ids.unlink() dividend_ids.unlink()
partner_ids = res_partner_obj.search([
('cooperator', '=', True),
('member', '=', True)],
order='cooperator_register_number')
number_of_days = (datetime.strptime(self.date_to, '%Y-%m-%d')
- datetime.strptime(self.date_from, '%Y-%m-%d')
).days + 1
partner_ids = res_partner_obj.search(
[("cooperator", "=", True), ("member", "=", True)],
order="cooperator_register_number",
)
number_of_days = (
datetime.strptime(self.date_to, "%Y-%m-%d")
- datetime.strptime(self.date_from, "%Y-%m-%d")
).days + 1
for partner in partner_ids: for partner in partner_ids:
total_amount_dividend = 0.0 total_amount_dividend = 0.0
@ -70,57 +80,71 @@ class dividend_year(models.Model):
vals = {} vals = {}
vals2 = {} vals2 = {}
line_id = False line_id = False
if line.effective_date >= self.date_from \
and line.effective_date <= self.date_to:
date_res = (datetime.strptime(self.date_to, '%Y-%m-%d')
- datetime.strptime(line.effective_date, '%Y-%m-%d')).days
if (
line.effective_date >= self.date_from
and line.effective_date <= self.date_to
):
date_res = (
datetime.strptime(self.date_to, "%Y-%m-%d")
- datetime.strptime(line.effective_date, "%Y-%m-%d")
).days
coeff = (date_res / number_of_days) * self.percentage coeff = (date_res / number_of_days) * self.percentage
dividend_amount = line.total_amount_line * coeff dividend_amount = line.total_amount_line * coeff
vals['days'] = date_res
vals['dividend_year_id'] = self.id
vals['coop_number'] = line.partner_id.cooperator_register_number
vals['partner_id'] = partner.id
vals['share_line_id'] = line.id
vals['coeff'] = coeff
vals['dividend_amount'] = dividend_amount
vals["days"] = date_res
vals["dividend_year_id"] = self.id
vals[
"coop_number"
] = line.partner_id.cooperator_register_number
vals["partner_id"] = partner.id
vals["share_line_id"] = line.id
vals["coeff"] = coeff
vals["dividend_amount"] = dividend_amount
total_amount_dividend += dividend_amount total_amount_dividend += dividend_amount
line_id = det_div_line_obj.create(vals) line_id = det_div_line_obj.create(vals)
elif line.effective_date < self.date_from: elif line.effective_date < self.date_from:
dividend_amount = line.total_amount_line * self.percentage dividend_amount = line.total_amount_line * self.percentage
vals['days'] = number_of_days
vals['dividend_year_id'] = self.id
vals['coop_number'] = line.partner_id.cooperator_register_number
vals['partner_id'] = partner.id
vals['share_line_id'] = line.id
vals['coeff'] = self.percentage
vals['dividend_amount'] = dividend_amount
vals["days"] = number_of_days
vals["dividend_year_id"] = self.id
vals[
"coop_number"
] = line.partner_id.cooperator_register_number
vals["partner_id"] = partner.id
vals["share_line_id"] = line.id
vals["coeff"] = self.percentage
vals["dividend_amount"] = dividend_amount
total_amount_dividend += dividend_amount total_amount_dividend += dividend_amount
line_id = det_div_line_obj.create(vals) line_id = det_div_line_obj.create(vals)
if line_id: if line_id:
vals2['coop_number'] = line.partner_id.cooperator_register_number
vals2['dividend_year_id'] = self.id
vals2['partner_id'] = line.partner_id.id
vals2[
"coop_number"
] = line.partner_id.cooperator_register_number
vals2["dividend_year_id"] = self.id
vals2["partner_id"] = line.partner_id.id
vals2['dividend_amount_net'] = total_amount_dividend
vals2['dividend_amount'] = total_amount_dividend
vals2["dividend_amount_net"] = total_amount_dividend
vals2["dividend_amount"] = total_amount_dividend
# TODO set as a parameter on dividend year object # TODO set as a parameter on dividend year object
if total_amount_dividend <= 190.00: if total_amount_dividend <= 190.00:
vals2['dividend_taxes'] = 0.0
vals2["dividend_taxes"] = 0.0
else: else:
div_tax = (total_amount_dividend - 190) * self.withholding_tax
vals2['dividend_taxes'] = div_tax
vals2['dividend_amount_net'] = total_amount_dividend - div_tax
div_tax = (
total_amount_dividend - 190
) * self.withholding_tax
vals2["dividend_taxes"] = div_tax
vals2["dividend_amount_net"] = (
total_amount_dividend - div_tax
)
div_line_obj.create(vals2) div_line_obj.create(vals2)
return True return True
class DetailedDividendLine(models.Model): class DetailedDividendLine(models.Model):
_name = 'detailed.dividend.line'
_name = "detailed.dividend.line"
@api.multi @api.multi
def _compute_total_line(self): def _compute_total_line(self):
@ -129,62 +153,61 @@ class DetailedDividendLine(models.Model):
res[line.id] = line.share_unit_price * line.share_number res[line.id] = line.share_unit_price * line.share_number
return res return res
dividend_year_id = fields.Many2one('dividend.year',
string='Dividend year')
coop_number = fields.Integer(string='Cooperator Number')
days = fields.Integer(string='Days')
partner_id = fields.Many2one('res.partner',
string='Cooperator',
readonly=True)
share_line_id = fields.Many2one('share.line',
string='Share line',
readonly=True)
share_number = fields.Integer(related='share_line_id.share_number',
string='Number of Share')
dividend_year_id = fields.Many2one("dividend.year", string="Dividend year")
coop_number = fields.Integer(string="Cooperator Number")
days = fields.Integer(string="Days")
partner_id = fields.Many2one(
"res.partner", string="Cooperator", readonly=True
)
share_line_id = fields.Many2one(
"share.line", string="Share line", readonly=True
)
share_number = fields.Integer(
related="share_line_id.share_number", string="Number of Share"
)
share_unit_price = fields.Monetary( share_unit_price = fields.Monetary(
string='Share unit price',
related='share_line_id.share_unit_price',
string="Share unit price", related="share_line_id.share_unit_price"
)
effective_date = fields.Date(
related="share_line_id.effective_date", string="Effective date"
) )
effective_date = fields.Date(related='share_line_id.effective_date',
string='Effective date')
total_amount_line = fields.Monetary( total_amount_line = fields.Monetary(
string="Total value of share", string="Total value of share",
currency_field="company_currency_id", currency_field="company_currency_id",
compute=_compute_total_line, compute=_compute_total_line,
readonly=True, readonly=True,
) )
coeff = fields.Float(string='Coefficient to apply',
digits=(2, 4))
dividend_amount = fields.Float(string='Gross Dividend')
dividend_amount_net = fields.Float(string='Dividend net')
dividend_taxes = fields.Float(string='Taxes')
coeff = fields.Float(string="Coefficient to apply", digits=(2, 4))
dividend_amount = fields.Float(string="Gross Dividend")
dividend_amount_net = fields.Float(string="Dividend net")
dividend_taxes = fields.Float(string="Taxes")
company_currency_id = fields.Many2one( company_currency_id = fields.Many2one(
related="share_line_id.company_currency_id",
readonly=True,
related="share_line_id.company_currency_id", readonly=True
) )
class dividend_line(models.Model):
_name = 'dividend.line'
class DividendLine(models.Model):
_name = "dividend.line"
@api.multi @api.multi
def _get_account_number(self): def _get_account_number(self):
res = {} res = {}
for line in self: for line in self:
bank_accounts = self.env['res.partner.bank'].search(
[('partner_id', '=', line.partner_id.id)])
bank_accounts = self.env["res.partner.bank"].search(
[("partner_id", "=", line.partner_id.id)]
)
res[line.id] = bank_accounts[0].acc_number res[line.id] = bank_accounts[0].acc_number
return res return res
coop_number = fields.Integer(string='Coop Number')
dividend_year_id = fields.Many2one('dividend.year',
string='Dividend year')
partner_id = fields.Many2one('res.partner',
string='Cooperator',
readonly=True)
account_number = fields.Char(compute=_get_account_number,
string='Account Number')
dividend_amount = fields.Float(string='Gross Dividend')
dividend_amount_net = fields.Float(string='Dividend net')
dividend_taxes = fields.Float(string='Taxes')
coop_number = fields.Integer(string="Coop Number")
dividend_year_id = fields.Many2one("dividend.year", string="Dividend year")
partner_id = fields.Many2one(
"res.partner", string="Cooperator", readonly=True
)
account_number = fields.Char(
compute=_get_account_number, string="Account Number"
)
dividend_amount = fields.Float(string="Gross Dividend")
dividend_amount_net = fields.Float(string="Dividend net")
dividend_taxes = fields.Float(string="Taxes")

31
easy_my_coop_export_xlsx/__manifest__.py

@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2018- Coop IT Easy SCRLfs. # Copyright (C) 2018- Coop IT Easy SCRLfs.
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@ -19,27 +17,18 @@
{ {
'name': 'Easy My Coop Export XLSX',
'summary': """
"name": "Easy My Coop Export XLSX",
"summary": """
Generate a xlsx file with information on current state of subscription Generate a xlsx file with information on current state of subscription
request, cooperators and capital release request. request, cooperators and capital release request.
""", """,
"author": "Coop IT Easy SCRLfs", "author": "Coop IT Easy SCRLfs",
'license': 'AGPL-3',
'version': '9.0.1.0',
'website': "www.coopiteasy.be",
'category': 'Cooperative Management',
'depends': [
'easy_my_coop',
],
'external_dependencies': {
'python': ['xlsxwriter'],
},
'data': [
'wizard/export_global_wizard.xml',
],
'installable': False,
"license": "AGPL-3",
"version": "12.0.0.0.1",
"website": "www.coopiteasy.be",
"category": "Cooperative Management",
"depends": ["easy_my_coop"],
"external_dependencies": {"python": ["xlsxwriter"]},
"data": ["wizard/export_global_wizard.xml"],
"installable": False,
} }

211
easy_my_coop_export_xlsx/wizard/export_global_wizard.py

@ -1,53 +1,50 @@
# -*- encoding: utf-8 -*-
from openerp import fields, models, api
import time
from cStringIO import StringIO
import base64 import base64
import time
import xlsxwriter import xlsxwriter
from cStringIO import StringIO
from openerp import api, fields, models
HEADER = [ HEADER = [
'Num. Coop',
'Nom',
'Email',
'Banque',
'Mobile',
'Adresse',
'Rue',
'Code Postal',
'Ville',
'Pays',
'Nombre de part total',
'Montant total des parts',
'Demande de liberation de capital',
'Communication',
'Nombre de part',
'Montant',
'Reception du paiement',
'Date de la souscription'
]
"Num. Coop",
"Nom",
"Email",
"Banque",
"Mobile",
"Adresse",
"Rue",
"Code Postal",
"Ville",
"Pays",
"Nombre de part total",
"Montant total des parts",
"Demande de liberation de capital",
"Communication",
"Nombre de part",
"Montant",
"Reception du paiement",
"Date de la souscription",
]
HEADER2 = [ HEADER2 = [
'Date de la souscription',
'Nom',
'Type',
'Nombre de part',
'Montant',
'Statut',
'Email',
'Mobile',
'Adresse',
'Code Postal',
'Ville',
'Pays',
]
"Date de la souscription",
"Nom",
"Type",
"Nombre de part",
"Montant",
"Statut",
"Email",
"Mobile",
"Adresse",
"Code Postal",
"Ville",
"Pays",
]
class export_global_report(models.TransientModel):
_name = 'export.global.report'
class ExportGlobalReport(models.TransientModel):
_name = "export.global.report"
name = fields.Char('Name')
name = fields.Char("Name")
def write_header(self, worksheet, headers): def write_header(self, worksheet, headers):
i = 0 i = 0
@ -58,17 +55,18 @@ class export_global_report(models.TransientModel):
@api.multi @api.multi
def export_global_report_xlsx(self): def export_global_report_xlsx(self):
partner_obj = self.env['res.partner']
invoice_obj = self.env['account.invoice']
subscription_obj = self.env['subscription.request']
partner_obj = self.env["res.partner"]
invoice_obj = self.env["account.invoice"]
subscription_obj = self.env["subscription.request"]
file_data = StringIO() file_data = StringIO()
workbook = xlsxwriter.Workbook(file_data) workbook = xlsxwriter.Workbook(file_data)
worksheet1 = workbook.add_worksheet() worksheet1 = workbook.add_worksheet()
self.write_header(worksheet1, HEADER) self.write_header(worksheet1, HEADER)
cooperators = partner_obj.search([('cooperator', '=', True),
('member', '=', True)])
cooperators = partner_obj.search(
[("cooperator", "=", True), ("member", "=", True)]
)
j = 1 j = 1
for coop in cooperators: for coop in cooperators:
@ -86,8 +84,15 @@ class export_global_report(models.TransientModel):
i += 1 i += 1
worksheet1.write(j, i, coop.phone) worksheet1.write(j, i, coop.phone)
i += 1 i += 1
address = coop.street + ' ' + coop.zip + ' ' \
+ coop.city + ' ' + coop.country_id.name
address = (
coop.street
+ " "
+ coop.zip
+ " "
+ coop.city
+ " "
+ coop.country_id.name
)
worksheet1.write(j, i, address) worksheet1.write(j, i, address)
i += 1 i += 1
worksheet1.write(j, i, coop.street) worksheet1.write(j, i, coop.street)
@ -102,8 +107,12 @@ class export_global_report(models.TransientModel):
i += 1 i += 1
worksheet1.write(j, i, coop.total_value) worksheet1.write(j, i, coop.total_value)
invoice_ids = invoice_obj.search([('release_capital_request', '=', True),
('partner_id', '=', coop.id)])
invoice_ids = invoice_obj.search(
[
("release_capital_request", "=", True),
("partner_id", "=", coop.id),
]
)
j += 1 j += 1
for invoice in invoice_ids: for invoice in invoice_ids:
i = 11 i = 11
@ -124,17 +133,27 @@ class export_global_report(models.TransientModel):
worksheet1.write(j, i, invoice.payment_ids[0].payment_date) worksheet1.write(j, i, invoice.payment_ids[0].payment_date)
i += 1 i += 1
if invoice.subscription_request: if invoice.subscription_request:
ind = len(invoice.subscription_request)-1
worksheet1.write(j, i, invoice.subscription_request[ind].date)
ind = len(invoice.subscription_request) - 1
worksheet1.write(
j, i, invoice.subscription_request[ind].date
)
j += 1 j += 1
sub_requests = subscription_obj.search([('state', 'in',
['draft', 'waiting']),
('partner_id', '=', coop.id)
])
sub_requests = subscription_obj.search(
[
("state", "in", ["draft", "waiting"]),
("partner_id", "=", coop.id),
]
)
for sub_request in sub_requests: for sub_request in sub_requests:
i = 11 i = 11
worksheet1.write(j, i, dict(subscription_obj._columns['type'].selection).get(sub_request.type,False))
worksheet1.write(
j,
i,
dict(subscription_obj._columns["type"].selection).get(
sub_request.type, False
),
)
i += 1 i += 1
worksheet1.write(j, i, sub_request.state) worksheet1.write(j, i, sub_request.state)
i += 3 i += 3
@ -149,8 +168,9 @@ class export_global_report(models.TransientModel):
worksheet1bis = workbook.add_worksheet() worksheet1bis = workbook.add_worksheet()
self.write_header(worksheet1bis, HEADER) self.write_header(worksheet1bis, HEADER)
cooperators = partner_obj.search([('cooperator', '=', True),
('member', '=', False)])
cooperators = partner_obj.search(
[("cooperator", "=", True), ("member", "=", False)]
)
j = 1 j = 1
for coop in cooperators: for coop in cooperators:
@ -175,8 +195,12 @@ class export_global_report(models.TransientModel):
i += 1 i += 1
worksheet1bis.write(j, i, coop.total_value) worksheet1bis.write(j, i, coop.total_value)
invoice_ids = invoice_obj.search([('release_capital_request', '=', True),
('partner_id', '=', coop.id)])
invoice_ids = invoice_obj.search(
[
("release_capital_request", "=", True),
("partner_id", "=", coop.id),
]
)
j += 1 j += 1
for invoice in invoice_ids: for invoice in invoice_ids:
i = 11 i = 11
@ -197,17 +221,27 @@ class export_global_report(models.TransientModel):
worksheet1bis.write(j, i, invoice.payment_ids[0].date) worksheet1bis.write(j, i, invoice.payment_ids[0].date)
i += 1 i += 1
if invoice.subscription_request: if invoice.subscription_request:
ind = len(invoice.subscription_request)-1
worksheet1bis.write(j, i, invoice.subscription_request[ind].date)
ind = len(invoice.subscription_request) - 1
worksheet1bis.write(
j, i, invoice.subscription_request[ind].date
)
j += 1 j += 1
sub_requests = subscription_obj.search([('state', 'in',
['draft', 'waiting']),
('partner_id', '=', coop.id)
])
sub_requests = subscription_obj.search(
[
("state", "in", ["draft", "waiting"]),
("partner_id", "=", coop.id),
]
)
for sub_request in sub_requests: for sub_request in sub_requests:
i = 11 i = 11
worksheet1bis.write(j, i, dict(subscription_obj._columns['type'].selection).get(sub_request.type,False))
worksheet1bis.write(
j,
i,
dict(subscription_obj._columns["type"].selection).get(
sub_request.type, False
),
)
i += 1 i += 1
worksheet1bis.write(j, i, sub_request.state) worksheet1bis.write(j, i, sub_request.state)
i += 3 i += 3
@ -222,9 +256,9 @@ class export_global_report(models.TransientModel):
worksheet2 = workbook.add_worksheet() worksheet2 = workbook.add_worksheet()
self.write_header(worksheet2, HEADER2) self.write_header(worksheet2, HEADER2)
sub_requests = subscription_obj.search([('state', 'in',
['draft', 'waiting']),
])
sub_requests = subscription_obj.search(
[("state", "in", ["draft", "waiting"])]
)
j = 1 j = 1
for sub_request in sub_requests: for sub_request in sub_requests:
@ -233,8 +267,10 @@ class export_global_report(models.TransientModel):
i += 1 i += 1
worksheet2.write(j, i, sub_request.name) worksheet2.write(j, i, sub_request.name)
i += 1 i += 1
sub_type_sel = subscription_obj._columns['type'].selection
worksheet2.write(j, i, dict(sub_type_sel).get(sub_request.type, False))
sub_type_sel = subscription_obj._columns["type"].selection
worksheet2.write(
j, i, dict(sub_type_sel).get(sub_request.type, False)
)
i += 1 i += 1
quantity = int(sub_request.ordered_parts) quantity = int(sub_request.ordered_parts)
worksheet2.write(j, i, quantity) worksheet2.write(j, i, quantity)
@ -262,20 +298,25 @@ class export_global_report(models.TransientModel):
data = base64.encodestring(file_data.read()) data = base64.encodestring(file_data.read())
attachment_id = self.env['ir.attachment'].create({
'name': "Global export" + time.strftime('%Y-%m-%d %H:%M')
+ ".xlsx",
'datas': data,
'datas_fname': 'Global_export.xlsx',
'res_model': 'export.global.report',
},)
attachment_id = self.env["ir.attachment"].create(
{
"name": "Global export"
+ time.strftime("%Y-%m-%d %H:%M")
+ ".xlsx",
"datas": data,
"datas_fname": "Global_export.xlsx",
"res_model": "export.global.report",
}
)
# Prepare your download URL # Prepare your download URL
download_url = '/web/content/' + str(attachment_id.id) + '?download=True'
base_url = self.env['ir.config_parameter'].get_param('web.base.url')
download_url = (
"/web/content/" + str(attachment_id.id) + "?download=True"
)
base_url = self.env["ir.config_parameter"].get_param("web.base.url")
return { return {
"type": "ir.actions.act_url",
"url": str(base_url) + str(download_url),
"target": "new",
"type": "ir.actions.act_url",
"url": str(base_url) + str(download_url),
"target": "new",
} }

17
easy_my_coop_fr/__manifest__.py

@ -5,18 +5,17 @@
{ {
"name": "Easy My Coop Fr", "name": "Easy My Coop Fr",
"version": "12.0.1.0.1", "version": "12.0.1.0.1",
"depends": ["easy_my_coop",
"l10n_fr"],
"depends": ["easy_my_coop", "l10n_fr"],
"author": "Houssine BAKKALI <houssine@coopiteasy.be>", "author": "Houssine BAKKALI <houssine@coopiteasy.be>",
"category": "Cooperative management", "category": "Cooperative management",
'webstite': "www.coopiteasy.be",
"webstite": "www.coopiteasy.be",
"license": "AGPL-3", "license": "AGPL-3",
"description": """
This is the french localization for the easy my coop module
"summary": """
This is the french localization for the easy my coop module
""", """,
'data': [
'views/subscription_template.xml',
'views/certificate_template.xml'
"data": [
"views/subscription_template.xml",
"views/certificate_template.xml",
], ],
'installable': True,
"installable": True,
} }

20
easy_my_coop_fr/models/coop.py

@ -2,18 +2,20 @@ from odoo import fields, models
class SubscriptionRequest(models.Model): class SubscriptionRequest(models.Model):
_inherit = 'subscription.request'
_inherit = "subscription.request"
company_type = fields.Selection(selection_add=[
('asso', 'Association'),
('eurl', 'EURL / Entreprise individuelle'),
('sarl', 'SARL'),
('sa', 'SA / SAS')
])
company_type = fields.Selection(
selection_add=[
("asso", "Association"),
("eurl", "EURL / Entreprise individuelle"),
("sarl", "SARL"),
("sa", "SA / SAS"),
]
)
def get_required_field(self): def get_required_field(self):
req_fields = super(SubscriptionRequest, self).get_required_field() req_fields = super(SubscriptionRequest, self).get_required_field()
if 'iban' in req_fields:
req_fields.remove('iban')
if "iban" in req_fields:
req_fields.remove("iban")
return req_fields return req_fields

16
easy_my_coop_fr/models/partner.py

@ -2,11 +2,13 @@ from odoo import fields, models
class ResPartner(models.Model): class ResPartner(models.Model):
_inherit = 'res.partner'
_inherit = "res.partner"
legal_form = fields.Selection(selection_add=[
('asso', 'Association'),
('eurl', 'EURL / Entreprise individuelle'),
('sarl', 'SARL'),
('sa', 'SA / SAS')
])
legal_form = fields.Selection(
selection_add=[
("asso", "Association"),
("eurl", "EURL / Entreprise individuelle"),
("sarl", "SARL"),
("sa", "SA / SAS"),
]
)

28
easy_my_coop_loan/__manifest__.py

@ -5,26 +5,22 @@
{ {
"name": "Easy My Coop Bond and Subordinated Loan Issues", "name": "Easy My Coop Bond and Subordinated Loan Issues",
"version": "12.0.1.0.1", "version": "12.0.1.0.1",
"depends": [
"easy_my_coop",
],
"depends": ["easy_my_coop"],
"author": "Coop IT Easy SCRLfs", "author": "Coop IT Easy SCRLfs",
"category": "Cooperative management", "category": "Cooperative management",
"website": "http://www.coopiteasy.be", "website": "http://www.coopiteasy.be",
"license": "AGPL-3", "license": "AGPL-3",
"description": """
This module allows to manage the bonds and subordinated loans subscription
life cycle.
"summary": """
This module allows to manage the bonds and
subordinated loans subscription life cycle.
""", """,
'data': [
'security/ir.model.access.csv',
'views/loan_view.xml',
'views/partner_view.xml',
'views/menus.xml',
'data/mail_template_data.xml',
],
"demo": [
"demo/coop.xml",
"data": [
"security/ir.model.access.csv",
"views/loan_view.xml",
"views/partner_view.xml",
"views/menus.xml",
"data/mail_template_data.xml",
], ],
'installable': True,
"demo": ["demo/coop.xml"],
"installable": True,
} }

124
easy_my_coop_loan/models/interest_line.py

@ -6,59 +6,79 @@ from odoo import fields, models
class LoanInterestLine(models.Model): class LoanInterestLine(models.Model):
_name = 'loan.interest.line'
_name = "loan.interest.line"
_description = "Loan Interest Line" _description = "Loan Interest Line"
name = fields.Integer(string="Year",
required=True)
issue_line = fields.Many2one('loan.issue.line',
string="Subscribed loan",
required=True)
partner_id = fields.Many2one(related='issue_line.partner_id',
store=True,
readlonly=True)
amount = fields.Monetary(related='issue_line.amount',
string="Subscribed amount",
currency_field='company_currency_id',
readonly=True)
interest = fields.Monetary(string="Gross interest amount",
currency_field='company_currency_id',
readonly=True)
net_interest = fields.Monetary(string="Net interest amount",
currency_field='company_currency_id',
readonly=True)
taxes_rate = fields.Float(string="Taxes on interest",
required=True)
taxes_amount = fields.Monetary(string="Taxes amount",
currency_field='company_currency_id',
readonly=True)
accrued_amount = fields.Monetary(string="Accrued amount",
currency_field='company_currency_id',
readonly=True)
accrued_interest = fields.Monetary(string="Accrued gross interest",
currency_field='company_currency_id',
readonly=True)
name = fields.Integer(string="Year", required=True)
issue_line = fields.Many2one(
"loan.issue.line", string="Subscribed loan", required=True
)
partner_id = fields.Many2one(
related="issue_line.partner_id", store=True, readlonly=True
)
amount = fields.Monetary(
related="issue_line.amount",
string="Subscribed amount",
currency_field="company_currency_id",
readonly=True,
)
interest = fields.Monetary(
string="Gross interest amount",
currency_field="company_currency_id",
readonly=True,
)
net_interest = fields.Monetary(
string="Net interest amount",
currency_field="company_currency_id",
readonly=True,
)
taxes_rate = fields.Float(string="Taxes on interest", required=True)
taxes_amount = fields.Monetary(
string="Taxes amount",
currency_field="company_currency_id",
readonly=True,
)
accrued_amount = fields.Monetary(
string="Accrued amount",
currency_field="company_currency_id",
readonly=True,
)
accrued_interest = fields.Monetary(
string="Accrued gross interest",
currency_field="company_currency_id",
readonly=True,
)
accrued_net_interest = fields.Monetary( accrued_net_interest = fields.Monetary(
string="Accrued net interest",
currency_field='company_currency_id',
readonly=True)
accrued_taxes = fields.Monetary(string="Accrued taxes to pay",
currency_field='company_currency_id',
readonly=True)
string="Accrued net interest",
currency_field="company_currency_id",
readonly=True,
)
accrued_taxes = fields.Monetary(
string="Accrued taxes to pay",
currency_field="company_currency_id",
readonly=True,
)
due_date = fields.Date(string="Due date") due_date = fields.Date(string="Due date")
company_currency_id = fields.Many2one('res.currency',
related='company_id.currency_id',
string="Company Currency",
readonly=True)
company_id = fields.Many2one('res.company',
related='issue_line.company_id',
string="Company",
readonly=True)
state = fields.Selection([('draft', 'Draft'),
('due', 'Due'),
('requested', 'Payment requested'),
('donation', 'Donation'),
('paid', 'Paid')
],
string="State",
default="draft")
company_currency_id = fields.Many2one(
"res.currency",
related="company_id.currency_id",
string="Company Currency",
readonly=True,
)
company_id = fields.Many2one(
"res.company",
related="issue_line.company_id",
string="Company",
readonly=True,
)
state = fields.Selection(
[
("draft", "Draft"),
("due", "Due"),
("requested", "Payment requested"),
("donation", "Donation"),
("paid", "Paid"),
],
string="State",
default="draft",
)

196
easy_my_coop_loan/models/loan.py

@ -4,81 +4,103 @@
import logging import logging
from odoo import api, fields, models, _
from odoo import _, api, fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class LoanIssue(models.Model): class LoanIssue(models.Model):
_name = 'loan.issue'
_description = 'Loan Issue'
_name = "loan.issue"
_description = "Loan Issue"
@api.multi @api.multi
def _compute_subscribed_amount(self): def _compute_subscribed_amount(self):
for issue in self: for issue in self:
susbscribed_amount = 0.0 susbscribed_amount = 0.0
for line in issue.loan_issue_lines.filtered( for line in issue.loan_issue_lines.filtered(
lambda record: record.state != 'cancelled'):
lambda record: record.state != "cancelled"
):
susbscribed_amount += line.amount susbscribed_amount += line.amount
issue.subscribed_amount = susbscribed_amount issue.subscribed_amount = susbscribed_amount
name = fields.Char(string="Name",
translate=True)
name = fields.Char(string="Name", translate=True)
default_issue = fields.Boolean(string="Default issue") default_issue = fields.Boolean(string="Default issue")
subscription_start_date = fields.Date(string="Start date subscription period")
subscription_start_date = fields.Date(
string="Start date subscription period"
)
subscription_end_date = fields.Date(string="End date subscription period") subscription_end_date = fields.Date(string="End date subscription period")
user_id = fields.Many2one('res.users',
string="Responsible")
user_id = fields.Many2one("res.users", string="Responsible")
loan_start_date = fields.Date(string="Loan start date") loan_start_date = fields.Date(string="Loan start date")
term_date = fields.Date(string="Term date") term_date = fields.Date(string="Term date")
loan_term = fields.Float(string="Duration of the loan in month") loan_term = fields.Float(string="Duration of the loan in month")
rate = fields.Float(string="Interest rate") rate = fields.Float(string="Interest rate")
face_value = fields.Monetary(string="Facial value",
currency_field='company_currency_id',
required=True)
minimum_amount = fields.Monetary(string="Minimum amount of issue",
currency_field='company_currency_id')
maximum_amount = fields.Monetary(string="Maximum amount of issue",
currency_field='company_currency_id')
min_amount_company = fields.Monetary(string="Minimum amount for a company",
currency_field='company_currency_id')
max_amount_company = fields.Monetary(string="Maximum amount for a company",
currency_field='company_currency_id')
min_amount_person = fields.Monetary(string="Minimum amount for a person",
currency_field='company_currency_id')
max_amount_person = fields.Monetary(string="Maximum amount for a person",
currency_field='company_currency_id')
subscribed_amount = fields.Monetary(string="Subscribed amount",
compute="_compute_subscribed_amount",
currency_field='company_currency_id')
interest_payment = fields.Selection([('end', 'End'),
('yearly', 'Yearly')],
string="Interest payment")
face_value = fields.Monetary(
string="Facial value",
currency_field="company_currency_id",
required=True,
)
minimum_amount = fields.Monetary(
string="Minimum amount of issue", currency_field="company_currency_id"
)
maximum_amount = fields.Monetary(
string="Maximum amount of issue", currency_field="company_currency_id"
)
min_amount_company = fields.Monetary(
string="Minimum amount for a company",
currency_field="company_currency_id",
)
max_amount_company = fields.Monetary(
string="Maximum amount for a company",
currency_field="company_currency_id",
)
min_amount_person = fields.Monetary(
string="Minimum amount for a person",
currency_field="company_currency_id",
)
max_amount_person = fields.Monetary(
string="Maximum amount for a person",
currency_field="company_currency_id",
)
subscribed_amount = fields.Monetary(
string="Subscribed amount",
compute="_compute_subscribed_amount",
currency_field="company_currency_id",
)
interest_payment = fields.Selection(
[("end", "End"), ("yearly", "Yearly")], string="Interest payment"
)
interest_payment_info = fields.Char(string="Yearly payment on") interest_payment_info = fields.Char(string="Yearly payment on")
loan_issue_lines = fields.One2many('loan.issue.line',
'loan_issue_id',
string="Loan issue lines")
state = fields.Selection([('draft', 'Draft'),
('confirmed', 'Confirmed'),
('cancelled', 'Cancelled'),
('ongoing', 'Ongoing'),
('closed', 'Closed')],
string="State",
default='draft')
company_currency_id = fields.Many2one('res.currency',
related='company_id.currency_id',
string="Company Currency",
readonly=True)
company_id = fields.Many2one('res.company',
string='Company',
required=True,
readonly=True,
default=lambda self: self.env['res.company']._company_default_get()) # noqa
loan_issue_lines = fields.One2many(
"loan.issue.line", "loan_issue_id", string="Loan issue lines"
)
state = fields.Selection(
[
("draft", "Draft"),
("confirmed", "Confirmed"),
("cancelled", "Cancelled"),
("ongoing", "Ongoing"),
("closed", "Closed"),
],
string="State",
default="draft",
)
company_currency_id = fields.Many2one(
"res.currency",
related="company_id.currency_id",
string="Company Currency",
readonly=True,
)
company_id = fields.Many2one(
"res.company",
string="Company",
required=True,
readonly=True,
default=lambda self: self.env["res.company"]._company_default_get(),
) # noqa
by_company = fields.Boolean(string="By company") by_company = fields.Boolean(string="By company")
by_individual = fields.Boolean(string='By individuals')
display_on_website = fields.Boolean(sting='Display on website')
taxes_rate = fields.Float(string="Taxes on interest",
required=True)
by_individual = fields.Boolean(string="By individuals")
display_on_website = fields.Boolean(sting="Display on website")
taxes_rate = fields.Float(string="Taxes on interest", required=True)
@api.multi @api.multi
def get_max_amount(self, partner): def get_max_amount(self, partner):
@ -88,7 +110,8 @@ class LoanIssue(models.Model):
""" """
self.ensure_one() self.ensure_one()
lines = self.loan_issue_lines.filtered( lines = self.loan_issue_lines.filtered(
lambda r: r.partner_id == partner and r.state != 'cancelled')
lambda r: r.partner_id == partner and r.state != "cancelled"
)
already_subscribed = sum(line.amount for line in lines) already_subscribed = sum(line.amount for line in lines)
max_amount = -1 # No max amount max_amount = -1 # No max amount
if partner.is_company and self.max_amount_company > 0: if partner.is_company and self.max_amount_company > 0:
@ -105,7 +128,8 @@ class LoanIssue(models.Model):
""" """
self.ensure_one() self.ensure_one()
lines = self.loan_issue_lines.filtered( lines = self.loan_issue_lines.filtered(
lambda r: r.partner_id == partner and r.state != 'cancelled')
lambda r: r.partner_id == partner and r.state != "cancelled"
)
amount_subscribed = sum(line.amount for line in lines) amount_subscribed = sum(line.amount for line in lines)
if partner.is_company: if partner.is_company:
min_amount = self.min_amount_company - amount_subscribed min_amount = self.min_amount_company - amount_subscribed
@ -115,42 +139,41 @@ class LoanIssue(models.Model):
@api.multi @api.multi
def get_web_issues(self, is_company): def get_web_issues(self, is_company):
bond_issues = self.search([
('display_on_website', '=', True),
('state', '=', 'ongoing')
])
bond_issues = self.search(
[("display_on_website", "=", True), ("state", "=", "ongoing")]
)
if is_company is True: if is_company is True:
return bond_issues.filtered('by_company')
return bond_issues.filtered("by_company")
else: else:
return bond_issues.filtered('by_company')
return bond_issues.filtered("by_company")
@api.multi @api.multi
def action_confirm(self): def action_confirm(self):
self.ensure_one() self.ensure_one()
self.write({'state': 'confirmed'})
self.write({"state": "confirmed"})
@api.multi @api.multi
def action_open(self): def action_open(self):
self.ensure_one() self.ensure_one()
self.write({'state': 'ongoing'})
self.write({"state": "ongoing"})
@api.multi @api.multi
def action_draft(self): def action_draft(self):
self.ensure_one() self.ensure_one()
self.write({'state': 'draft'})
self.write({"state": "draft"})
@api.multi @api.multi
def action_cancel(self): def action_cancel(self):
self.ensure_one() self.ensure_one()
self.write({'state': 'cancelled'})
self.write({"state": "cancelled"})
@api.multi @api.multi
def action_close(self): def action_close(self):
self.ensure_one() self.ensure_one()
self.write({'state': 'closed'})
self.write({"state": "closed"})
def get_interest_vals(self, line, vals): def get_interest_vals(self, line, vals):
interest_obj = self.env['loan.interest.line']
interest_obj = self.env["loan.interest.line"]
accrued_amount = line.amount accrued_amount = line.amount
accrued_interest = 0 accrued_interest = 0
accrued_net_interest = 0 accrued_net_interest = 0
@ -163,38 +186,43 @@ class LoanIssue(models.Model):
accrued_interest += interest accrued_interest += interest
accrued_net_interest += net_interest accrued_net_interest += net_interest
accrued_taxes += taxes_amount accrued_taxes += taxes_amount
vals['interest'] = interest
vals['net_interest'] = net_interest
vals['taxes_amount'] = taxes_amount
vals['accrued_amount'] = accrued_amount
vals['accrued_interest'] = accrued_interest
vals['accrued_net_interest'] = accrued_net_interest
vals['accrued_taxes'] = accrued_taxes
vals['name'] = year
vals["interest"] = interest
vals["net_interest"] = net_interest
vals["taxes_amount"] = taxes_amount
vals["accrued_amount"] = accrued_amount
vals["accrued_interest"] = accrued_interest
vals["accrued_net_interest"] = accrued_net_interest
vals["accrued_taxes"] = accrued_taxes
vals["name"] = year
interest_obj.create(vals) interest_obj.create(vals)
@api.multi @api.multi
def compute_loan_interest(self): def compute_loan_interest(self):
self.ensure_one() self.ensure_one()
if self.interest_payment == 'end':
if self.interest_payment == "end":
due_date = self.term_date due_date = self.term_date
else: else:
raise NotImplementedError(_("Interest payment by year hasn't been "
"implemented yet"))
raise NotImplementedError(
_("Interest payment by year hasn't been " "implemented yet")
)
for line in self.loan_issue_lines: for line in self.loan_issue_lines:
# TODO remove this line # TODO remove this line
line.interest_lines.unlink() line.interest_lines.unlink()
# Please Do not Forget # Please Do not Forget
vals = { vals = {
'issue_line': line.id,
'due_date': due_date,
'taxes_rate': self.taxes_rate
}
"issue_line": line.id,
"due_date": due_date,
"taxes_rate": self.taxes_rate,
}
self.get_interest_vals(line, vals) self.get_interest_vals(line, vals)
rounded_term = int(self.loan_term) rounded_term = int(self.loan_term)
if self.loan_term - rounded_term > 0: if self.loan_term - rounded_term > 0:
# TODO Handle this case # TODO Handle this case
raise NotImplementedError(_("Calculation on non entire year "
"hasn't been implemented yet"))
raise NotImplementedError(
_(
"Calculation on non entire year "
"hasn't been implemented yet"
)
)

120
easy_my_coop_loan/models/loan_issue_line.py

@ -8,65 +8,79 @@ from odoo import api, fields, models
class LoanIssueLine(models.Model): class LoanIssueLine(models.Model):
_name = 'loan.issue.line'
_description = 'Loan Issue Line'
_order = 'date desc, id'
_name = "loan.issue.line"
_description = "Loan Issue Line"
_order = "date desc, id"
@api.multi @api.multi
@api.depends('quantity', 'face_value')
@api.depends("quantity", "face_value")
def _compute_amount(self): def _compute_amount(self):
for line in self: for line in self:
line.amount = line.face_value * line.quantity line.amount = line.face_value * line.quantity
name = fields.Char(string="Reference") name = fields.Char(string="Reference")
loan_issue_id = fields.Many2one('loan.issue',
string="Loan issue",
required=True)
interest_lines = fields.One2many('loan.interest.line',
'issue_line',
string="Interest lines")
quantity = fields.Integer(string='quantity',
required=True)
face_value = fields.Monetary(related='loan_issue_id.face_value',
currency_field='company_currency_id',
store=True,
readonly=True)
partner_id = fields.Many2one('res.partner',
string="Subscriber",
required=True)
date = fields.Date(string="Subscription date",
default=lambda self: datetime.strftime(datetime.now(),
'%Y-%m-%d'),
required=True)
amount = fields.Monetary(string="Subscribed amount",
currency_field='company_currency_id',
compute='_compute_amount',
store=True)
state = fields.Selection([('draft', 'Draft'),
('subscribed', 'Subscribed'),
('waiting', 'Waiting payment'),
('paid', 'paid'),
('cancelled', 'Cancelled'),
('ended', 'Ended')],
string="State",
required=True,
default="draft")
company_currency_id = fields.Many2one('res.currency',
related='company_id.currency_id',
string="Company Currency",
readonly=True)
company_id = fields.Many2one('res.company',
related='loan_issue_id.company_id',
string="Company",
readonly=True)
loan_issue_id = fields.Many2one(
"loan.issue", string="Loan issue", required=True
)
interest_lines = fields.One2many(
"loan.interest.line", "issue_line", string="Interest lines"
)
quantity = fields.Integer(string="quantity", required=True)
face_value = fields.Monetary(
related="loan_issue_id.face_value",
currency_field="company_currency_id",
store=True,
readonly=True,
)
partner_id = fields.Many2one(
"res.partner", string="Subscriber", required=True
)
date = fields.Date(
string="Subscription date",
default=lambda self: datetime.strftime(datetime.now(), "%Y-%m-%d"),
required=True,
)
amount = fields.Monetary(
string="Subscribed amount",
currency_field="company_currency_id",
compute="_compute_amount",
store=True,
)
state = fields.Selection(
[
("draft", "Draft"),
("subscribed", "Subscribed"),
("waiting", "Waiting payment"),
("paid", "paid"),
("cancelled", "Cancelled"),
("ended", "Ended"),
],
string="State",
required=True,
default="draft",
)
company_currency_id = fields.Many2one(
"res.currency",
related="company_id.currency_id",
string="Company Currency",
readonly=True,
)
company_id = fields.Many2one(
"res.company",
related="loan_issue_id.company_id",
string="Company",
readonly=True,
)
def get_loan_sub_mail_template(self): def get_loan_sub_mail_template(self):
return self.env.ref('easy_my_coop_loan.loan_subscription_confirmation',
False)
return self.env.ref(
"easy_my_coop_loan.loan_subscription_confirmation", False
)
def get_loan_pay_req_mail_template(self): def get_loan_pay_req_mail_template(self):
return self.env.ref('easy_my_coop_loan.loan_issue_payment_request',
False)
return self.env.ref(
"easy_my_coop_loan.loan_issue_payment_request", False
)
@api.model @api.model
def create(self, vals): def create(self, vals):
@ -80,12 +94,12 @@ class LoanIssueLine(models.Model):
@api.multi @api.multi
def action_draft(self): def action_draft(self):
for line in self: for line in self:
line.write({'state': 'draft'})
line.write({"state": "draft"})
@api.multi @api.multi
def action_validate(self): def action_validate(self):
for line in self: for line in self:
line.write({'state': 'subscribed'})
line.write({"state": "subscribed"})
@api.multi @api.multi
def action_request_payment(self): def action_request_payment(self):
@ -93,14 +107,14 @@ class LoanIssueLine(models.Model):
for line in self: for line in self:
pay_req_mail_template.send_mail(line.id) pay_req_mail_template.send_mail(line.id)
line.write({'state': 'waiting'})
line.write({"state": "waiting"})
@api.multi @api.multi
def action_cancel(self): def action_cancel(self):
for line in self: for line in self:
line.write({'state': 'cancelled'})
line.write({"state": "cancelled"})
@api.multi @api.multi
def action_paid(self): def action_paid(self):
for line in self: for line in self:
line.write({'state': 'paid'})
line.write({"state": "paid"})

6
easy_my_coop_loan/models/partner.py

@ -3,7 +3,7 @@
# Robin Keunen <robin@coopiteasy.be> # Robin Keunen <robin@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import fields, models, api
from odoo import api, fields, models
class ResPartner(models.Model): class ResPartner(models.Model):
@ -15,9 +15,7 @@ class ResPartner(models.Model):
string="Loans", string="Loans",
) )
is_loaner = fields.Boolean( is_loaner = fields.Boolean(
string="Loaner",
compute="_compute_is_loaner",
store=True,
string="Loaner", compute="_compute_is_loaner", store=True
) )
@api.multi @api.multi

7
easy_my_coop_loan/tests/test_emc_loan.py

@ -2,10 +2,12 @@
# Robin Keunen <robin@coopiteasy.be> # Robin Keunen <robin@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo.addons.easy_my_coop.tests.test_base import EMCBaseCase
from odoo.fields import Date
from datetime import timedelta from datetime import timedelta
from odoo.exceptions import AccessError from odoo.exceptions import AccessError
from odoo.fields import Date
from odoo.addons.easy_my_coop.tests.test_base import EMCBaseCase
class EMCLoanCase(EMCBaseCase): class EMCLoanCase(EMCBaseCase):
@ -101,4 +103,3 @@ class EMCLoanCase(EMCBaseCase):
line.action_paid() line.action_paid()
loan_issue.compute_loan_interest() loan_issue.compute_loan_interest()

19
easy_my_coop_loan_website/__manifest__.py

@ -5,22 +5,15 @@
{ {
"name": "Easy My Coop Loan Issues Website", "name": "Easy My Coop Loan Issues Website",
"version": "12.0.1.0.1", "version": "12.0.1.0.1",
"depends": [
"easy_my_coop_loan",
"easy_my_coop_website",
"website",
],
"depends": ["easy_my_coop_loan", "easy_my_coop_website", "website"],
"author": "Coop IT Easy SCRLfs", "author": "Coop IT Easy SCRLfs",
"category": "Cooperative management", "category": "Cooperative management",
"website": "http://www.coopiteasy.be", "website": "http://www.coopiteasy.be",
"license": "AGPL-3", "license": "AGPL-3",
"description": """
This module implements the subscription page for bonds and
subordinated loans.
"summary": """
This module implements the subscription page
for bonds and subordinated loans.
""", """,
'data': [
'data/website_loan_data.xml',
'template/loan_issue_template.xml'
],
'installable': True,
"data": ["data/website_loan_data.xml", "template/loan_issue_template.xml"],
"installable": True,
} }

74
easy_my_coop_loan_website/controllers/main.py

@ -1,32 +1,37 @@
from odoo import http from odoo import http
from odoo.http import request from odoo.http import request
from odoo.tools.translate import _ from odoo.tools.translate import _
class WebsiteLoanIssueSubscription(http.Controller): class WebsiteLoanIssueSubscription(http.Controller):
@http.route(['/subscription/get_loan_issue'],
type='json',
auth="user",
methods=['POST'], website=True)
@http.route(
["/subscription/get_loan_issue"],
type="json",
auth="user",
methods=["POST"],
website=True,
)
def get_loan_issue(self, loan_issue_id, **kw): def get_loan_issue(self, loan_issue_id, **kw):
loan_issue_obj = request.env['loan.issue']
loan_issue_obj = request.env["loan.issue"]
partner = request.env.user.partner_id partner = request.env.user.partner_id
if loan_issue_id: if loan_issue_id:
loan_issue = loan_issue_obj.sudo().browse(int(loan_issue_id)) loan_issue = loan_issue_obj.sudo().browse(int(loan_issue_id))
max_amount = loan_issue.get_max_amount(partner) max_amount = loan_issue.get_max_amount(partner)
return { return {
loan_issue.id: { loan_issue.id: {
'max_amount': max_amount,
'face_value': loan_issue.face_value,
}
"max_amount": max_amount,
"face_value": loan_issue.face_value,
} }
}
else: else:
return False return False
@http.route(['/subscription/loan_issue_form'],
type='http', auth="user", website=True)
@http.route(
["/subscription/loan_issue_form"],
type="http",
auth="user",
website=True,
)
def display_loan_issue_subscription_page(self, **kwargs): def display_loan_issue_subscription_page(self, **kwargs):
values = {} values = {}
partner = request.env.user.partner_id partner = request.env.user.partner_id
@ -35,11 +40,11 @@ class WebsiteLoanIssueSubscription(http.Controller):
values = self.fill_values(values, is_company) values = self.fill_values(values, is_company)
values.update(kwargs=kwargs.items()) values.update(kwargs=kwargs.items())
return request.render( return request.render(
"easy_my_coop_loan_website.loanissuesubscription",
values)
"easy_my_coop_loan_website.loanissuesubscription", values
)
def get_loan_issues(self, is_company): def get_loan_issues(self, is_company):
loan_obj = request.env['loan.issue']
loan_obj = request.env["loan.issue"]
loan_issues = loan_obj.sudo().get_web_issues(is_company) loan_issues = loan_obj.sudo().get_web_issues(is_company)
return loan_issues return loan_issues
@ -48,21 +53,21 @@ class WebsiteLoanIssueSubscription(http.Controller):
company = request.website.company_id company = request.website.company_id
loan_issues = self.get_loan_issues(is_company) loan_issues = self.get_loan_issues(is_company)
values['loan_issues'] = loan_issues
values['company'] = company
values["loan_issues"] = loan_issues
values["company"] = company
if not values.get('loan_issue_id'):
if not values.get("loan_issue_id"):
for loan_issue in loan_issues: for loan_issue in loan_issues:
if loan_issue.default_issue is True: if loan_issue.default_issue is True:
values['loan_issue_id'] = loan_issue.id
values["loan_issue_id"] = loan_issue.id
break break
if not values.get('loan_issue_id', False) and loan_issues:
values['loan_issue_id'] = loan_issues[0].id
if not values.get("loan_issue_id", False) and loan_issues:
values["loan_issue_id"] = loan_issues[0].id
return values return values
def validation(self, loan_issue, kwargs): def validation(self, loan_issue, kwargs):
sub_amount = kwargs.get('subscription_amount')
sub_amount = kwargs.get("subscription_amount")
redirect = "easy_my_coop_loan_website.loanissuesubscription" redirect = "easy_my_coop_loan_website.loanissuesubscription"
values = {} values = {}
@ -74,22 +79,25 @@ class WebsiteLoanIssueSubscription(http.Controller):
return request.render(redirect, values) return request.render(redirect, values)
return True return True
@http.route(['/subscription/subscribe_loan_issue'],
type='http',
auth="user", website=True)
@http.route(
["/subscription/subscribe_loan_issue"],
type="http",
auth="user",
website=True,
)
def loan_issue_subscription(self, **kwargs): def loan_issue_subscription(self, **kwargs):
loan_obj = request.env['loan.issue']
loan_obj_line = request.env['loan.issue.line']
loan_obj = request.env["loan.issue"]
loan_obj_line = request.env["loan.issue.line"]
loan_issue = loan_obj.sudo().browse(kwargs.get('loan_issue_id'))
loan_issue = loan_obj.sudo().browse(kwargs.get("loan_issue_id"))
partner = request.env.user.partner_id partner = request.env.user.partner_id
if self.validation(loan_issue, kwargs): if self.validation(loan_issue, kwargs):
values = { values = {
'loan_issue_id': loan_issue.id,
'partner_id': partner.id,
'amount': kwargs['subscription_amount'],
'state': 'subscribed'
}
"loan_issue_id": loan_issue.id,
"partner_id": partner.id,
"amount": kwargs["subscription_amount"],
"state": "subscribed",
}
loan_obj_line.sudo().create(values) loan_obj_line.sudo().create(values)
return request.render("easy_my_coop_website.cooperator_thanks", values) return request.render("easy_my_coop_website.cooperator_thanks", values)

2
easy_my_coop_taxshelter_report/__manifest__.py

@ -15,7 +15,7 @@
"category": "Cooperative management", "category": "Cooperative management",
"website": "www.coopiteasy.be", "website": "www.coopiteasy.be",
"license": "AGPL-3", "license": "AGPL-3",
"description": """
"summary": """
This module allows you to create a fiscal declaration year and to print This module allows you to create a fiscal declaration year and to print
tax shelter declaration for each cooperator. tax shelter declaration for each cooperator.
""", """,

6
easy_my_coop_taxshelter_report/models/mail_template.py

@ -6,7 +6,11 @@ class MailTemplate(models.Model):
@api.multi @api.multi
def send_mail_with_multiple_attachments( def send_mail_with_multiple_attachments(
self, res_id, additional_attachments, force_send=False, raise_exception=False
self,
res_id,
additional_attachments,
force_send=False,
raise_exception=False,
): ):
"""Generates a new mail message for the given template and record, """Generates a new mail message for the given template and record,
and schedules it for delivery through the ``mail`` and schedules it for delivery through the ``mail``

82
easy_my_coop_taxshelter_report/models/tax_shelter_declaration.py

@ -38,10 +38,16 @@ class TaxShelterDeclaration(models.Model):
month_from = fields.Char(String="Month from", required=True) month_from = fields.Char(String="Month from", required=True)
month_to = fields.Char(String="Month to", required=True) month_to = fields.Char(String="Month to", required=True)
tax_shelter_percentage = fields.Selection( tax_shelter_percentage = fields.Selection(
[("30", "30%"), ("45", "45%")], string="Tax Shelter percentage", required=True
[("30", "30%"), ("45", "45%")],
string="Tax Shelter percentage",
required=True,
) )
state = fields.Selection( state = fields.Selection(
[("draft", "Draft"), ("computed", "Computed"), ("validated", "Validated")],
[
("draft", "Draft"),
("computed", "Computed"),
("validated", "Validated"),
],
string="State", string="State",
required=True, required=True,
default="draft", default="draft",
@ -76,7 +82,10 @@ class TaxShelterDeclaration(models.Model):
declaration = self declaration = self
else: else:
declaration = self.search( declaration = self.search(
[("date_from", "<=", entry.date), ("date_to", ">=", entry.date)]
[
("date_from", "<=", entry.date),
("date_to", ">=", entry.date),
]
) )
if entry.partner_id.id in declaration.excluded_cooperator.ids: if entry.partner_id.id in declaration.excluded_cooperator.ids:
return True return True
@ -93,13 +102,18 @@ class TaxShelterDeclaration(models.Model):
line_vals["type"] = TYPE_MAP[entry.type] line_vals["type"] = TYPE_MAP[entry.type]
if entry.type == "subscription": if entry.type == "subscription":
if not excluded: if not excluded:
capital_after_sub = ongoing_capital_sub + entry.total_amount_line
capital_after_sub = (
ongoing_capital_sub + entry.total_amount_line
)
else: else:
capital_after_sub = ongoing_capital_sub capital_after_sub = ongoing_capital_sub
line_vals["capital_before_sub"] = ongoing_capital_sub line_vals["capital_before_sub"] = ongoing_capital_sub
line_vals["capital_after_sub"] = capital_after_sub line_vals["capital_after_sub"] = capital_after_sub
line_vals["capital_limit"] = self.tax_shelter_capital_limit line_vals["capital_limit"] = self.tax_shelter_capital_limit
if ongoing_capital_sub < self.tax_shelter_capital_limit and not excluded:
if (
ongoing_capital_sub < self.tax_shelter_capital_limit
and not excluded
):
line_vals["tax_shelter"] = True line_vals["tax_shelter"] = True
return line_vals return line_vals
@ -116,7 +130,9 @@ class TaxShelterDeclaration(models.Model):
cert_vals[ cert_vals[
"cooperator_number" "cooperator_number"
] = entry.partner_id.cooperator_register_number ] = entry.partner_id.cooperator_register_number
certificate = self.env["tax.shelter.certificate"].create(cert_vals)
certificate = self.env["tax.shelter.certificate"].create(
cert_vals
)
partner_certificate[entry.partner_id.id] = certificate partner_certificate[entry.partner_id.id] = certificate
excluded = self._excluded_from_declaration(entry) excluded = self._excluded_from_declaration(entry)
line_vals = self._prepare_line( line_vals = self._prepare_line(
@ -129,8 +145,9 @@ class TaxShelterDeclaration(models.Model):
return partner_certificate return partner_certificate
@api.one
@api.multi
def compute_declaration(self): def compute_declaration(self):
self.ensure_one()
entries = self.env["subscription.register"].search( entries = self.env["subscription.register"].search(
[ [
("partner_id.is_company", "=", False), ("partner_id.is_company", "=", False),
@ -140,7 +157,7 @@ class TaxShelterDeclaration(models.Model):
) )
subscriptions = entries.filtered( subscriptions = entries.filtered(
(lambda r: r.type == "subscription" and r.date < self.date_from)
lambda r: r.type == "subscription" and r.date < self.date_from
) # noqa ) # noqa
cap_prev_sub = 0.0 cap_prev_sub = 0.0
for subscription in subscriptions: for subscription in subscriptions:
@ -154,13 +171,15 @@ class TaxShelterDeclaration(models.Model):
self.state = "computed" self.state = "computed"
@api.one
@api.multi
def validate_declaration(self): def validate_declaration(self):
self.ensure_one()
self.tax_shelter_certificates.write({"state": "validated"}) self.tax_shelter_certificates.write({"state": "validated"})
self.state = "validated" self.state = "validated"
@api.one
@api.multi
def reset_declaration(self): def reset_declaration(self):
self.ensure_one()
if not self.state == "validated": if not self.state == "validated":
self.tax_shelter_certificates.unlink() self.tax_shelter_certificates.unlink()
self.state = "draft" self.state = "draft"
@ -235,13 +254,15 @@ class TaxShelterCertificate(models.Model):
compute="_compute_amounts", string="Total previously subscribed" compute="_compute_amounts", string="Total previously subscribed"
) )
total_amount_eligible_previously_subscribed = fields.Float( total_amount_eligible_previously_subscribed = fields.Float(
compute="_compute_amounts", string="Total eligible previously subscribed"
compute="_compute_amounts",
string="Total eligible previously subscribed",
) )
total_amount_subscribed = fields.Float( total_amount_subscribed = fields.Float(
compute="_compute_amounts", string="Total subscribed" compute="_compute_amounts", string="Total subscribed"
) )
total_amount_eligible = fields.Float( total_amount_eligible = fields.Float(
compute="_compute_amounts", string="Total amount eligible To Tax shelter"
compute="_compute_amounts",
string="Total amount eligible To Tax shelter",
) )
total_amount_resold = fields.Float( total_amount_resold = fields.Float(
compute="_compute_amounts", string="Total resold" compute="_compute_amounts", string="Total resold"
@ -252,14 +273,21 @@ class TaxShelterCertificate(models.Model):
total_amount = fields.Float( total_amount = fields.Float(
compute="_compute_amounts", string="Total", readonly=True compute="_compute_amounts", string="Total", readonly=True
) )
company_id = fields.Many2one(related="declaration_id.company_id", string="Company")
company_id = fields.Many2one(
related="declaration_id.company_id", string="Company"
)
def generate_pdf_report(self, report_type): def generate_pdf_report(self, report_type):
report, name = REPORT_DIC[report_type] report, name = REPORT_DIC[report_type]
report = self.env.ref(report).render_qweb_pdf(self.id)[0] report = self.env.ref(report).render_qweb_pdf(self.id)[0]
report = base64.b64encode(report) report = base64.b64encode(report)
report_name = ( report_name = (
self.partner_id.name + " " + name + " " + self.declaration_id.name + ".pdf"
self.partner_id.name
+ " "
+ name
+ " "
+ self.declaration_id.name
+ ".pdf"
) )
return (report_name, report) return (report_name, report)
@ -325,7 +353,9 @@ class TaxShelterCertificate(models.Model):
certificate.total_amount_eligible = total_amount_elligible certificate.total_amount_eligible = total_amount_elligible
for line in certificate.previously_subscribed_eligible_lines: for line in certificate.previously_subscribed_eligible_lines:
total_amount_previously_eligible += line.amount_subscribed_eligible
total_amount_previously_eligible += (
line.amount_subscribed_eligible
)
certificate.total_amount_eligible_previously_subscribed = ( certificate.total_amount_eligible_previously_subscribed = (
total_amount_previously_eligible total_amount_previously_eligible
) )
@ -357,7 +387,7 @@ class TaxShelterCertificate(models.Model):
lambda r: r.type == "subscribed" lambda r: r.type == "subscribed"
and r.transaction_date < certificate.declaration_id.date_from and r.transaction_date < certificate.declaration_id.date_from
) )
certificate.previously_subscribed_eligible_lines = certificate.lines.filtered(
certificate.previously_subscribed_eligible_lines = certificate.lines.filtered( # noqa
lambda r: r.type == "subscribed" lambda r: r.type == "subscribed"
and r.transaction_date < certificate.declaration_id.date_from and r.transaction_date < certificate.declaration_id.date_from
and r.tax_shelter and r.tax_shelter
@ -401,8 +431,12 @@ class TaxShelterCertificateLine(models.Model):
share_type = fields.Many2one( share_type = fields.Many2one(
"product.product", string="Share type", required=True, readonly=True "product.product", string="Share type", required=True, readonly=True
) )
share_unit_price = fields.Float(string="Share price", required=True, readonly=True)
quantity = fields.Integer(string="Number of shares", required=True, readonly=True)
share_unit_price = fields.Float(
string="Share price", required=True, readonly=True
)
quantity = fields.Integer(
string="Number of shares", required=True, readonly=True
)
transaction_date = fields.Date(string="Transaction date") transaction_date = fields.Date(string="Transaction date")
tax_shelter = fields.Boolean(string="Tax shelter eligible", readonly=True) tax_shelter = fields.Boolean(string="Tax shelter eligible", readonly=True)
type = fields.Selection( type = fields.Selection(
@ -419,7 +453,9 @@ class TaxShelterCertificateLine(models.Model):
compute="_compute_totals", string="Amount subscribed", store=True compute="_compute_totals", string="Amount subscribed", store=True
) )
amount_subscribed_eligible = fields.Float( amount_subscribed_eligible = fields.Float(
compute="_compute_totals", string="Amount subscribed eligible", store=True
compute="_compute_totals",
string="Amount subscribed eligible",
store=True,
) )
amount_resold = fields.Float( amount_resold = fields.Float(
compute="_compute_totals", string="Amount resold", store=True compute="_compute_totals", string="Amount resold", store=True
@ -431,7 +467,9 @@ class TaxShelterCertificateLine(models.Model):
capital_before_sub = fields.Float( capital_before_sub = fields.Float(
string="Capital before subscription", readonly=True string="Capital before subscription", readonly=True
) )
capital_after_sub = fields.Float(string="Capital after subscription", readonly=True)
capital_after_sub = fields.Float(
string="Capital after subscription", readonly=True
)
capital_limit = fields.Float(string="Capital limit", readonly=True) capital_limit = fields.Float(string="Capital limit", readonly=True)
@api.multi @api.multi
@ -460,4 +498,6 @@ class TaxShelterCertificateLine(models.Model):
if line.type == "resold": if line.type == "resold":
line.amount_resold = line.share_unit_price * -(line.quantity) line.amount_resold = line.share_unit_price * -(line.quantity)
if line.type == "transfered": if line.type == "transfered":
line.amount_transfered = line.share_unit_price * -(line.quantity)
line.amount_transfered = line.share_unit_price * -(
line.quantity
)

22
easy_my_coop_website/__manifest__.py

@ -6,23 +6,19 @@
{ {
"name": "Easy My Coop Website", "name": "Easy My Coop Website",
"version": "12.0.1.0.0", "version": "12.0.1.0.0",
"depends": [
"easy_my_coop",
"website",
"website_recaptcha_reloaded",
],
"depends": ["easy_my_coop", "website", "website_recaptcha_reloaded"],
"author": "Coop IT Easy SCRLfs", "author": "Coop IT Easy SCRLfs",
"category": "Cooperative management", "category": "Cooperative management",
"website": "www.coopiteasy.be", "website": "www.coopiteasy.be",
"license": "AGPL-3", "license": "AGPL-3",
"description": """
This module adds the cooperator subscription form allowing to subscribe for
shares online.
"summary": """
This module adds the cooperator subscription form
allowing to subscribe for shares online.
""", """,
'data': [
'views/subscription_template.xml',
'data/website_cooperator_data.xml',
"data": [
"views/subscription_template.xml",
"data/website_cooperator_data.xml",
], ],
'installable': True,
'application': True,
"installable": True,
"application": True,
} }

408
easy_my_coop_website/controllers/main.py

@ -1,39 +1,79 @@
import base64 import base64
from datetime import datetime
import re import re
from datetime import datetime
from odoo import http from odoo import http
from odoo.http import request from odoo.http import request
from odoo.tools.translate import _ from odoo.tools.translate import _
# Only use for behavior, don't stock it # Only use for behavior, don't stock it
_TECHNICAL = ['view_from', 'view_callback']
_TECHNICAL = ["view_from", "view_callback"]
# Allow in description # Allow in description
_BLACKLIST = ['id', 'create_uid', 'create_date', 'write_uid', 'write_date',
'user_id', 'active']
_COOP_FORM_FIELD = ['email', 'confirm_email', 'firstname', 'lastname',
'birthdate', 'iban', 'share_product_id',
'address', 'city', 'zip_code', 'country_id', 'phone',
'lang', 'nb_parts', 'total_parts', 'error_msg']
_COMPANY_FORM_FIELD = ['is_company', 'company_register_number', 'company_name',
'company_email', 'confirm_email', 'email', 'firstname',
'lastname', 'birthdate', 'iban', 'share_product_id',
'address', 'city', 'zip_code', 'country_id', 'phone',
'lang', 'nb_parts', 'total_parts', 'error_msg',
'company_type']
_BLACKLIST = [
"id",
"create_uid",
"create_date",
"write_uid",
"write_date",
"user_id",
"active",
]
_COOP_FORM_FIELD = [
"email",
"confirm_email",
"firstname",
"lastname",
"birthdate",
"iban",
"share_product_id",
"address",
"city",
"zip_code",
"country_id",
"phone",
"lang",
"nb_parts",
"total_parts",
"error_msg",
]
_COMPANY_FORM_FIELD = [
"is_company",
"company_register_number",
"company_name",
"company_email",
"confirm_email",
"email",
"firstname",
"lastname",
"birthdate",
"iban",
"share_product_id",
"address",
"city",
"zip_code",
"country_id",
"phone",
"lang",
"nb_parts",
"total_parts",
"error_msg",
"company_type",
]
class WebsiteSubscription(http.Controller): class WebsiteSubscription(http.Controller):
@http.route(['/page/become_cooperator',
'/become_cooperator'],
type='http', auth="public", website=True)
@http.route(
["/page/become_cooperator", "/become_cooperator"],
type="http",
auth="public",
website=True,
)
def display_become_cooperator_page(self, **kwargs): def display_become_cooperator_page(self, **kwargs):
values = {} values = {}
logged = False logged = False
if request.env.user.login != 'public':
if request.env.user.login != "public":
logged = True logged = True
partner = request.env.user.partner_id partner = request.env.user.partner_id
if partner.is_company: if partner.is_company:
@ -47,14 +87,17 @@ class WebsiteSubscription(http.Controller):
values.update(kwargs=kwargs.items()) values.update(kwargs=kwargs.items())
return request.render("easy_my_coop_website.becomecooperator", values) return request.render("easy_my_coop_website.becomecooperator", values)
@http.route(['/page/become_company_cooperator',
'/become_company_cooperator'],
type='http', auth="public", website=True)
@http.route(
["/page/become_company_cooperator", "/become_company_cooperator"],
type="http",
auth="public",
website=True,
)
def display_become_company_cooperator_page(self, **kwargs): def display_become_company_cooperator_page(self, **kwargs):
values = {} values = {}
logged = False logged = False
if request.env.user.login != 'public':
if request.env.user.login != "public":
logged = True logged = True
values = self.fill_values(values, True, logged, True) values = self.fill_values(values, True, logged, True)
@ -62,15 +105,13 @@ class WebsiteSubscription(http.Controller):
if kwargs.get(field): if kwargs.get(field):
values[field] = kwargs.pop(field) values[field] = kwargs.pop(field)
values.update(kwargs=kwargs.items()) values.update(kwargs=kwargs.items())
return request.render("easy_my_coop_website.becomecompanycooperator",
values)
return request.render(
"easy_my_coop_website.becomecompanycooperator", values
)
def preRenderThanks(self, values, kwargs): def preRenderThanks(self, values, kwargs):
""" Allow to be overrided """ """ Allow to be overrided """
return {
'_values': values,
'_kwargs': kwargs,
}
return {"_values": values, "_kwargs": kwargs}
def get_subscription_response(self, values, kwargs): def get_subscription_response(self, values, kwargs):
values = self.preRenderThanks(values, kwargs) values = self.preRenderThanks(values, kwargs)
@ -83,175 +124,198 @@ class WebsiteSubscription(http.Controller):
def get_values_from_user(self, values, is_company): def get_values_from_user(self, values, is_company):
# the subscriber is connected # the subscriber is connected
if request.env.user.login != 'public':
values['logged'] = 'on'
if request.env.user.login != "public":
values["logged"] = "on"
partner = request.env.user.partner_id partner = request.env.user.partner_id
if partner.member or partner.old_member: if partner.member or partner.old_member:
values['already_cooperator'] = 'on'
values["already_cooperator"] = "on"
if partner.bank_ids: if partner.bank_ids:
values['iban'] = partner.bank_ids[0].acc_number
values['address'] = partner.street
values['zip_code'] = partner.zip
values['city'] = partner.city
values['country_id'] = partner.country_id.id
values["iban"] = partner.bank_ids[0].acc_number
values["address"] = partner.street
values["zip_code"] = partner.zip
values["city"] = partner.city
values["country_id"] = partner.country_id.id
if is_company: if is_company:
# company values # company values
values['company_register_number'] = partner.company_register_number
values['company_name'] = partner.name
values['company_email'] = partner.email
values['company_type'] = partner.legal_form
values[
"company_register_number"
] = partner.company_register_number
values["company_name"] = partner.name
values["company_email"] = partner.email
values["company_type"] = partner.legal_form
# contact person values # contact person values
representative = partner.get_representative() representative = partner.get_representative()
values['firstname'] = representative.firstname
values['lastname'] = representative.lastname
values['gender'] = representative.gender
values['email'] = representative.email
values['contact_person_function'] = representative.function
values['birthdate'] = self.get_date_string(representative.birthdate_date)
values['lang'] = representative.lang
values['phone'] = representative.phone
values["firstname"] = representative.firstname
values["lastname"] = representative.lastname
values["gender"] = representative.gender
values["email"] = representative.email
values["contact_person_function"] = representative.function
values["birthdate"] = self.get_date_string(
representative.birthdate_date
)
values["lang"] = representative.lang
values["phone"] = representative.phone
else: else:
values['firstname'] = partner.firstname
values['lastname'] = partner.lastname
values['email'] = partner.email
values['gender'] = partner.gender
values['birthdate'] = self.get_date_string(partner.birthdate_date)
values['lang'] = partner.lang
values['phone'] = partner.phone
values["firstname"] = partner.firstname
values["lastname"] = partner.lastname
values["email"] = partner.email
values["gender"] = partner.gender
values["birthdate"] = self.get_date_string(
partner.birthdate_date
)
values["lang"] = partner.lang
values["phone"] = partner.phone
return values return values
def fill_values(self, values, is_company, logged, load_from_user=False): def fill_values(self, values, is_company, logged, load_from_user=False):
sub_req_obj = request.env['subscription.request']
sub_req_obj = request.env["subscription.request"]
company = request.website.company_id company = request.website.company_id
products = self.get_products_share(is_company) products = self.get_products_share(is_company)
if load_from_user: if load_from_user:
values = self.get_values_from_user(values, is_company) values = self.get_values_from_user(values, is_company)
if is_company: if is_company:
values['is_company'] = 'on'
values["is_company"] = "on"
if logged: if logged:
values['logged'] = 'on'
values['countries'] = self.get_countries()
values['langs'] = self.get_langs()
values['products'] = products
fields_desc = sub_req_obj.sudo().fields_get(['company_type', 'gender'])
values['company_types'] = fields_desc['company_type']['selection']
values['genders'] = fields_desc['gender']['selection']
values['company'] = company
if not values.get('share_product_id'):
values["logged"] = "on"
values["countries"] = self.get_countries()
values["langs"] = self.get_langs()
values["products"] = products
fields_desc = sub_req_obj.sudo().fields_get(["company_type", "gender"])
values["company_types"] = fields_desc["company_type"]["selection"]
values["genders"] = fields_desc["gender"]["selection"]
values["company"] = company
if not values.get("share_product_id"):
for product in products: for product in products:
if product.default_share_product is True: if product.default_share_product is True:
values['share_product_id'] = product.id
values["share_product_id"] = product.id
break break
if not values.get('share_product_id', False) and products:
values['share_product_id'] = products[0].id
if not values.get('country_id'):
if not values.get("share_product_id", False) and products:
values["share_product_id"] = products[0].id
if not values.get("country_id"):
if company.default_country_id: if company.default_country_id:
values['country_id'] = company.default_country_id.id
values["country_id"] = company.default_country_id.id
else: else:
values['country_id'] = '21'
if not values.get('activities_country_id'):
values["country_id"] = "21"
if not values.get("activities_country_id"):
if company.default_country_id: if company.default_country_id:
values['activities_country_id'] = company.default_country_id.id
values["activities_country_id"] = company.default_country_id.id
else: else:
values['activities_country_id'] = '21'
if not values.get('lang'):
values["activities_country_id"] = "21"
if not values.get("lang"):
if company.default_lang_id: if company.default_lang_id:
values['lang'] = company.default_lang_id.code
comp = request.env['res.company']._company_default_get()
values.update({
'display_data_policy': comp.display_data_policy_approval,
'data_policy_required': comp.data_policy_approval_required,
'data_policy_text': comp.data_policy_approval_text,
'display_internal_rules': comp.display_internal_rules_approval,
'internal_rules_required': comp.internal_rules_approval_required,
'internal_rules_text': comp.internal_rules_approval_text,
})
values["lang"] = company.default_lang_id.code
comp = request.env["res.company"]._company_default_get()
values.update(
{
"display_data_policy": comp.display_data_policy_approval,
"data_policy_required": comp.data_policy_approval_required,
"data_policy_text": comp.data_policy_approval_text,
"display_internal_rules": comp.display_internal_rules_approval,
"internal_rules_required": comp.internal_rules_approval_required,
"internal_rules_text": comp.internal_rules_approval_text,
}
)
return values return values
def get_products_share(self, is_company): def get_products_share(self, is_company):
product_obj = request.env['product.template']
product_obj = request.env["product.template"]
products = product_obj.sudo().get_web_share_products(is_company) products = product_obj.sudo().get_web_share_products(is_company)
return products return products
def get_countries(self): def get_countries(self):
countries = request.env['res.country'].sudo().search([])
countries = request.env["res.country"].sudo().search([])
return countries return countries
def get_langs(self): def get_langs(self):
langs = request.env['res.lang'].sudo().search([])
langs = request.env["res.lang"].sudo().search([])
return langs return langs
def get_selected_share(self, kwargs): def get_selected_share(self, kwargs):
prod_obj = request.env['product.template']
prod_obj = request.env["product.template"]
product_id = kwargs.get("share_product_id") product_id = kwargs.get("share_product_id")
return prod_obj.sudo().browse(int(product_id)).product_variant_ids[0] return prod_obj.sudo().browse(int(product_id)).product_variant_ids[0]
def validation(self, kwargs, logged, values, post_file): def validation(self, kwargs, logged, values, post_file):
user_obj = request.env['res.users']
sub_req_obj = request.env['subscription.request']
user_obj = request.env["res.users"]
sub_req_obj = request.env["subscription.request"]
redirect = "easy_my_coop_website.becomecooperator" redirect = "easy_my_coop_website.becomecooperator"
email = kwargs.get('email')
is_company = kwargs.get("is_company") == 'on'
email = kwargs.get("email")
is_company = kwargs.get("is_company") == "on"
if is_company: if is_company:
is_company = True is_company = True
redirect = "easy_my_coop_website.becomecompanycooperator" redirect = "easy_my_coop_website.becomecompanycooperator"
email = kwargs.get('company_email')
email = kwargs.get("company_email")
if 'g-recaptcha-response' not in kwargs or kwargs['g-recaptcha-response'] == '':
if (
"g-recaptcha-response" not in kwargs
or kwargs["g-recaptcha-response"] == ""
):
values = self.fill_values(values, is_company, logged) values = self.fill_values(values, is_company, logged)
values.update(kwargs) values.update(kwargs)
values["error_msg"] = _("the captcha has not been validated,"
" please fill in the captcha")
values["error_msg"] = _(
"the captcha has not been validated,"
" please fill in the captcha"
)
return request.render(redirect, values) return request.render(redirect, values)
elif not request.website.is_captcha_valid( elif not request.website.is_captcha_valid(
kwargs['g-recaptcha-response']):
kwargs["g-recaptcha-response"]
):
values = self.fill_values(values, is_company, logged) values = self.fill_values(values, is_company, logged)
values.update(kwargs) values.update(kwargs)
values["error_msg"] = _("the captcha has not been validated,"
" please fill in the captcha")
values["error_msg"] = _(
"the captcha has not been validated,"
" please fill in the captcha"
)
return request.render(redirect, values) return request.render(redirect, values)
# Check that required field from model subscription_request exists # Check that required field from model subscription_request exists
required_fields = sub_req_obj.sudo().get_required_field() required_fields = sub_req_obj.sudo().get_required_field()
error = set(field for field in required_fields if not values.get(field)) #noqa
error = {
field for field in required_fields if not values.get(field)
} # noqa
if error: if error:
values = self.fill_values(values, is_company, logged) values = self.fill_values(values, is_company, logged)
values["error_msg"] = _("Some mandatory fields have not "
"been filled")
values["error_msg"] = _(
"Some mandatory fields have not " "been filled"
)
values = dict(values, error=error, kwargs=kwargs.items()) values = dict(values, error=error, kwargs=kwargs.items())
return request.render(redirect, values) return request.render(redirect, values)
if not logged and email: if not logged and email:
user = user_obj.sudo().search([('login', '=', email)])
user = user_obj.sudo().search([("login", "=", email)])
if user: if user:
values = self.fill_values(values, is_company, logged) values = self.fill_values(values, is_company, logged)
values.update(kwargs) values.update(kwargs)
values["error_msg"] = _("There is an existing account for this"
" mail address. Please login before "
"fill in the form")
values["error_msg"] = _(
"There is an existing account for this"
" mail address. Please login before "
"fill in the form"
)
return request.render(redirect, values) return request.render(redirect, values)
else: else:
confirm_email = kwargs.get('confirm_email')
confirm_email = kwargs.get("confirm_email")
if email != confirm_email: if email != confirm_email:
values = self.fill_values(values, is_company, logged) values = self.fill_values(values, is_company, logged)
values.update(kwargs) values.update(kwargs)
values["error_msg"] = _("The email and the confirmation "
"email doesn't match.Please check "
"the given mail addresses")
values["error_msg"] = _(
"The email and the confirmation "
"email doesn't match.Please check "
"the given mail addresses"
)
return request.render(redirect, values) return request.render(redirect, values)
company = request.website.company_id company = request.website.company_id
@ -259,8 +323,9 @@ class WebsiteSubscription(http.Controller):
if not post_file: if not post_file:
values = self.fill_values(values, is_company, logged) values = self.fill_values(values, is_company, logged)
values.update(kwargs) values.update(kwargs)
values["error_msg"] = _("You need to upload a"
" scan of your id card")
values["error_msg"] = _(
"You need to upload a" " scan of your id card"
)
return request.render(redirect, values) return request.render(redirect, values)
iban = kwargs.get("iban") iban = kwargs.get("iban")
@ -268,8 +333,7 @@ class WebsiteSubscription(http.Controller):
if not valid: if not valid:
values = self.fill_values(values, is_company, logged) values = self.fill_values(values, is_company, logged)
values["error_msg"] = _("You iban account number"
"is not valid")
values["error_msg"] = _("You iban account number" "is not valid")
return request.render(redirect, values) return request.render(redirect, values)
# check the subscription's amount # check the subscription's amount
@ -282,41 +346,50 @@ class WebsiteSubscription(http.Controller):
share = self.get_selected_share(kwargs) share = self.get_selected_share(kwargs)
if partner.cooperator_type != share.default_code: if partner.cooperator_type != share.default_code:
values = self.fill_values(values, is_company, logged) values = self.fill_values(values, is_company, logged)
values["error_msg"] = (_("You can't subscribe two "
"different types of share"))
values["error_msg"] = _(
"You can't subscribe two "
"different types of share"
)
return request.render(redirect, values) return request.render(redirect, values)
total_amount = float(kwargs.get('total_parts'))
total_amount = float(kwargs.get("total_parts"))
if max_amount > 0 and total_amount > max_amount: if max_amount > 0 and total_amount > max_amount:
values = self.fill_values(values, is_company, logged) values = self.fill_values(values, is_company, logged)
values["error_msg"] = (_("You can't subscribe for an amount that "
"exceed ")
+ str(max_amount)
+ company.currency_id.symbol)
values["error_msg"] = (
_("You can't subscribe for an amount that " "exceed ")
+ str(max_amount)
+ company.currency_id.symbol
)
return request.render(redirect, values) return request.render(redirect, values)
return True return True
@http.route(['/subscription/get_share_product'],
type='json',
auth="public",
methods=['POST'], website=True)
@http.route(
["/subscription/get_share_product"],
type="json",
auth="public",
methods=["POST"],
website=True,
)
def get_share_product(self, share_product_id, **kw): def get_share_product(self, share_product_id, **kw):
product_template = request.env['product.template']
product_template = request.env["product.template"]
product = product_template.sudo().browse(int(share_product_id)) product = product_template.sudo().browse(int(share_product_id))
return { return {
product.id: { product.id: {
'list_price': product.list_price,
'min_qty': product.minimum_quantity,
'force_min_qty': product.force_min_qty
}
"list_price": product.list_price,
"min_qty": product.minimum_quantity,
"force_min_qty": product.force_min_qty,
} }
}
@http.route(['/subscription/subscribe_share'],
type='http',
auth="public", website=True)
@http.route(
["/subscription/subscribe_share"],
type="http",
auth="public",
website=True,
)
def share_subscription(self, **kwargs): def share_subscription(self, **kwargs):
sub_req_obj = request.env['subscription.request']
attach_obj = request.env['ir.attachment']
sub_req_obj = request.env["subscription.request"]
attach_obj = request.env["ir.attachment"]
# List of file to add to ir_attachment once we have the ID # List of file to add to ir_attachment once we have the ID
post_file = [] post_file = []
@ -325,17 +398,21 @@ class WebsiteSubscription(http.Controller):
values = {} values = {}
for field_name, field_value in kwargs.items(): for field_name, field_value in kwargs.items():
if hasattr(field_value, 'filename'):
if hasattr(field_value, "filename"):
post_file.append(field_value) post_file.append(field_value)
elif (field_name in sub_req_obj._fields
and field_name not in _BLACKLIST):
elif (
field_name in sub_req_obj._fields
and field_name not in _BLACKLIST
):
values[field_name] = field_value values[field_name] = field_value
# allow to add some free fields or blacklisted field like ID # allow to add some free fields or blacklisted field like ID
elif field_name not in _TECHNICAL: elif field_name not in _TECHNICAL:
post_description.append("%s: %s" % (field_name, field_value))
post_description.append(
"{}: {}".format(field_name, field_value)
)
logged = kwargs.get("logged") == 'on'
is_company = kwargs.get("is_company") == 'on'
logged = kwargs.get("logged") == "on"
is_company = kwargs.get("is_company") == "on"
response = self.validation(kwargs, logged, values, post_file) response = self.validation(kwargs, logged, values, post_file)
if response is not True: if response is not True:
@ -344,19 +421,19 @@ class WebsiteSubscription(http.Controller):
already_coop = False already_coop = False
if logged: if logged:
partner = request.env.user.partner_id partner = request.env.user.partner_id
values['partner_id'] = partner.id
values["partner_id"] = partner.id
already_coop = partner.member already_coop = partner.member
elif kwargs.get("already_cooperator") == 'on':
elif kwargs.get("already_cooperator") == "on":
already_coop = True already_coop = True
values["already_cooperator"] = already_coop values["already_cooperator"] = already_coop
values["is_company"] = is_company values["is_company"] = is_company
if kwargs.get('data_policy_approved', 'off') == 'on':
values['data_policy_approved'] = True
if kwargs.get("data_policy_approved", "off") == "on":
values["data_policy_approved"] = True
if kwargs.get('internal_rules_approved', 'off') == 'on':
values['internal_rules_approved'] = True
if kwargs.get("internal_rules_approved", "off") == "on":
values["internal_rules_approved"] = True
lastname = kwargs.get("lastname").upper() lastname = kwargs.get("lastname").upper()
firstname = kwargs.get("firstname").title() firstname = kwargs.get("firstname").title()
@ -364,17 +441,18 @@ class WebsiteSubscription(http.Controller):
values["name"] = firstname + " " + lastname values["name"] = firstname + " " + lastname
values["lastname"] = lastname values["lastname"] = lastname
values["firstname"] = firstname values["firstname"] = firstname
values["birthdate"] = datetime.strptime(kwargs.get("birthdate"),
"%d/%m/%Y").date()
values["birthdate"] = datetime.strptime(
kwargs.get("birthdate"), "%d/%m/%Y"
).date()
values["source"] = "website" values["source"] = "website"
values["share_product_id"] = self.get_selected_share(kwargs).id values["share_product_id"] = self.get_selected_share(kwargs).id
if is_company: if is_company:
if kwargs.get("company_register_number", is_company): if kwargs.get("company_register_number", is_company):
values["company_register_number"] = re.sub('[^0-9a-zA-Z]+',
'',
kwargs.get("company_register_number"))
values["company_register_number"] = re.sub(
"[^0-9a-zA-Z]+", "", kwargs.get("company_register_number")
)
subscription_id = sub_req_obj.sudo().create_comp_sub_req(values) subscription_id = sub_req_obj.sudo().create_comp_sub_req(values)
else: else:
subscription_id = sub_req_obj.sudo().create(values) subscription_id = sub_req_obj.sudo().create(values)
@ -382,12 +460,12 @@ class WebsiteSubscription(http.Controller):
if subscription_id: if subscription_id:
for field_value in post_file: for field_value in post_file:
attachment_value = { attachment_value = {
'name': field_value.filename,
'res_name': field_value.filename,
'res_model': 'subscription.request',
'res_id': subscription_id,
'datas': base64.encodestring(field_value.read()),
'datas_fname': field_value.filename,
"name": field_value.filename,
"res_name": field_value.filename,
"res_model": "subscription.request",
"res_id": subscription_id,
"datas": base64.encodestring(field_value.read()),
"datas_fname": field_value.filename,
} }
attach_obj.sudo().create(attachment_value) attach_obj.sudo().create(attachment_value)

23
easy_my_coop_website_portal/__manifest__.py

@ -3,23 +3,16 @@
# - Houssine Bakkali <houssine@coopiteasy.be> # - Houssine Bakkali <houssine@coopiteasy.be>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ {
'name': 'Easy My Coop Website Portal',
"name": "Easy My Coop Website Portal",
"version": "12.0.1.0.0", "version": "12.0.1.0.0",
'depends': [
'easy_my_coop',
'website',
'account',
'portal',
],
'description': """
"depends": ["easy_my_coop", "website", "account", "portal"],
"summary": """
Show cooperator information in the website portal. Show cooperator information in the website portal.
""", """,
'author': 'Coop IT Easy SCRLfs',
'license': 'AGPL-3',
'category': 'Cooperative Management',
"author": "Coop IT Easy SCRLfs",
"license": "AGPL-3",
"category": "Cooperative Management",
"website": "www.coopiteasy.be", "website": "www.coopiteasy.be",
'data': [
'views/easy_my_coop_website_portal_templates.xml',
],
'installable': True,
"data": ["views/easy_my_coop_website_portal_templates.xml"],
"installable": True,
} }

303
easy_my_coop_website_portal/controllers/main.py

@ -4,211 +4,263 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _
from odoo.exceptions import AccessError, MissingError from odoo.exceptions import AccessError, MissingError
from odoo.fields import Date from odoo.fields import Date
from odoo.http import request, route from odoo.http import request, route
from odoo import _
from odoo.addons.portal.controllers.portal import CustomerPortal
from odoo.addons.portal.controllers.portal import pager as portal_pager
from odoo.addons.payment.controllers.portal import PaymentProcessing from odoo.addons.payment.controllers.portal import PaymentProcessing
from odoo.addons.portal.controllers.portal import (
CustomerPortal,
pager as portal_pager,
)
class CooperatorPortalAccount(CustomerPortal): class CooperatorPortalAccount(CustomerPortal):
CustomerPortal.MANDATORY_BILLING_FIELDS.extend(["iban",
"birthdate_date",
"gender"])
CustomerPortal.MANDATORY_BILLING_FIELDS.extend(
["iban", "birthdate_date", "gender"]
)
def _prepare_portal_layout_values(self): def _prepare_portal_layout_values(self):
values = super(CooperatorPortalAccount,
self)._prepare_portal_layout_values()
values = super(
CooperatorPortalAccount, self
)._prepare_portal_layout_values()
# We assume that commercial_partner_id always point to the # We assume that commercial_partner_id always point to the
# partner itself or to the linked partner. So there is no # partner itself or to the linked partner. So there is no
# need to check if the partner is a "contact" or not. # need to check if the partner is a "contact" or not.
partner = request.env.user.partner_id partner = request.env.user.partner_id
coop = partner.commercial_partner_id coop = partner.commercial_partner_id
partner_obj = request.env['res.partner']
coop_bank = request.env['res.partner.bank'].sudo().search(
[('partner_id', 'in', [coop.id])],
limit=1
partner_obj = request.env["res.partner"]
coop_bank = (
request.env["res.partner.bank"]
.sudo()
.search([("partner_id", "in", [coop.id])], limit=1)
)
invoice_mgr = request.env["account.invoice"]
capital_request_count = invoice_mgr.search_count(
[
("state", "in", ["open", "paid", "cancelled"]),
# Get only the release capital request
("release_capital_request", "=", True),
]
) )
invoice_mgr = request.env['account.invoice']
capital_request_count = invoice_mgr.search_count([
('state', 'in', ['open', 'paid', 'cancelled']),
# Get only the release capital request
('release_capital_request', '=', True),
])
invoice_count = invoice_mgr.search_count([
('release_capital_request', '=', False)
])
iban = ''
invoice_count = invoice_mgr.search_count(
[("release_capital_request", "=", False)]
)
iban = ""
if partner.bank_ids: if partner.bank_ids:
iban = partner.bank_ids[0].acc_number iban = partner.bank_ids[0].acc_number
fields_desc = partner_obj.sudo().fields_get(['gender'])
fields_desc = partner_obj.sudo().fields_get(["gender"])
values.update({
'coop': coop,
'coop_bank': coop_bank,
'capital_request_count': capital_request_count,
'invoice_count': invoice_count,
'iban': iban,
'genders': fields_desc['gender']['selection']
})
values.update(
{
"coop": coop,
"coop_bank": coop_bank,
"capital_request_count": capital_request_count,
"invoice_count": invoice_count,
"iban": iban,
"genders": fields_desc["gender"]["selection"],
}
)
return values return values
def details_form_validate(self, data): def details_form_validate(self, data):
error, error_message = super(CooperatorPortalAccount,
self).details_form_validate(data)
sub_req_obj = request.env['subscription.request']
error, error_message = super(
CooperatorPortalAccount, self
).details_form_validate(data)
sub_req_obj = request.env["subscription.request"]
iban = data.get("iban") iban = data.get("iban")
valid = sub_req_obj.check_iban(iban) valid = sub_req_obj.check_iban(iban)
if not valid: if not valid:
error['iban'] = 'error'
error["iban"] = "error"
error_message.append(_("You iban account number is not valid")) error_message.append(_("You iban account number is not valid"))
return error, error_message return error, error_message
@route(['/my/account'], type='http', auth='user', website=True)
@route(["/my/account"], type="http", auth="user", website=True)
def account(self, redirect=None, **post): def account(self, redirect=None, **post):
res = super(CooperatorPortalAccount, self).account(
redirect, **post)
if not res.qcontext.get('error'):
res = super(CooperatorPortalAccount, self).account(redirect, **post)
if not res.qcontext.get("error"):
partner = request.env.user.partner_id partner = request.env.user.partner_id
partner_bank = request.env['res.partner.bank']
iban = post.get('iban')
partner_bank = request.env["res.partner.bank"]
iban = post.get("iban")
if iban: if iban:
if partner.bank_ids: if partner.bank_ids:
bank_account = partner.bank_ids[0] bank_account = partner.bank_ids[0]
bank_account.acc_number = iban bank_account.acc_number = iban
else: else:
partner_bank.sudo().create({
'partner_id': partner.id,
'acc_number': iban
})
partner_bank.sudo().create(
{"partner_id": partner.id, "acc_number": iban}
)
return res return res
@route(['/my/invoices', '/my/invoices/page/<int:page>'], type='http',
auth="user", website=True)
def portal_my_invoices(self, page=1, date_begin=None, date_end=None,
sortby=None, **kw):
@route(
["/my/invoices", "/my/invoices/page/<int:page>"],
type="http",
auth="user",
website=True,
)
def portal_my_invoices(
self, page=1, date_begin=None, date_end=None, sortby=None, **kw
):
res = super(CooperatorPortalAccount, self).portal_my_invoices( res = super(CooperatorPortalAccount, self).portal_my_invoices(
page, date_begin, date_end, sortby, **kw)
invoice_obj = request.env['account.invoice']
page, date_begin, date_end, sortby, **kw
)
invoice_obj = request.env["account.invoice"]
qcontext = res.qcontext qcontext = res.qcontext
if qcontext: if qcontext:
invoices = invoice_obj.search([('release_capital_request', '=', False)])
invoices = invoice_obj.search(
[("release_capital_request", "=", False)]
)
invoice_count = len(invoices) invoice_count = len(invoices)
qcontext['invoices'] = invoices
qcontext['pager']['invoice_count'] = invoice_count
qcontext["invoices"] = invoices
qcontext["pager"]["invoice_count"] = invoice_count
return res return res
@route( @route(
['/my/release_capital_request',
'/my/release_capital_request/page/<int:page>'],
type='http', auth="user", website=True)
def portal_my_release_capital_request(self, page=1, date_begin=None,
date_end=None, sortby=None, **kw):
[
"/my/release_capital_request",
"/my/release_capital_request/page/<int:page>",
],
type="http",
auth="user",
website=True,
)
def portal_my_release_capital_request(
self, page=1, date_begin=None, date_end=None, sortby=None, **kw
):
"""Render a page with the list of release capital request. """Render a page with the list of release capital request.
A release capital request is an invoice with a flag that tell A release capital request is an invoice with a flag that tell
if it's a capital request or not. if it's a capital request or not.
""" """
values = self._prepare_portal_layout_values() values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id partner = request.env.user.partner_id
invoice_mgr = request.env['account.invoice']
invoice_mgr = request.env["account.invoice"]
domain = [ domain = [
('partner_id', 'in',
[partner.commercial_partner_id.id]),
('state', 'in', ['open', 'paid', 'cancelled']),
("partner_id", "in", [partner.commercial_partner_id.id]),
("state", "in", ["open", "paid", "cancelled"]),
# Get only the release capital request # Get only the release capital request
('release_capital_request', '=', True),
("release_capital_request", "=", True),
] ]
archive_groups = self._get_archive_groups_sudo('account.invoice',
domain)
archive_groups = self._get_archive_groups_sudo(
"account.invoice", domain
)
if date_begin and date_end: if date_begin and date_end:
domain += [('create_date', '>=', date_begin),
('create_date', '<', date_end)]
domain += [
("create_date", ">=", date_begin),
("create_date", "<", date_end),
]
# count for pager # count for pager
capital_request_count = invoice_mgr.sudo().search_count(domain) capital_request_count = invoice_mgr.sudo().search_count(domain)
# pager # pager
pager = portal_pager( pager = portal_pager(
url="/my/release_capital_request", url="/my/release_capital_request",
url_args={'date_begin': date_begin, 'date_end': date_end,
'sortby': sortby},
url_args={
"date_begin": date_begin,
"date_end": date_end,
"sortby": sortby,
},
total=capital_request_count, total=capital_request_count,
page=page, page=page,
step=self._items_per_page
step=self._items_per_page,
) )
# content according to pager and archive selected # content according to pager and archive selected
invoices = invoice_mgr.sudo().search( invoices = invoice_mgr.sudo().search(
domain, limit=self._items_per_page, offset=pager['offset'])
values.update({
'date': date_begin,
'capital_requests': invoices,
'page_name': 'Release request',
'pager': pager,
'archive_groups': archive_groups,
'default_url': '/my/release_capital_request',
})
domain, limit=self._items_per_page, offset=pager["offset"]
)
values.update(
{
"date": date_begin,
"capital_requests": invoices,
"page_name": "Release request",
"pager": pager,
"archive_groups": archive_groups,
"default_url": "/my/release_capital_request",
}
)
return request.render( return request.render(
"easy_my_coop_website_portal.portal_my_capital_releases",
values
"easy_my_coop_website_portal.portal_my_capital_releases", values
) )
@route(['/my/invoices/<int:invoice_id>'],
type='http', auth="public", website=True)
def portal_my_invoice_detail(self, invoice_id, access_token=None,
report_type=None, download=False, **kw):
@route(
["/my/invoices/<int:invoice_id>"],
type="http",
auth="public",
website=True,
)
def portal_my_invoice_detail(
self,
invoice_id,
access_token=None,
report_type=None,
download=False,
**kw
):
# override in order to not retrieve release capital request as invoices # override in order to not retrieve release capital request as invoices
try: try:
invoice_sudo = self._document_check_access('account.invoice',
invoice_id,
access_token)
invoice_sudo = self._document_check_access(
"account.invoice", invoice_id, access_token
)
except (AccessError, MissingError): except (AccessError, MissingError):
return request.redirect('/my')
return request.redirect("/my")
if invoice_sudo.release_capital_request: if invoice_sudo.release_capital_request:
report_ref = 'easy_my_coop.action_cooperator_invoices'
report_ref = "easy_my_coop.action_cooperator_invoices"
else: else:
report_ref = 'account.account_invoices'
if report_type in ('html', 'pdf', 'text'):
return self._show_report(model=invoice_sudo,
report_type=report_type,
report_ref=report_ref,
download=download)
values = self._invoice_get_page_view_values(invoice_sudo, access_token,
**kw)
PaymentProcessing.remove_payment_transaction(invoice_sudo.transaction_ids)
report_ref = "account.account_invoices"
if report_type in ("html", "pdf", "text"):
return self._show_report(
model=invoice_sudo,
report_type=report_type,
report_ref=report_ref,
download=download,
)
values = self._invoice_get_page_view_values(
invoice_sudo, access_token, **kw
)
PaymentProcessing.remove_payment_transaction(
invoice_sudo.transaction_ids
)
return request.render("account.portal_invoice_page", values) return request.render("account.portal_invoice_page", values)
@route(['/my/cooperator_certificate/pdf'],
type='http', auth="user", website=True)
@route(
["/my/cooperator_certificate/pdf"],
type="http",
auth="user",
website=True,
)
def get_cooperator_certificat(self, **kw): def get_cooperator_certificat(self, **kw):
"""Render the cooperator certificate pdf of the current user""" """Render the cooperator certificate pdf of the current user"""
partner = request.env.user.partner_id partner = request.env.user.partner_id
return self._show_report( return self._show_report(
model=partner,
report_type='pdf',
report_ref='easy_my_coop.action_cooperator_report_certificat',
download=True
)
model=partner,
report_type="pdf",
report_ref="easy_my_coop.action_cooperator_report_certificat",
download=True,
)
def _render_pdf(self, pdf, filename): def _render_pdf(self, pdf, filename):
"""Render a http response for a pdf""" """Render a http response for a pdf"""
pdfhttpheaders = [ pdfhttpheaders = [
('Content-Disposition', 'inline; filename="%s.pdf"' % filename),
('Content-Type', 'application/pdf'),
('Content-Length', len(pdf))
("Content-Disposition", 'inline; filename="%s.pdf"' % filename),
("Content-Type", "application/pdf"),
("Content-Length", len(pdf)),
] ]
return request.make_response(pdf, headers=pdfhttpheaders) return request.make_response(pdf, headers=pdfhttpheaders)
def _get_archive_groups_sudo(self, model, domain=None, fields=None,
groupby="create_date",
order="create_date desc"):
def _get_archive_groups_sudo(
self,
model,
domain=None,
fields=None,
groupby="create_date",
order="create_date desc",
):
"""Same as the one from website_portal_v10 except that it runs """Same as the one from website_portal_v10 except that it runs
in root. in root.
""" """
@ -217,10 +269,13 @@ class CooperatorPortalAccount(CustomerPortal):
if domain is None: if domain is None:
domain = [] domain = []
if fields is None: if fields is None:
fields = ['name', 'create_date']
fields = ["name", "create_date"]
groups = [] groups = []
for group in request.env[model].sudo().read_group(
domain, fields=fields, groupby=groupby, orderby=order):
for group in (
request.env[model]
.sudo()
.read_group(domain, fields=fields, groupby=groupby, orderby=order)
):
label = group[groupby] label = group[groupby]
date_begin = date_end = None date_begin = date_end = None
for leaf in group["__domain"]: for leaf in group["__domain"]:
@ -229,10 +284,12 @@ class CooperatorPortalAccount(CustomerPortal):
date_begin = leaf[2] date_begin = leaf[2]
elif leaf[1] == "<": elif leaf[1] == "<":
date_end = leaf[2] date_end = leaf[2]
groups.append({
'date_begin': Date.to_string(Date.from_string(date_begin)),
'date_end': Date.to_string(Date.from_string(date_end)),
'name': label,
'item_count': group[groupby + '_count']
})
groups.append(
{
"date_begin": Date.to_string(Date.from_string(date_begin)),
"date_end": Date.to_string(Date.from_string(date_end)),
"name": label,
"item_count": group[groupby + "_count"],
}
)
return groups return groups

33
easy_my_coop_website_taxshelter/__manifest__.py

@ -3,27 +3,20 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ {
'name': 'Easy My Coop Tax Shelter Website',
"name": "Easy My Coop Tax Shelter Website",
"version": "12.0.1.0.0", "version": "12.0.1.0.0",
'depends': [
'website',
'website_portal_v10',
'easy_my_coop_taxshelter_report',
'report',
"depends": [
"website",
"website_portal_v10",
"easy_my_coop_taxshelter_report",
"report",
], ],
'description': """
Give access to Tax Shelter Report in the website portal.
""",
'author': 'Coop IT Easy SCRLfs',
'license': 'AGPL-3',
'category': 'Cooperative Management',
"summary": "Give access to Tax Shelter Report in the website portal.",
"author": "Coop IT Easy SCRLfs",
"license": "AGPL-3",
"category": "Cooperative Management",
"website": "www.coopiteasy.be", "website": "www.coopiteasy.be",
'category': 'Cooperative Management',
'data': [
'views/easy_my_coop_website_taxshelter_templates.xml',
],
'installable': False,
'application': False,
"data": ["views/easy_my_coop_website_taxshelter_templates.xml"],
"installable": False,
"application": False,
} }

122
easy_my_coop_website_taxshelter/controllers/main.py

@ -1,89 +1,93 @@
# -*- coding: utf-8 -*-
# Copyright 2017-2018 Coop IT Easy SCRLfs <remy@gcoopiteasy.be> # Copyright 2017-2018 Coop IT Easy SCRLfs <remy@gcoopiteasy.be>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from werkzeug.exceptions import Forbidden, NotFound
from openerp import http from openerp import http
from openerp.addons.website_portal_v10.controllers.main import WebsiteAccount
from openerp.exceptions import AccessError, MissingError from openerp.exceptions import AccessError, MissingError
from openerp.http import request from openerp.http import request
from openerp.addons.website_portal_v10.controllers.main import WebsiteAccount
from werkzeug.exceptions import Forbidden, NotFound
class TaxShelterWebsiteAccount(WebsiteAccount): class TaxShelterWebsiteAccount(WebsiteAccount):
@http.route() @http.route()
def account(self): def account(self):
""" Add Tax Shelter Certificate to main account page """ """ Add Tax Shelter Certificate to main account page """
response = super(TaxShelterWebsiteAccount, self).account() response = super(TaxShelterWebsiteAccount, self).account()
partner = request.env.user.partner_id partner = request.env.user.partner_id
tax_shelter_mgr = request.env['tax.shelter.certificate']
tax_shelter_count = tax_shelter_mgr.sudo().search_count([
('partner_id', 'in', [partner.commercial_partner_id.id]),
])
tax_shelter_mgr = request.env["tax.shelter.certificate"]
tax_shelter_count = tax_shelter_mgr.sudo().search_count(
[("partner_id", "in", [partner.commercial_partner_id.id])]
)
response.qcontext.update({
'tax_shelter_count': tax_shelter_count,
})
response.qcontext.update({"tax_shelter_count": tax_shelter_count})
return response return response
@http.route( @http.route(
['/my/tax_shelter_certificate',
'/my/tax_shelter_certificate/page/<int:page>'],
type='http', auth="user", website=True)
def portal_my_tax_shelter_certificate(self, page=1, date_begin=None,
date_end=None, **kw):
[
"/my/tax_shelter_certificate",
"/my/tax_shelter_certificate/page/<int:page>",
],
type="http",
auth="user",
website=True,
)
def portal_my_tax_shelter_certificate(
self, page=1, date_begin=None, date_end=None, **kw
):
"""Render a page that lits the tax shelter report: """Render a page that lits the tax shelter report:
* Tax Shelter Certificates * Tax Shelter Certificates
* Shares Certifcates * Shares Certifcates
""" """
values = self._prepare_portal_layout_values() values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id partner = request.env.user.partner_id
tax_shelter_mgr = request.env['tax.shelter.certificate']
tax_shelter_mgr = request.env["tax.shelter.certificate"]
domain = [
('partner_id', 'in', [partner.commercial_partner_id.id]),
]
domain = [("partner_id", "in", [partner.commercial_partner_id.id])]
if date_begin and date_end: if date_begin and date_end:
domain += [('create_date', '>=', date_begin),
('create_date', '<', date_end)]
domain += [
("create_date", ">=", date_begin),
("create_date", "<", date_end),
]
# count for pager # count for pager
tax_shelter_count = tax_shelter_mgr.sudo().search_count(domain) tax_shelter_count = tax_shelter_mgr.sudo().search_count(domain)
# pager # pager
pager = request.website.pager( pager = request.website.pager(
url="/my/tax_shelter_certificate", url="/my/tax_shelter_certificate",
url_args={'date_begin': date_begin, 'date_end': date_end},
url_args={"date_begin": date_begin, "date_end": date_end},
total=tax_shelter_count, total=tax_shelter_count,
page=page, page=page,
step=self._items_per_page
step=self._items_per_page,
) )
# content according to pager and archive selected # content according to pager and archive selected
tax_shelters = tax_shelter_mgr.sudo().search( tax_shelters = tax_shelter_mgr.sudo().search(
domain, limit=self._items_per_page, offset=pager['offset'])
domain, limit=self._items_per_page, offset=pager["offset"]
)
tax_shelters = tax_shelters.sorted( tax_shelters = tax_shelters.sorted(
key=lambda r: r.declaration_id.fiscal_year,
reverse=True
key=lambda r: r.declaration_id.fiscal_year, reverse=True
)
values.update(
{
"date": date_begin,
"tax_shelters": tax_shelters,
"page_name": "invoice",
"pager": pager,
"default_url": "/my/tax_shelter_certificate",
}
) )
values.update({
'date': date_begin,
'tax_shelters': tax_shelters,
'page_name': 'invoice',
'pager': pager,
'default_url': '/my/tax_shelter_certificate',
})
return request.website.render( return request.website.render(
"easy_my_coop_website_taxshelter.portal_my_tax_shelter",
values
"easy_my_coop_website_taxshelter.portal_my_tax_shelter", values
) )
@http.route(['/my/taxshelter_certificate/pdf/<int:oid>'],
type='http', auth="user", website=True)
@http.route(
["/my/taxshelter_certificate/pdf/<int:oid>"],
type="http",
auth="user",
website=True,
)
def get_taxshelter_certificate_pdf(self, oid=-1): def get_taxshelter_certificate_pdf(self, oid=-1):
"""Render the Tax Shelter Certificate pdf of the given Tax """Render the Tax Shelter Certificate pdf of the given Tax
Shelter Report Shelter Report
@ -91,7 +95,7 @@ class TaxShelterWebsiteAccount(WebsiteAccount):
# Get the subscription certificate and raise an error if the user # Get the subscription certificate and raise an error if the user
# is not allowed to access to it or if the object is not found. # is not allowed to access to it or if the object is not found.
partner = request.env.user.partner_id partner = request.env.user.partner_id
tax_shelter_mgr = request.env['tax.shelter.certificate']
tax_shelter_mgr = request.env["tax.shelter.certificate"]
tax_shelter = tax_shelter_mgr.sudo().browse(oid) tax_shelter = tax_shelter_mgr.sudo().browse(oid)
try: try:
if tax_shelter.partner_id != partner: if tax_shelter.partner_id != partner:
@ -101,19 +105,22 @@ class TaxShelterWebsiteAccount(WebsiteAccount):
except MissingError: except MissingError:
raise NotFound() raise NotFound()
# Get the pdf # Get the pdf
report_mgr = request.env['report']
report_mgr = request.env["report"]
pdf = report_mgr.sudo().get_pdf( pdf = report_mgr.sudo().get_pdf(
tax_shelter, tax_shelter,
'easy_my_coop_taxshelter_report.tax_shelter_subscription_report'
"easy_my_coop_taxshelter_report.tax_shelter_subscription_report",
) )
filename = "Tax Shelter Certificate - %s - %s" % (
partner.name,
tax_shelter.declaration_id.fiscal_year
filename = "Tax Shelter Certificate - {} - {}".format(
partner.name, tax_shelter.declaration_id.fiscal_year
) )
return self._render_pdf(pdf, filename) return self._render_pdf(pdf, filename)
@http.route(['/my/share_certificate/pdf/<int:oid>'],
type='http', auth="user", website=True)
@http.route(
["/my/share_certificate/pdf/<int:oid>"],
type="http",
auth="user",
website=True,
)
def get_share_certificate_pdf(self, oid=-1): def get_share_certificate_pdf(self, oid=-1):
"""Render the Share Certificate pdf of the given Tax Shelter """Render the Share Certificate pdf of the given Tax Shelter
Report Report
@ -121,7 +128,7 @@ class TaxShelterWebsiteAccount(WebsiteAccount):
# Get the share certificate and raise an error if the user # Get the share certificate and raise an error if the user
# is not allowed to access to it or if the object is not found. # is not allowed to access to it or if the object is not found.
partner = request.env.user.partner_id partner = request.env.user.partner_id
tax_shelter_mgr = request.env['tax.shelter.certificate']
tax_shelter_mgr = request.env["tax.shelter.certificate"]
tax_shelter = tax_shelter_mgr.sudo().browse(oid) tax_shelter = tax_shelter_mgr.sudo().browse(oid)
try: try:
if tax_shelter.partner_id != partner: if tax_shelter.partner_id != partner:
@ -131,22 +138,21 @@ class TaxShelterWebsiteAccount(WebsiteAccount):
except MissingError: except MissingError:
raise NotFound() raise NotFound()
# Get the pdf # Get the pdf
report_mgr = request.env['report']
report_mgr = request.env["report"]
pdf = report_mgr.sudo().get_pdf( pdf = report_mgr.sudo().get_pdf(
tax_shelter, tax_shelter,
'easy_my_coop_taxshelter_report.tax_shelter_shares_report'
"easy_my_coop_taxshelter_report.tax_shelter_shares_report",
) )
filename = "Share Certificate - %s - %s" % (
partner.name,
tax_shelter.declaration_id.fiscal_year
filename = "Share Certificate - {} - {}".format(
partner.name, tax_shelter.declaration_id.fiscal_year
) )
return self._render_pdf(pdf, filename) return self._render_pdf(pdf, filename)
def _render_pdf(self, pdf, filename): def _render_pdf(self, pdf, filename):
"""Render a http response for a pdf""" """Render a http response for a pdf"""
pdfhttpheaders = [ pdfhttpheaders = [
('Content-Disposition', 'inline; filename="%s.pdf"' % filename),
('Content-Type', 'application/pdf'),
('Content-Length', len(pdf))
("Content-Disposition", 'inline; filename="%s.pdf"' % filename),
("Content-Type", "application/pdf"),
("Content-Length", len(pdf)),
] ]
return request.make_response(pdf, headers=pdfhttpheaders) return request.make_response(pdf, headers=pdfhttpheaders)

16
partner_age/__manifest__.py

@ -5,18 +5,12 @@
{ {
"name": "Partner Age", "name": "Partner Age",
"version": "12.0.1.0.0", "version": "12.0.1.0.0",
"depends": [
"easy_my_coop",
"partner_contact_birthdate"],
"depends": ["easy_my_coop", "partner_contact_birthdate"],
"author": "Houssine BAKKALI <houssine.bakkali@gmail.com>", "author": "Houssine BAKKALI <houssine.bakkali@gmail.com>",
"category": "Cooperative management", "category": "Cooperative management",
'website': "www.coopiteasy.be",
"website": "www.coopiteasy.be",
"license": "AGPL-3", "license": "AGPL-3",
"description": """
This module computes the age of the partner.
""",
'data': [
'view/partner_view.xml',
],
'installable': True,
"summary": "This module computes the age of the partner.",
"data": ["view/partner_view.xml"],
"installable": True,
} }

39
partner_age/models/partner.py

@ -1,34 +1,41 @@
from datetime import datetime from datetime import datetime
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as OE_DFORMAT
from openerp import models, fields, api
from openerp import api, fields, models
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as OE_DFORMAT
class ResPartner(models.Model): class ResPartner(models.Model):
_inherit = 'res.partner'
_inherit = "res.partner"
def _search_age(self, operator, value): def _search_age(self, operator, value):
if operator not in ('=', '!=', '<', '<=', '>', '>=', 'in', 'not in'):
if operator not in ("=", "!=", "<", "<=", ">", ">=", "in", "not in"):
return [] return []
query = """SELECT id query = """SELECT id
FROM "%s" FROM "%s"
WHERE extract(year from age(CURRENT_DATE, WHERE extract(year from age(CURRENT_DATE,
birthdate_date)) %s %%s""" % \
(self._table, operator)
birthdate_date)) %s %%s""" % (
self._table,
operator,
)
self.env.cr.execute(query, (value,)) self.env.cr.execute(query, (value,))
ids = [t[0] for t in self.env.cr.fetchall()] ids = [t[0] for t in self.env.cr.fetchall()]
return [('id', 'in', ids)]
return [("id", "in", ids)]
@api.one
@api.depends('birthdate_date')
@api.multi
@api.depends("birthdate_date")
def _compute_age(self): def _compute_age(self):
self.ensure_one()
if self.birthdate_date: if self.birthdate_date:
dBday = datetime.strptime(str(self.birthdate_date),
OE_DFORMAT).date()
dBday = datetime.strptime(
str(self.birthdate_date), OE_DFORMAT
).date()
dToday = datetime.now().date() dToday = datetime.now().date()
self.age = dToday.year - dBday.year - ((
dToday.month, dToday.day) < (dBday.month, dBday.day))
self.age = (
dToday.year
- dBday.year
- ((dToday.month, dToday.day) < (dBday.month, dBday.day))
)
age = fields.Integer(string='Age',
compute='_compute_age',
search='_search_age')
age = fields.Integer(
string="Age", compute="_compute_age", search="_search_age"
)

28
theme_light/__manifest__.py

@ -2,21 +2,15 @@
# - Houssine BAKKALI - <houssine@coopiteasy.be> # - Houssine BAKKALI - <houssine@coopiteasy.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{ {
'name': 'Theme light',
'description': 'extract of the theme zen',
'category': 'Website',
'version': '12.0.1.0.0',
'author': 'Benjamin Dugardin',
'author': 'Houssine BAKKALI',
'website': "www.coopiteasy.be",
'depends': ['base',
'web',
'website_theme_install'
],
'data': [
'views/layout_template.xml',
'report/header_report_G002.xml',
],
'installable': True,
'application': True,
"name": "Theme light",
"summary": "extract of the theme zen",
"license": "AGPL-3",
"category": "Website",
"version": "12.0.1.0.0",
"author": "Benjamin Dugardin," "Houssine BAKKALI," "Coop IT Easy SCRLfs",
"website": "www.coopiteasy.be",
"depends": ["base", "web", "website_theme_install"],
"data": ["views/layout_template.xml", "report/header_report_G002.xml"],
"installable": True,
"application": True,
} }

32
website_recaptcha_reloaded/__manifest__.py

@ -1,26 +1,14 @@
# Copyright 2004 Tech-Receptives Solutions Pvt. Ltd. # Copyright 2004 Tech-Receptives Solutions Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{ {
'name': 'Website reCAPTCHA Reloaded',
'version': '12.0.0.1',
'category': 'Website',
'depends': ['website'],
'author': 'Tech Receptives',
'license': 'AGPL-3',
'website': 'https://www.techreceptives.com',
'description': """
Odoo Website reCAPTCHA Reloaded
================================
This modules allows you to integrate Google reCAPTCHA v2.0 to your website
forms. You can configure your Google reCAPTCHA site and public keys
in "Settings" -> "Website Settings"
You will need to install various website_<module>_recaptcha modules
to use it in your various pages.
""",
'data': [
'views/website_view.xml',
'views/res_config.xml',
],
'installable': True,
"name": "Website reCAPTCHA Reloaded",
"version": "12.0.0.0.1",
"category": "Website",
"depends": ["website"],
"author": "Tech Receptives",
"license": "AGPL-3",
"website": "https://www.techreceptives.com",
"summary": "Add google recaptcha to forms.",
"data": ["views/website_view.xml", "views/res_config.xml"],
"installable": True,
} }

18
website_recaptcha_reloaded/models/res_config.py

@ -4,25 +4,23 @@
from odoo import api, fields, models from odoo import api, fields, models
class website_config_settings(models.TransientModel):
_inherit = 'res.config.settings'
class WebsiteConfigSettings(models.TransientModel):
_inherit = "res.config.settings"
recaptcha_key_site = fields.Char( recaptcha_key_site = fields.Char(
related='website_id.recaptcha_key_site',
readonly=False,
related="website_id.recaptcha_key_site", readonly=False
) )
recaptcha_key_secret = fields.Char( recaptcha_key_secret = fields.Char(
related='website_id.recaptcha_key_secret',
readonly=False,
related="website_id.recaptcha_key_secret", readonly=False
) )
has_google_recaptcha = fields.Boolean( has_google_recaptcha = fields.Boolean(
'Google reCaptcha',
compute='_compute_has_google_recaptcha',
inverse='_inverse_has_google_recaptcha',
"Google reCaptcha",
compute="_compute_has_google_recaptcha",
inverse="_inverse_has_google_recaptcha",
readonly=False, readonly=False,
) )
@api.depends('website_id')
@api.depends("website_id")
def _compute_has_google_recaptcha(self): def _compute_has_google_recaptcha(self):
self.has_google_recaptcha = bool(self.recaptcha_key_site) self.has_google_recaptcha = bool(self.recaptcha_key_site)

39
website_recaptcha_reloaded/website.py

@ -1,15 +1,16 @@
# Copyright 2019 Simone Orsi - Camptocamp SA # Copyright 2019 Simone Orsi - Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
import requests import requests
URL = 'https://www.google.com/recaptcha/api/siteverify'
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
URL = "https://www.google.com/recaptcha/api/siteverify"
class Website(models.Model): class Website(models.Model):
_inherit = 'website'
_inherit = "website"
recaptcha_key_site = fields.Char() recaptcha_key_site = fields.Char()
recaptcha_key_secret = fields.Char() recaptcha_key_secret = fields.Char()
@ -17,27 +18,31 @@ class Website(models.Model):
@api.model @api.model
def _get_error_message(self, errorcode=None): def _get_error_message(self, errorcode=None):
mapping = { mapping = {
'missing-input-secret': _('The secret parameter is missing.'),
'invalid-input-secret':
_('The secret parameter is invalid or malformed.'),
'missing-input-response': _('The response parameter is missing.'),
'invalid-input-response':
_('The response parameter is invalid or malformed.'),
"missing-input-secret": _("The secret parameter is missing."),
"invalid-input-secret": _(
"The secret parameter is invalid or malformed."
),
"missing-input-response": _("The response parameter is missing."),
"invalid-input-response": _(
"The response parameter is invalid or malformed."
),
} }
return mapping.get(errorcode, _('There was a problem with '
'the captcha entry.'))
return mapping.get(
errorcode, _("There was a problem with " "the captcha entry.")
)
def is_captcha_valid(self, response): def is_captcha_valid(self, response):
get_res = {'secret': self.recaptcha_key_secret,
'response': response}
get_res = {"secret": self.recaptcha_key_secret, "response": response}
res = requests.post(URL, data=get_res).json() res = requests.post(URL, data=get_res).json()
error_msg = "\n".join(self._get_error_message(error)
for error in res.get('error-codes', []))
error_msg = "\n".join(
self._get_error_message(error)
for error in res.get("error-codes", [])
)
if error_msg: if error_msg:
raise ValidationError(error_msg) raise ValidationError(error_msg)
if not res.get('success'):
if not res.get("success"):
raise ValidationError(self._get_error_message()) raise ValidationError(self._get_error_message())
return True return True
Loading…
Cancel
Save