Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • lefilament/cgscop/cgscop_cotisation
  • hsilvant/cgscop_cotisation
2 results
Select Git revision
Show changes
Commits on Source (29)
Showing
with 671 additions and 98 deletions
......@@ -9,7 +9,7 @@ exclude: |
# Maybe reactivate this when all README files include prettier ignore tags?
^README\.md$|
# Library files can have extraneous formatting (even minimized)
static/(src/)?lib/|
/static/(src/)?lib/|
# Repos using Sphinx to generate docs don't need prettying
^docs/_templates/.*\.html$|
# You don't usually want a bot to modify your legal texts
......@@ -27,6 +27,11 @@ repos:
entry: found forbidden files; remove them
language: fail
files: "\\.rej$"
- id: en-po-files
name: en.po files cannot exist
entry: found a en.po file
language: fail
files: '[a-zA-Z0-9_]*/i18n/en\.po$'
- repo: https://github.com/oca/maintainer-tools
rev: ab1d7f6
hooks:
......@@ -46,7 +51,7 @@ repos:
- --remove-duplicate-keys
- --remove-unused-variables
- repo: https://github.com/psf/black
rev: 20.8b1
rev: 22.3.0
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-prettier
......@@ -54,6 +59,7 @@ repos:
hooks:
- id: prettier
name: prettier (with plugin-xml)
exclude: ^datas/
additional_dependencies:
- "prettier@2.1.2"
- "@prettier/plugin-xml@0.12.0"
......@@ -96,32 +102,28 @@ repos:
- id: pyupgrade
args: ["--keep-percent-format"]
- repo: https://github.com/PyCQA/isort
rev: 5.5.1
rev: 5.12.0
hooks:
- id: isort
name: isort except __init__.py
args:
- --settings=.
exclude: /__init__\.py$
- repo: https://gitlab.com/PyCQA/flake8
- repo: https://github.com/PyCQA/flake8
rev: 3.8.3
hooks:
- id: flake8
name: flake8
additional_dependencies: ["flake8-bugbear==20.1.4"]
- repo: https://github.com/PyCQA/pylint
rev: pylint-2.5.3
- repo: https://github.com/OCA/pylint-odoo
rev: 7.0.2
hooks:
- id: pylint
- id: pylint_odoo
name: pylint with optional checks
args:
- --rcfile=.pylintrc
- --exit-zero
verbose: true
additional_dependencies: &pylint_deps
- pylint-odoo==3.5.0
- id: pylint
name: pylint with mandatory checks
- id: pylint_odoo
args:
- --rcfile=.pylintrc-mandatory
additional_dependencies: *pylint_deps
......@@ -10,6 +10,7 @@
"installable": True,
"depends": [
"account",
"account_banking_mandate",
"account_banking_sepa_direct_debit",
"account_payment_order",
"cgscop_account",
......@@ -19,12 +20,16 @@
],
"data": [
"security/ir.model.access.csv",
"datas/mail_data.xml",
"views/account_banking_mandate.xml",
"views/account_move.xml",
"views/account_payment_order.xml",
"views/account_payment_line.xml",
"views/res_config_settings.xml",
"views/res_partner.xml",
"report/scop_contribution_report.xml",
"wizard/account_payment_line_create_view.xml",
"wizard/account_banking_mandate_change_wizard.xml",
],
"qweb": [
"static/src/xml/*.xml",
......
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<!-- Email d'avis de prélèvement -->
<record id="email_template_payment_order" model="mail.template">
<field name="name">CG SCOP : Prélèvements</field>
<field name="model_id" ref="account_payment_order.model_account_payment_order"/>
<field name="email_from">"Confédération Générale des Scop et Scic" &lt;administratif.cg@scop.coop&gt;</field>
<field name="reply_to">"Confédération Générale des Scop et Scic" &lt;administratif.cg@scop.coop&gt;</field>
<field name="partner_to">${object.get_recipients()}</field>
<field name="subject">CG SCOP : Avis de prélèvement</field>
<field name="body_html" type="html">
<div style="margin: 0px; padding: 0px;">
<p style="margin: 0px; padding: 0px; font-size: 13px;">
<p>${object.get_email_values().get("partner_id").member_number} - ${object.get_email_values().get("partner_id").name}</p>
<p>&#160;</p>
<p>Chère Coopératrice, Cher Coopérateur,</p>
<p>&#160;</p>
<p>&#160;</p>
<p>
Vous avez choisi de régler vos cotisations à la Confédération générale des Scop et des Scic par prélèvement bancaire.
</p>
<p>
Nous vous informons que nous avons procédé ce jour à un ordre de prélèvement qui sera présenté au débit de votre compte le ${object.get_email_values().get("date").strftime('%d/%m/%Y')}.
</p>
<p>&#160;</p>
<p>
Le mandat de prélèvement enregistré pour votre coopérative est le suivant : ${object.get_email_values().get("bank")}
</p>
<p>&#160;</p>
<p>
Ce courriel vous est envoyé à titre informatif, l’ordre de prélèvement ne peut plus être arrêté en banque, sauf par vos soins en prenant contact avec votre établissement bancaire.
</p>
<p>Dans ce cas, nous vous remercions de bien vouloir nous en informer.</p>
<p>&#160;</p>
<p>
En cas de difficulté économique, nous vous invitons également à vous rapprocher de votre délégation régionale.
</p>
<p>&#160;</p>
<p>
Ce prélèvement correspond au paiement des cotisations :
<ul>
% for line in object.get_email_values().get("deadline"):
% set quarter = "er" if line.get("quarter") == "1" else "ème"
<li>
${line.get("quarter")}${quarter} Trimestre ${line.get("year")} : ${format_amount(line.get("amount"), object.company_currency_id)}
</li>
% endfor
</ul>
</p>
<p>&#160;</p>
<p>
Nous vous rappelons que les bordereaux de cotisations sont mis à disposition dans <a href="https://extranet.scop.coop/">votre espace extranet</a> et ne sont plus transmis par courrier.
</p>
<p>
Pour toute question relative à vos cotisations appelées par la CGSCOP, notre équipe est à votre disposition par téléphone au 01 44 85 47 00 ou par courriel à <a href="mailto:administratif.cg@scop.coop">administratif.cg@scop.coop</a>.
</p>
<p>&#160;</p>
<p
>Nous vous adressons nos salutations sincères et coopératives,</p>
<p>&#160;</p>
<p>L'équipe de la CGScop</p>
</p>
</div>
</field>
<field name="lang">fr_FR</field>
<field name="auto_delete" eval="False" />
</record>
</data>
</odoo>
# © 2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openupgradelib import openupgrade # pylint: disable=W7936
def scop_liasse_fiscale_map_values(env):
openupgrade.map_values(
env.cr,
openupgrade.get_legacy_name("year"),
"year",
[
(2020, "2020"),
(2021, "2021"),
(2022, "2022"),
],
table="scop_cotisation",
)
@openupgrade.migrate()
def migrate(env, version):
scop_liasse_fiscale_map_values(env)
# © 2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openupgradelib import openupgrade
column_renames = {
"scop_cotisation": [("year", None)],
}
# TODO: migrer lf_note_ref dans ref
@openupgrade.migrate()
def migrate(env, version):
openupgrade.rename_columns(env.cr, column_renames)
# © 2019 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import account_banking_mandate
from . import account_move
from . import account_payment_order
from . import chart_template
......
# © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import _, models
from odoo.exceptions import UserError
class AccountBankingMandate(models.Model):
_inherit = "account.banking.mandate"
# ------------------------------------------------------
# Button functions
# ------------------------------------------------------
def set_payment_order(self):
self.ensure_one()
payment_mode = self.env["account.payment.mode"].search(
[("payment_method_id.code", "=", "sepa_direct_debit")]
)
if not payment_mode:
raise UserError(_("Aucun mode de prélèvement SEPA configuré."))
self.partner_id.customer_payment_mode_id = payment_mode
def set_invoice_mandate(self):
return {
"name": "Affectation du nouveau mandat",
"type": "ir.actions.act_window",
"res_model": "account.banking.mandate.change.wizard",
"views": [[False, "form"]],
"target": "new",
}
# ------------------------------------------------------
# Business functions
# ------------------------------------------------------
def _select_open_invoices(self):
self.ensure_one()
invoice_ids = self.env["account.move"].search(
[
("partner_id", "=", self.partner_id.id),
("move_type", "in", ("out_invoice", "out_refund")),
("state", "in", ("draft", "posted")),
("payment_state", "in", ("draft", "not_paid", "partial")),
]
)
return invoice_ids
def _change_invoice_mandate(self, invoice_ids):
"""
Affecte le mandat courant pur la facture passée en paramètre
:param invoice : objet account.move
"""
payment_mode = self.env["account.payment.mode"].search(
[
("payment_method_id.code", "=", "sepa_direct_debit"),
("company_id", "=", self.env.company.id),
]
)
if not payment_mode:
raise UserError(_("Aucun mode de prélèvement SEPA configuré."))
for invoice in invoice_ids:
invoice.update(
{
"payment_mode_id": payment_mode.id,
"partner_bank_id": self.partner_bank_id.id,
"mandate_id": self.id,
}
)
def _remove_invoice_mandate(self, invoice_ids):
"""
Supprime le mandat courant pur la facture passée en paramètre
:param invoice : objet account.move
"""
payment_mode = self.env["account.payment.mode"].search(
[("name", "ilike", "Virement"), ("company_id", "=", self.env.company.id)],
limit=1,
)
for invoice in invoice_ids:
invoice.update(
{
"payment_mode_id": payment_mode.id if payment_mode else None,
"partner_bank_id": False,
"mandate_id": False,
}
)
self.partner_id.customer_payment_mode_id = payment_mode
......@@ -23,10 +23,7 @@ class ScopAccountMove(models.Model):
if res.get("is_contribution"):
res["journal_id"] = self.env.company.contribution_journal_id.id
else:
if (
res.get("journal_id")
== self.env.company.contribution_journal_id.id
):
if res.get("journal_id") == self.env.company.contribution_journal_id.id:
res["is_contribution"] = True
return res
......
# Copyright 2020 Le Filament
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models
from odoo.exceptions import ValidationError
from itertools import groupby
from odoo import _, fields, models
from odoo.exceptions import UserError, ValidationError
class AccountPaymentOrder(models.Model):
......@@ -17,6 +19,12 @@ class AccountPaymentOrder(models.Model):
attachment_ids = fields.One2many(
comodel_name="ir.attachment", compute="_compute_attachment_ids"
)
mandate_validity = fields.Boolean(
"Mandats valides", compute="_compute_mandate_validity"
)
email_sent = fields.Boolean("Email envoyé aux coopératives", default=False)
email_datetime = fields.Datetime("Date email envoyé aux coopératives")
email_count = fields.Integer(string="Nombre de mails", compute="_compute_emails")
# ------------------------------------------------------
# Compute fields
......@@ -27,7 +35,11 @@ class AccountPaymentOrder(models.Model):
def _compute_bank_line_amount(self):
for po in self:
po.bank_line_amount = sum(po.bank_line_ids.mapped("amount_currency"))
po.bank_line_amount = sum(
po.payment_ids.filtered(lambda p: not p.reversed_entry_id).mapped(
"amount_total_signed"
)
)
def _compute_attachment_ids(self):
Attachment = self.env["ir.attachment"]
......@@ -39,6 +51,24 @@ class AccountPaymentOrder(models.Model):
]
)
def _compute_mandate_validity(self):
for o in self:
validity = o.mapped("payment_line_ids.mandate_id").filtered(
lambda m: m.state != "valid"
)
if validity:
o.mandate_validity = False
else:
o.mandate_validity = True
# Emails
def _compute_emails(self):
for r in self:
email_ids = self.env["mail.mail"].search(
[("mail_message_id", "in", r.message_ids.ids)]
)
r.email_count = len(email_ids)
# ------------------------------------------------------
# Button function
# ------------------------------------------------------
......@@ -68,6 +98,57 @@ class AccountPaymentOrder(models.Model):
"domain": [["payment_order_id", "=", self.id]],
}
def view_wrong_iban(self):
self.ensure_one()
bank_ids = self.mapped("payment_line_ids.partner_bank_id").filtered(
lambda b: b.acc_type != "iban"
)
return {
"type": "ir.actions.act_window",
"name": "Comptes bancaires",
"res_model": "res.partner.bank",
"views": [[False, "tree"], [False, "form"]],
"domain": [["id", "in", bank_ids.ids]],
}
def view_wrong_mandate(self):
self.ensure_one()
mandate_ids = self.mapped("payment_line_ids.mandate_id").filtered(
lambda m: m.state != "valid"
)
return {
"type": "ir.actions.act_window",
"name": "Mandats non valides",
"res_model": "account.banking.mandate",
"views": [[False, "tree"], [False, "form"]],
"domain": [["id", "in", mandate_ids.ids]],
}
def action_send_email(self):
self.ensure_one()
try:
template = self.env.ref("cgscop_cotisation.email_template_payment_order")
except Exception:
raise UserError(_("Aucun modèle d'e-mail n'a été trouvé."))
# Get partners
partner_ids = self.payment_line_ids.mapped("partner_id")
for partner in partner_ids:
template.with_context(partner_id=partner.id).send_mail(
self.id,
)
self.email_sent = True
self.email_datetime = fields.Datetime.now()
def action_show_emails(self):
return {
"name": "Etat des mails envoyés",
"type": "ir.actions.act_window",
"view_mode": "tree",
"views": [(False, "tree"), (False, "form")],
"res_model": "mail.mail",
"domain": [("mail_message_id", "in", self.message_ids.ids)],
}
# ------------------------------------------------------
# Common function
# ------------------------------------------------------
......@@ -91,9 +172,68 @@ class AccountPaymentOrder(models.Model):
else:
return True
# Email
def get_email_values(self):
self.ensure_one()
partner_id = self.env["res.partner"].browse(self.env.context.get("partner_id"))
partner_line_ids = self.payment_line_ids.filtered(
lambda l: l.partner_id == partner_id
)
quarter_detail = []
quarter_agg = []
for line in partner_line_ids:
invoice_id = line.move_line_id.move_id
quarter_detail.append(
("%s-%s" % (invoice_id.year, invoice_id.cotiz_quarter), line.amount_currency)
)
quarter_detail.sort(key=lambda x: x[0])
for quarter, values in groupby(quarter_detail, key=lambda x: x[0]):
amount = 0
for val in values:
amount += val[1]
quarter_agg.append({
"year": quarter[0:4],
"quarter": quarter[-1],
"amount": amount,
})
return {
"partner_id": partner_id,
"total": sum(partner_line_ids.mapped("amount_currency")),
"date": partner_line_ids.mapped("date")[0],
"bank": partner_line_ids.mapped("partner_bank_id.acc_number")[0],
"deadline": quarter_agg,
}
def get_recipients(self):
recipients = ",".join(map(lambda x: str(x), self._get_recipient().ids))
return recipients
def _get_recipient(self):
partner_id = self.env["res.partner"].browse(self.env.context.get("partner_id"))
if partner_id:
tag_cotiz_id = self.env.company.tag_cotiz_id
child_ids = partner_id.child_ids.filtered(
lambda child: (tag_cotiz_id in child.category_id) and child.email
)
if partner_id.email:
recipient_ids = partner_id + child_ids
else:
recipient_ids = child_ids
return recipient_ids
# ------------------------------------------------------
# Override Parent
# ------------------------------------------------------
def open2generated(self):
self.check_sepa_order()
return super(AccountPaymentOrder, self).open2generated()
def _prepare_move(self, bank_lines=None):
res = super()._prepare_move(bank_lines=bank_lines)
res["commercial_partner_id"] = bank_lines[0].partner_id.id
res["partner_id"] = bank_lines[0].partner_id.id
return res
......@@ -12,3 +12,23 @@ class ResPartner(models.Model):
inverse_name="partner_id",
string="Cotisations",
)
def get_partner_contribution_type(self):
"""
Returns list of contribution type for partner
"""
contribution_type = [self.env.ref("cgscop_partner.riga_14397")]
if self.ur_id in [
self.env.ref("cgscop_partner.riga_14232"),
self.env.ref("cgscop_partner.riga_14243"),
self.env.ref("cgscop_partner.riga_14231"),
]:
contribution_type.append(self.env.ref("cgscop_partner.riga_14399"))
if self.is_federation_com:
contribution_type.append(self.env.ref("cgscop_partner.riga_14398"))
# TODO: Mettre à jour avec is_federation_cae après la maj des périodes par la CG
if self.cae:
contribution_type.append(self.env.ref("cgscop_partner.cotiz_fede_cae"))
if self.is_federation_indus:
contribution_type.append(self.env.ref("cgscop_partner.cotiz_fede_indus"))
return contribution_type
# © 2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging
from psycopg2.extensions import AsIs
from odoo import api, fields, models, tools
_logger = logging.getLogger(__name__)
class ScopContributionReport(models.Model):
_name = "scop.contribution.report"
......@@ -146,6 +150,7 @@ class ScopContributionReport(models.Model):
"CREATE or REPLACE VIEW %s as (%s)",
(AsIs(self._table), AsIs(self._query())),
)
self._set_ro_table()
# ------------------------------------------------------
# Computed fields
......@@ -198,7 +203,9 @@ class ScopContributionReport(models.Model):
payments_html = False
if self.source == "odoo":
invoice_ids = self.get_invoice_contribution()
payment_ids = invoice_ids.mapped("move_line_payment_ids")
payment_ids = invoice_ids.mapped("move_line_payment_ids").filtered(
lambda p: p.move_id.move_type == "entry"
)
if payment_ids:
payments = payment_ids.mapped(
lambda p: {
......@@ -208,14 +215,6 @@ class ScopContributionReport(models.Model):
"credit": p.credit,
"class": "",
}
if not p.invoice_id
else {
"date": p.date,
"name": p.name,
"ref": "",
"credit": p.credit,
"class": "text-danger",
}
)
payments_html = self._get_html_table(payments)
if not payments_html:
......@@ -226,11 +225,7 @@ class ScopContributionReport(models.Model):
def get_invoice_contribution(self):
invoice_ids = (
self.env["account.move"]
.sudo()
.search(
self._get_contribution_domain()
)
self.env["account.move"].sudo().search(self._get_contribution_domain())
)
return invoice_ids
......
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_scop_contribution_report_user,access_scop_contribution_report_user,model_scop_contribution_report,base.group_user,1,0,0,0
access_account_banking_mandate_change_wizard,access_account_banking_mandate_change_wizard,model_account_banking_mandate_change_wizard,account.group_account_manager,1,1,1,1
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- Copyright 2020 Le Filament
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<data>
<record id="view_mandate_form_inherit" model="ir.ui.view">
<field name="name">scop.view.mandate.form</field>
<field name="model">account.banking.mandate</field>
<field name="inherit_id" ref="account_banking_mandate.view_mandate_form" />
<field name="priority" eval="90" />
<field name="arch" type="xml">
<xpath expr="//group[@name='main']" position="before">
<div class="col-12 mt16 mb16" name="change_mandate_button">
<button
name="set_payment_order"
type="object"
class="btn-outline-info"
string="Affecter le prélèvement comme mode de paiement par défaut"
attrs="{'invisible': [('state', '!=', 'valid')]}"
confirm="Valider le prélèvement par défaut pour la coopérative ?"
/>
<button
name="set_invoice_mandate"
type="object"
class="btn-outline-info"
style="margin-left: 15px;"
string="Affecter ce mandat aux factures ouvertes"
context="{'action_type': 'update_mandate'}"
attrs="{'invisible': [('state', '!=', 'valid')]}"
/>
<button
name="set_invoice_mandate"
type="object"
class="btn-outline-danger"
style="margin-left: 15px;"
string="Affecter 'Virement' aux factures et cotisations ouvertes"
context="{'action_type': 'remove_mandate'}"
attrs="{'invisible': [('state', 'not in', ['expired', 'cancel'])]}"
/>
</div>
</xpath>
</field>
</record>
</data>
</odoo>
......@@ -43,17 +43,17 @@
<attribute name="string">Date de cotisation</attribute>
</xpath>
<xpath expr="//field[@name='user_id']" position="attributes">
<attribute name="invisible">True</attribute>
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='team_id']" position="attributes">
<attribute name="invisible">True</attribute>
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='beneficiary_id']" position="attributes">
<attribute name="invisible">True</attribute>
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='team_id']" position="attributes">
<attribute name="invisible">True</attribute>
<attribute name="invisible">1</attribute>
</xpath>
</field>
</record>
......@@ -70,24 +70,29 @@
position="before"
>
<field name="partner_member_number" readonly="1" />
</xpath>
<xpath
expr="//field[@name='invoice_partner_display_name'][2]"
position="attributes"
>
<attribute name="string">Adhérent</attribute>
<field
name="invoice_partner_display_name"
string="Adhérent"
optional="show"
/>
<field
name="invoice_date"
string="Date de cotisation"
optional="show"
/>
</xpath>
<xpath expr="//field[@name='invoice_origin']" position="after">
<field name="type_contribution_id" optional="hide" />
<field name="year" optional="hide" />
</xpath>
<xpath expr="//field[@name='invoice_date']" position="attributes">
<attribute name="string">Date de cotisation</attribute>
<xpath expr="//field[@name='activity_ids']" position="attributes">
<attribute name="optional">hide</attribute>
</xpath>
<xpath expr="//field[@name='company_id']" position="attributes">
<attribute name="invisible">True</attribute>
<attribute name="optional">hide</attribute>
</xpath>
<xpath expr="//field[@name='invoice_origin']" position="attributes">
<attribute name="invisible">True</attribute>
<attribute name="optional">hide</attribute>
</xpath>
<xpath expr="//field[@name='state']" position="after">
<field name="is_sdd" invisible="1" />
......@@ -120,7 +125,7 @@
<filter
name="draft"
string="Brouillon"
domain="['|', ('state','=','draft'), ('move_type','in', ['out_invoice', 'out_refund'])]"
domain="[('state','=','draft'), ('move_type','in', ['out_invoice', 'out_refund'])]"
/>
<filter
name="unpaid"
......@@ -223,19 +228,41 @@
>
<field name="date" />
<field name="name" />
<field name="partner_id" />
<field name="commercial_partner_id" />
<field name="ref" />
<field name="journal_id" />
<field name="amount_total" sum="Total Amount" />
<field name="reversed_entry_id" />
<field name="reversal_move_id" widget="many2many_tags" />
<field name="payment_reference" optional="hide" />
<button
name="%(account.action_view_account_move_reversal)d"
type="action"
string="Rejeter (extourne)"
class="btn-outline-danger btn-sm"
attrs="{'invisible': [('reversed_entry_id', '!=', False), ('state', '=', 'posted')]}"
attrs="{'invisible': [
'|',
'&amp;', ('reversal_move_id', '=', []), ('reversed_entry_id', '!=', False),
'&amp;', ('reversal_move_id', '!=', []), ('reversed_entry_id', '=', False),
]}"
/>
<field
name="state"
widget="badge"
decoration-success="state == 'posted'"
decoration-info="state == 'draft'"
optional="show"
/>
<field
name="payment_state"
widget="badge"
decoration-danger="payment_state == 'not_paid'"
decoration-warning="payment_state in ('partial', 'in_payment')"
decoration-success="payment_state in ('paid', 'reversed')"
attrs="{'invisible': [('payment_state', 'in', ('invoicing_legacy'))]}"
optional="hide"
/>
<field name="state" />
<field name="partner_id" optional="hide" />
<field name="currency_id" invisible="1" />
</tree>
</field>
......@@ -247,7 +274,7 @@
<field name="model">account.move</field>
<field name="arch" type="xml">
<search string="Pièces comptables">
<field name="partner_id" string="Adhérent" />
<field name="commercial_partner_id" string="Adhérent" />
<field name="ref" string="Référence" />
<field name="name" />
<filter
......
......@@ -13,6 +13,26 @@
/>
<field name="priority">100</field>
<field name="arch" type="xml">
<!-- Header and buttons -->
<xpath expr="//button[@name='action_cancel']" position="after">
<button
name="action_send_email"
type="object"
string="Envoyer un email aux coopératives"
class="btn-info"
groups="account.group_account_manager"
attrs="{'invisible': ['|', '|', ('state', 'not in', ('generated', 'uploaded')), ('email_sent', '=', True), ('company_id', '!=', %(base.main_company)d)]}"
confirm="Valider l'envoi des emails ?"
/>
<button
name="action_send_email"
type="object"
string="Renvoyer un email aux coopératives"
groups="account.group_account_manager"
attrs="{'invisible': ['|', '|', ('state', 'not in', ('generated', 'uploaded')), ('email_sent', '!=', True), ('company_id', '!=', %(base.main_company)d)]}"
confirm="Valider l'envoi des emails ?"
/>
</xpath>
<xpath expr="//button[@name='action_cancel']" position="attributes">
<attribute
name="groups"
......@@ -32,7 +52,33 @@
name="confirm"
>Confirmer l'annulation de l'ordre de prélèvement ?</attribute>
</xpath>
<xpath expr="//field[@name='bank_line_count']" position="after">
<!-- Sheet -->
<!-- Button box -->
<xpath expr="//div[@name='button_box']" position="inside">
<button
class="oe_stat_button"
name="action_show_emails"
type="object"
icon="fa-envelope-o"
>
<field string="Emails" name="email_count" widget="statinfo" />
</button>
</xpath>
<!-- Alert -->
<xpath expr="//div[hasclass('oe_title')]" position="before">
<field name="email_sent" invisible="1" />
<div
class="alert alert-warning"
role="alert"
attrs="{'invisible': [('email_sent', '!=', True)]}"
>
Un email a été envoyé aux coopératives le
<field name="email_datetime" readonly="1" />
</div>
</xpath>
<!-- Sheet Buttons -->
<xpath expr="//field[@name='payment_count']" position="after">
<field name="payment_line_amount" />
<field name="bank_line_amount" />
<button
......@@ -51,15 +97,41 @@
attrs="{'invisible': [('state', 'not in', ('uploaded', 'done'))]}"
/>
</xpath>
<!-- Boutons de vérification IBAN et mandats -->
<xpath expr="//notebook" position="before">
<field name="mandate_validity" invisible="1" />
<button
name="view_wrong_iban"
type="object"
string="Voir les IBAN à corriger"
class="btn-danger"
attrs="{'invisible': [('sepa', '=', True)]}"
style="margin-right: 10px;"
/>
<button
name="view_wrong_mandate"
type="object"
string="Voir les Mandats non valides"
class="btn-danger"
attrs="{'invisible': [('mandate_validity', '=', True)]}"
/>
</xpath>
<!-- Affichage des fichers XML -->
<xpath expr="//notebook" position="inside">
<page name="attachments" string="Fichiers de prélèvements">
<field name="attachment_ids">
<tree>
<field name="attachment_ids" readonly="1" mode="tree">
<tree create="0" edit="0">
<field name="create_date" />
<field name="name" />
<field name="type" />
<field name="datas" filename="datas_fname" />
<field name="datas" filename="name" widget="binary" />
<field name="create_uid" />
<!-- <button-->
<!-- name="download_sdd_file"-->
<!-- type="object"-->
<!-- string="Télécharger le fichier"-->
<!-- class="btn-sm btn-o-info"-->
<!-- />-->
</tree>
<form>
<h1><field name="name" /></h1>
......
......@@ -13,7 +13,7 @@
<page
name='scop_contribution'
string="Cotisations"
attrs="{'invisible': ['|', ('is_cooperative', '!=', True), ('project_status', '!=', '6_suivi')]}"
attrs="{'invisible': ['|', ('is_cooperative', '!=', True), ('project_status', 'not in', ['4_suivi', '6_decede'])]}"
>
<notebook>
<page name="contribution" string="Appels de Cotisations">
......@@ -30,10 +30,6 @@
<field name='amount_called' />
<field name='amount_paid' />
<field name='amount_due' />
<field
name='is_loss'
style="text-align: center;"
/>
</tree>
</field>
</page>
......
# © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import account_banking_mandate_change_wizard
from . import account_move_reversal
from . import account_payment_line_create
from . import scop_deces_wizard
# © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models
class AccountBankingMandateChange(models.TransientModel):
_name = "account.banking.mandate.change.wizard"
_description = "Wizard changement mandat"
@api.model
def _default_mandate_id(self):
return self.env.context.get("active_id")
@api.model
def _default_invoice_ids(self):
invoice_ids = (
self.env["account.banking.mandate"]
.browse(self.env.context.get("active_id"))
._select_open_invoices()
)
return invoice_ids
mandate_id = fields.Many2one(
comodel_name="account.banking.mandate",
string="Mandat",
default=_default_mandate_id,
required=True,
)
partner_id = fields.Many2one(related="mandate_id.partner_id")
invoice_ids = fields.Many2many(
comodel_name="account.move",
string="Factures",
default=_default_invoice_ids,
)
def change_mandate(self):
if self.env.context.get("action_type") == "update_mandate":
self.mandate_id._change_invoice_mandate(self.invoice_ids)
elif self.env.context.get("action_type") == "remove_mandate":
self.mandate_id._remove_invoice_mandate(self.invoice_ids)
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<record id="account_banking_mandate_change_wizard_form" model="ir.ui.view">
<field name="name">account.banking.mandate.change.wizard.form</field>
<field name="model">account.banking.mandate.change.wizard</field>
<field name="arch" type="xml">
<form string="Changement de mandat">
<group>
<field name="partner_id" invisible="1" />
<field name="mandate_id" readonly="1" />
</group>
<label for="invoice_ids" />
<field
name="invoice_ids"
mode="tree"
domain="[('partner_id', '=', partner_id), ('state', 'in', ('draft', 'posted')), ('payment_state', 'in', ('draft', 'not_paid', 'partial')), ('move_type', 'in', ('out_invoice', 'out_refund'))]"
>
<tree
editable="bottom"
create="0"
edit="0"
delete="1"
decoration-info="state == 'draft'"
>
<field name="partner_id" invisible="1" />
<field name="name" decoration-bf="1" />
<field name="partner_member_number" />
<field name="invoice_date" />
<field
name="invoice_partner_display_name"
string="Partenaire"
/>
<field name="invoice_date_due" />
<field name="payment_mode_id" optional="show" />
<field name="mandate_id" optional="show" />
<field name="amount_untaxed_signed" string="Total HT" />
<field
name="amount_total_signed"
decoration-bf="1"
string="Total TTC"
/>
<field
name="state"
widget="badge"
decoration-success="state == 'posted'"
decoration-info="state == 'draft'"
/>
<field
name="payment_state"
widget="badge"
decoration-danger="payment_state == 'not_paid'"
decoration-warning="payment_state in ('partial', 'in_payment')"
decoration-success="payment_state in ('paid', 'reversed')"
/>
<field name="currency_id" invisible="1" />
<field name="company_currency_id" invisible="1" />
<field name="company_id" invisible="1" />
</tree>
</field>
<footer>
<button
name="change_mandate"
type="object"
string="Affecter le mandat"
class="btn-primary"
confirm="Valider le changement de mandat ?"
invisible="context.get('action_type') != 'update_mandate'"
/>
<button
name="change_mandate"
type="object"
string="Supprimer le mandat"
class="btn-danger"
confirm="Valider la suppression des mandats et le passage en virement ?"
invisible="context.get('action_type') != 'remove_mandate'"
/>
<button special="cancel" string="Cancel" />
</footer>
</form>
</field>
</record>
</data>
</odoo>
# © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class AccountPaymentLineCreate(models.TransientModel):
_inherit = "account.payment.line.create"
start_date = fields.Date(string="Date Mini")
ur_ids = fields.Many2many(comodel_name="union.regionale", string="Union Régionale")
def _prepare_move_line_domain(self):
self.ensure_one()
domain = super()._prepare_move_line_domain()
if self.start_date:
domain += [("date_maturity", ">=", self.start_date)]
if self.ur_ids:
domain += [("partner_id.ur_id", "in", self.ur_ids.ids)]
return domain