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

Target

Select target project
  • lefilament/adefpat/adefpat_project
1 result
Show changes
Showing
with 2384 additions and 806 deletions
This diff is collapsed.
# Copyright 2020 Le Filament (<http://www.le-filament.com>) # Copyright 2020-2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models, api from odoo import api, fields, models
class ProjectTask(models.Model): class ProjectTask(models.Model):
_inherit = 'project.task' _inherit = "project.task"
@api.model @api.model
def default_get(self, fields): def default_get(self, fields):
res = super(ProjectTask, self).default_get(fields) res = super(ProjectTask, self).default_get(fields)
if 'default_project_id' in self.env.context: if "default_project_id" in self.env.context:
default_project_id = self.env['project.project'].browse(self.env.context['default_project_id']) default_project_id = self.env["project.project"].browse(
self.env.context["default_project_id"]
)
if default_project_id.exists().porteurs_projets_ids: if default_project_id.exists().porteurs_projets_ids:
participant_ids = [] participant_ids = []
for porteur_project in default_project_id.porteurs_projets_ids: for porteur_project in default_project_id.porteurs_projets_ids:
vals = { vals = {
'porteur_id': porteur_project.porteur_id.id, "porteur_id": porteur_project.porteur_id.id,
'lastname': porteur_project.lastname, "lastname": porteur_project.lastname,
'firstname': porteur_project.firstname, "firstname": porteur_project.firstname,
'commune': porteur_project.commune, "commune": porteur_project.commune,
'mobile': porteur_project.mobile, "mobile": porteur_project.mobile,
'fixe': porteur_project.fixe, "fixe": porteur_project.fixe,
'email': porteur_project.email, "email": porteur_project.email,
'eligible': porteur_project.eligible, "eligible": porteur_project.eligible,
} }
participant_ids.append((0, 0, vals)) participant_ids.append((0, 0, vals))
res.update({'participant_ids': participant_ids}) res.update({"participant_ids": participant_ids})
cout_id = self.env['adefpat.project.cout'].search([ cout_id = self.env["adefpat.project.cout"].search(
('project_id', '=', default_project_id.id), [
('partner_id', '!=', False) ("project_id", "=", default_project_id.id),
], limit=1) ("partner_id", "!=", False),
],
limit=1,
)
if cout_id: if cout_id:
res.update({'formateur_id': cout_id.partner_id.id}) res.update({"formateur_id": cout_id.partner_id.id})
return res return res
user_id = fields.Many2one( user_id = fields.Many2one(
'res.users', "res.users",
string='CFD', string="CFD",
default=lambda self: self.env.uid, default=lambda self: self.env.uid,
index=True, index=True,
track_visibility='always') track_visibility="always",
)
formateur_id = fields.Many2one( formateur_id = fields.Many2one(
'res.partner', "res.partner",
string='Formateur', string="Formateur",
domain=[ domain=[
('active', '=', True), ("active", "=", True),
('is_company', '=', False), ("is_company", "=", False),
('is_consultant_form', '=', True), ("is_consultant_form", "=", True),
'|', ('reference', '=', 'reference'), "|",
('reference', '=', 'prereference')], ("reference", "=", "reference"),
on_delete='restrict') ("reference", "=", "prereference"),
duree_jr = fields.Selection([ ],
('demi_journee', "Demi journée"), ondelete="restrict",
('journee', "Journée"), )
duree_jr = fields.Selection(
[
("demi_journee", "Demi journée"),
("journee", "Journée"),
], ],
"Durée (en jours)") "Durée (en jours)",
duree_hr = fields.Float(
"Durée en jours",
compute='_compute_duree_hr',
store=True
) )
duree_hr = fields.Float("Durée (int)", compute="_compute_duree_hr", store=True)
participant_ids = fields.One2many( participant_ids = fields.One2many(
'res.partner.porteur.project', "res.partner.porteur.project", "task_id", string="Participants"
'task_id', )
string="Participants") cout_seance = fields.Float("Coût de la séance", compute="_compute_cout_seance")
cout_seance = fields.Float("Coût de la séance", compute='_compute_cout_seance')
date_account = fields.Date("Date de la facture") date_account = fields.Date("Date de la facture")
@api.depends('duree_jr') @api.depends("duree_jr")
@api.multi @api.multi
def _compute_duree_hr(self): def _compute_duree_hr(self):
for task in self: for task in self:
if task.duree_jr == 'journee': if task.duree_jr == "journee":
task.duree_hr = 1 task.duree_hr = 1
if task.duree_jr == 'demi_journee': if task.duree_jr == "demi_journee":
task.duree_hr = 0.5\ task.duree_hr = 0.5
@api.depends('formateur_id', 'duree_hr') @api.depends("formateur_id", "duree_hr")
@api.multi @api.multi
def _compute_cout_seance(self): def _compute_cout_seance(self):
for task in self: for task in self:
if task.formateur_id: if task.formateur_id:
formateur_proj = self.env['adefpat.project.cout'].search([ formateur_proj = self.env["adefpat.project.cout"].search(
('project_id', '=', task.project_id.id), [
('partner_id', '=', task.formateur_id.id) ("project_id", "=", task.project_id.id),
], limit=1) ("partner_id", "=", task.formateur_id.id),
],
limit=1,
)
if formateur_proj: if formateur_proj:
task.cout_seance = formateur_proj.cout_jour * task.duree_hr task.cout_seance = formateur_proj.cout_jour * task.duree_hr
\ No newline at end of file
# Copyright 2020 Le Filament (<http://www.le-filament.com>) # Copyright 2020-2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models, _ from odoo import fields, models
class ResCompany(models.Model): class ResCompany(models.Model):
_inherit = "res.company" _inherit = "res.company"
explication_financement = fields.Text( explication_financement = fields.Text(
string="Explication financement porteur de projet") string="Explication financement porteur de projet"
)
modalites_intervention = fields.Text("Modalités d'intervention") modalites_intervention = fields.Text("Modalités d'intervention")
modalites_facturation = fields.Text("Modalités de facturation") modalites_facturation = fields.Text("Modalités de facturation")
modalites_reponse = fields.Text("Modalités de réponse") modalites_reponse = fields.Text("Modalités de réponse")
modalites_modif_marche = fields.Text("Modalités de modification du marché") modalites_modif_marche = fields.Text("Modalités de modification du marché")
\ No newline at end of file
# Copyright 2020 Le Filament (<http://www.le-filament.com>) # Copyright 2020-2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models from odoo import fields, models
class ResConfigSettings(models.TransientModel): class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings' _inherit = "res.config.settings"
explication_financement = fields.Text( explication_financement = fields.Text(
related='company_id.explication_financement', related="company_id.explication_financement",
string="Explication financement porteur de projet", string="Explication financement porteur de projet",
readonly=False) readonly=False,
)
modalites_intervention = fields.Text( modalites_intervention = fields.Text(
related='company_id.modalites_intervention', related="company_id.modalites_intervention",
string="Modalités d'intervention", string="Modalités d'intervention",
readonly=False) readonly=False,
)
modalites_facturation = fields.Text( modalites_facturation = fields.Text(
related='company_id.modalites_facturation', related="company_id.modalites_facturation",
string="Modalités de facturation", string="Modalités de facturation",
readonly=False) readonly=False,
)
modalites_reponse = fields.Text( modalites_reponse = fields.Text(
related='company_id.modalites_reponse', related="company_id.modalites_reponse",
string="Modalités de réponse", string="Modalités de réponse",
readonly=False) readonly=False,
)
modalites_modif_marche = fields.Text( modalites_modif_marche = fields.Text(
related='company_id.modalites_modif_marche', related="company_id.modalites_modif_marche",
string="Modalités de modification du marché", string="Modalités de modification du marché",
readonly=False) readonly=False,
\ No newline at end of file )
# Copyright 2020 Le Filament (<http://www.le-filament.com>) # Copyright 2020-2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, api
from ast import literal_eval from ast import literal_eval
from odoo import api, fields, models
class ResPartner(models.Model): class ResPartner(models.Model):
_inherit = 'res.partner' _inherit = "res.partner"
project_count = fields.Integer( project_count = fields.Integer(
compute='_compute_project_count', compute="_compute_project_count", string="Nombre de projets", store=True
string='Nombre de projets', )
store=True)
def _compute_project_count(self): def _compute_project_count(self):
for partner in self: for partner in self:
porteurs_projects = self.env['res.partner.porteur.project'].search([ porteurs_projects = self.env["res.partner.porteur.project"].search(
('partner_id', '=', partner.id)]) [("partner_id", "=", partner.id)]
projects = self.env['project.project'].search_count([ )
('porteurs_projets_ids', 'in', porteurs_projects.ids)]) projects = self.env["project.project"].search_count(
[("porteurs_projets_ids", "in", porteurs_projects.ids)]
)
partner.project_count = projects partner.project_count = projects
@api.multi @api.multi
def action_view_partner_projects(self): def action_view_partner_projects(self):
self.ensure_one() self.ensure_one()
action = self.env.ref('project.open_view_project_all_config').read()[0] action = self.env.ref("project.open_view_project_all_config").read()[0]
action['domain'] = literal_eval(action['domain']) action["domain"] = literal_eval(action["domain"])
porteurs_projects = self.env['res.partner.porteur.project'].search([ porteurs_projects = self.env["res.partner.porteur.project"].search(
('partner_id', '=', self.id)]) [("partner_id", "=", self.id)]
action['domain'].append(('porteurs_projets_ids', 'in', porteurs_projects.ids)) )
return action action["domain"].append(("porteurs_projets_ids", "in", porteurs_projects.ids))
\ No newline at end of file return action
# © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import formateur_project_report
# © 2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import tools
from odoo import models, fields, api
class AdefpatFormateurProjectReport(models.Model):
_name = "adefpat.formateur.project.report"
_description = "Rapport formateurs"
_auto = False
_order = 'formateur_id'
# project fields
project_id = fields.Many2one(
comodel_name="project.project",
string="Nom du dossier",
)
project_num = fields.Char(
related="project_id.num_dossier", string="Numéro du dossier"
)
type_convention_id = fields.Many2one(
comodel_name="adefpat.type.convention",
string="Convention de financement",
related="project_id.type_convention_id"
)
# formateur fields
formateur_id = fields.Many2one(
comodel_name="res.partner",
string="Formateur",
)
formateur_name = fields.Char("Nom du formateur", related="formateur_id.name")
number_hour_period = fields.Float("Nb heures sur période")
# ------------------------------------------------------
# Query
# ------------------------------------------------------
def _select(self):
select_str = """
SELECT
row_number() over (ORDER BY pr.id) AS id,
pr.id AS project_id,
t.formateur_id AS formateur_id,
SUM(t.duree_hr * 7) AS number_hour_period
FROM
project_task t
LEFT JOIN
project_project pr ON t.project_id = pr.id
LEFT JOIN
adefpat_type_convention c ON pr.type_convention_id = c.id
"""
return select_str
def _where(self):
period_start = fields.Date.from_string(self.env.context.get("period_start"))
period_end = fields.Date.from_string(self.env.context.get("period_end"))
is_fd = self.env.context.get("is_fd")
is_closed = self.env.context.get("is_closed")
where = """
WHERE
t.duree_hr > 0
"""
if period_start and period_end:
where += """
AND t.date_deadline >= '%s'
AND t.date_deadline <= '%s'
""" % (period_start, period_end)
if is_fd:
where += "AND c.is_fd is true "
if is_closed:
where += """
AND pr.closing_date IS NOT NULL
AND pr.closing_date <= '%s'
AND pr.closing_date >= '%s'
""" % (period_end, period_start)
return where
def _group_by(self):
group_by = """
GROUP BY
pr.id, t.formateur_id
"""
return group_by
@api.model_cr
def init(self):
tools.drop_view_if_exists(self.env.cr, self._table)
self.env.cr.execute("""CREATE or REPLACE VIEW %s as (
%s %s %s
)""" % (self._table, self._select(), self._where(), self._group_by()))
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- TREE VIEW -->
<!-- Rapport Porteurs de Projets -->
<record id="view_adefpat_formateur_reporting_tree" model="ir.ui.view">
<field name="name">view.adefpat.formateur.reporting.tree</field>
<field name="model">adefpat.formateur.project.report</field>
<field name="arch" type="xml">
<tree string="Formateurs" create="0" edit="0" delete="0">
<field name="project_num" />
<field name="project_id" string="Nom du dossier" />
<field name="type_convention_id" />
<field name="formateur_name" />
<field name="number_hour_period" />
</tree>
</field>
</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 odoo import tools
from odoo import models, fields, api
class ScopContributionReport(models.Model):
_name = "scop.contribution.report"
_description = "Vue cotisations"
_auto = False
_order = 'year desc, partner_id'
name = fields.Char(compute='_compute_name')
year = fields.Char('Année de cotisation')
source = fields.Selection(
string='Source',
selection=[('odoo', 'Odoo')],
required=True,)
type_contribution_id = fields.Many2one(
comodel_name="scop.contribution.type",
string="Type de cotisation",
readonly=True)
partner_id = fields.Many2one('res.partner', string='Partner', readonly=True)
amount_called = fields.Float('Montant Appelé')
amount_paid = fields.Float('Montant Payé')
amount_due = fields.Float('Montant Restant')
is_loss = fields.Boolean('Exonération/Perte', compute="_compute_is_loss")
payments = fields.Html('Paiements', compute="_compute_payments")
_depends = {
'account.invoice': [
'year', 'type_contribution_id', 'partner_id',
'amount_total_signed', 'residual_company_signed',
'state', 'type', 'is_contribution', 'refund_invoice_id'
],
}
# ------------------------------------------------------
# Sub Query
# ------------------------------------------------------
def _select_invoice(self):
select_str = """
SELECT
'odoo' as source,
CAST(i.year AS VARCHAR),
i.type_contribution_id,
i.partner_id,
SUM(i.amount_total_signed) AS amount_called,
SUM(i.amount_total_signed - i.residual_company_signed) AS amount_paid,
SUM(i.residual_company_signed) AS amount_due
"""
return select_str
def _from_invoice(self):
from_str = """
FROM
account_invoice i
"""
return from_str
def _where_invoice(self):
where_str = """
WHERE
i.state in ('open', 'paid', 'in_payment') AND
i.is_contribution = true
"""
return where_str
def _groupby_invoice(self):
groupby_str = """
GROUP BY
i.year,
i.type_contribution_id,
i.partner_id
"""
return groupby_str
def _query_invoice(self):
query = "(%s %s %s %s)" % (
self._select_invoice(), self._from_invoice(),
self._where_invoice(), self._groupby_invoice())
return query
def _subquery(self):
return self._query_invoice()
# ------------------------------------------------------
# Main Query
# ------------------------------------------------------
def _select(self):
select_str = """
SELECT
ROW_NUMBER() OVER(ORDER BY c.year, c.partner_id) AS id,
c.source,
c.year,
c.type_contribution_id,
c.partner_id,
SUM(c.amount_called) AS amount_called,
SUM(c.amount_paid) AS amount_paid,
SUM(c.amount_due) AS amount_due
FROM (
"""
return select_str
def _query_groupby(self):
return """
GROUP BY
c.year,
c.type_contribution_id,
c.partner_id,
c.source
"""
def _query_order(self):
return "ORDER BY c.year DESC"
def _query(self):
query = (
self._select() + self._subquery() + ') c ' +
self._query_groupby() + self._query_order()
)
return query
@api.model_cr
def init(self):
tools.drop_view_if_exists(self.env.cr, self._table)
self.env.cr.execute("""CREATE or REPLACE VIEW %s as (
%s
)""" % (
self._table, self._query()))
# ------------------------------------------------------
# Computed fields
# ------------------------------------------------------
@api.multi
def _compute_is_loss(self):
for contribution in self:
contribution.is_loss = contribution._get_is_loss()
@api.multi
def _compute_name(self):
for contribution in self:
contribution.name = (contribution.year + ' - ' +
contribution.type_contribution_id.name +
' - ' + contribution.partner_id.name)
@api.multi
def _compute_payments(self):
for contribution in self:
contribution.payments = contribution._get_payment()
# ------------------------------------------------------
# Business functions
# ------------------------------------------------------
def _get_is_loss(self):
invoice_ids = self.env['account.invoice'].sudo().search([
('year', '=', int(self.year)),
('partner_id', '=', self.partner_id.id),
('type_contribution_id', '=', self.type_contribution_id.id),
])
refund_ids = invoice_ids.filtered(lambda i: i.type == 'out_refund')
if refund_ids:
return True
else:
return False
def _get_payment(self):
self.ensure_one()
payments_html = False
if self.source == 'odoo':
invoice_ids = self.get_invoice_contribution()
payment_ids = invoice_ids.mapped('payment_move_line_ids')
if payment_ids:
payments = payment_ids.mapped(lambda p: {
'date': p.date,
'name': p.name,
'ref': p.ref,
'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:
payments_html = "<p>Il n'y a pas de paiements associés à cette cotisation</p>"
return payments_html
def get_invoice_contribution(self):
invoice_ids = self.env['account.invoice'].sudo().search([
('year', '=', int(self.year)),
('partner_id', '=', self.partner_id.id),
('type_contribution_id', '=', self.type_contribution_id.id),
('type', '=', 'out_invoice'),
'|',
('bordereau_id.state', 'not in', ('cancel',)),
('bordereau_id', '=', False)
])
return invoice_ids
def _get_html_table(self, payments):
"""
:param payments: list of dict {date, name, ref, amount}
@return: HTML table with payments
"""
start_html = """
<table class='table table-sm table-striped table-hover table-bordered'>
<thead><tr>
<th>Date</th>
<th>Libellé</th>
<th>Référence</th>
<th>Montant</th>
</tr></thead>
<tbody>
"""
content_html = ""
for payment in payments:
content_html += """
<tr class='%s'>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td class='text-right'>%.2f €</td>
</tr>
""" % (payment.get('class', ''),
payment.get('date', '').strftime('%d/%m/%Y'),
payment.get('name', ''), payment.get('ref', ''),
payment.get('credit', 0.0),)
end_html = "</tbody></table>"
return start_html + content_html + end_html
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- SEARCH VIEW -->
<record model="ir.ui.view" id="scop_contribution_report_search">
<field name="name">scop.contribution.report.search</field>
<field name="model">scop.contribution.report</field>
<field name="arch" type="xml">
<search string="Cotisations">
<field name='partner_id'/>
<field name="year"/>
<field name="type_contribution_id"/>
<filter name="filter_paid" string="À régler" domain="[('amount_due', '!=', 0)]"/>
<filter name="filter_paid" string="Réglé" domain="[('amount_due', '=', 0)]"/>
<separator></separator>
<filter name="filter_cg" string="Cotisations CG" domain="[('type_contribution_id', '=', 1)]"/>
<filter name="filter_ur" string="Cotisations UR" domain="[('type_contribution_id', '=', 3)]"/>
<filter name="filter_fede" string="Cotisations Fédé" domain="[('type_contribution_id', '=', 2)]"/>
<group expand="0" string="Group By">
<filter name="group_by_type_contribution_id" string="Type de cotisation" context="{'group_by':'type_contribution_id'}"/>
<filter name="group_by_year" string="Année" context="{'group_by':'year'}"/>
</group>
</search>
</field>
</record>
<!-- TREE VIEW -->
<record model="ir.ui.view" id="scop_contribution_report_tree">
<field name="name">scop.contribution.report.tree</field>
<field name="model">scop.contribution.report</field>
<field name="arch" type="xml">
<tree string="Cotisations">
<field name="year"/>
<field name="type_contribution_id"/>
<field name='partner_id'/>
<field name='amount_called'/>
<field name='amount_paid'/>
<field name='amount_due'/>
</tree>
</field>
</record>
<!-- FORM VIEW -->
<record model="ir.ui.view" id="scop_contribution_report_form">
<field name="name">scop.contribution.report.form</field>
<field name="model">scop.contribution.report</field>
<field name="arch" type="xml">
<form string="Cotisations">
<sheet>
<h2><field name="name"/></h2>
<separator></separator>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Montant Appelé</th>
<th>Montant payé</th>
<th>Montant restant</th>
</tr>
</thead>
<tbody>
<tr>
<td><field name='amount_called'/></td>
<td><field name='amount_paid'/></td>
<td><field name='amount_due'/></td>
</tr>
</tbody>
</table>
<separator></separator>
<h4>Détail des Paiements</h4>
<field name='payments' widget="html"/>
</sheet>
</form>
</field>
</record>
<!-- PIVOT VIEW -->
<record model="ir.ui.view" id="scop_contribution_report_pivot">
<field name="name">scop.contribution.report.pivot</field>
<field name="model">scop.contribution.report</field>
<field name="arch" type="xml">
<pivot string="Cotisations">
<field name="year" type="row"/>
<field name="type_contribution_id" type="row"/>
<field name='amount_called' type="measure"/>
<field name='amount_paid' type="measure"/>
<field name='amount_due' type="measure"/>
</pivot>
</field>
</record>
<!-- GRAPH VIEW -->
<record model="ir.ui.view" id="scop_contribution_report_graph">
<field name="name">scop.contribution.report.graph</field>
<field name="model">scop.contribution.report</field>
<field name="arch" type="xml">
<graph string="Cotisations">
<field name="year"/>
<field name='amount_called' type="measure"/>
<field name='amount_paid' type="measure"/>
<field name='amount_due' type="measure"/>
</graph>
</field>
</record>
<!-- ACTION -->
<record id="scop_contribution_report_action" model="ir.actions.act_window">
<field name="name">Vue cotisations</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">scop.contribution.report</field>
<field name="view_mode">tree,pivot,graph,form</field>
</record>
<!-- Menu -->
<menuitem
id="scop_contribution_report_menu"
name="Cotisations"
parent="account.account_reports_management_menu"
action="scop_contribution_report_action"
sequence="80"
/>
</data>
</odoo>
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_adefpat_type_convention_group_user,access_adefpat_type_convention_group_user,model_adefpat_type_convention,base.group_user,1,1,1,1 access_adefpat_type_convention_group_user,access_adefpat_type_convention_group_user,model_adefpat_type_convention,base.group_user,1,1,1,1
access_adefpat_reunion_gap_group_user,access_adefpat_reunion_gap_group_user,model_adefpat_reunion_gap,base.group_user,1,1,1,1 access_adefpat_reunion_gap_group_user,access_adefpat_reunion_gap_group_user,model_adefpat_reunion_gap,base.group_user,1,1,1,1
access_res_partner_reunion_gap_group_user,access_res_partner_reunion_gap_group_user,model_res_partner_reunion_gap,base.group_user,1,1,1,1
access_adefpat_project_financement_group_user,access_adefpat_project_financement_group_user,model_adefpat_project_financement,base.group_user,1,1,1,1 access_adefpat_project_financement_group_user,access_adefpat_project_financement_group_user,model_adefpat_project_financement,base.group_user,1,1,1,1
access_adefpat_project_cout_group_user,access_adefpat_project_cout_group_user,model_adefpat_project_cout,base.group_user,1,1,1,1 access_adefpat_project_cout_group_user,access_adefpat_project_cout_group_user,model_adefpat_project_cout,base.group_user,1,1,1,1
access_res_partner_membres_project_group_user,access_res_partner_membres_project_group_user,model_res_partner_membres_project,base.group_user,1,1,1,1 access_res_partner_membres_project_group_user,access_res_partner_membres_project_group_user,model_res_partner_membres_project,base.group_user,1,1,1,1
access_res_partner_consultants_project_group_user,access_res_partner_consultants_project_group_user,model_res_partner_consultants_project,base.group_user,1,1,1,1 access_res_partner_consultants_project_group_user,access_res_partner_consultants_project_group_user,model_res_partner_consultants_project,base.group_user,1,1,1,1
access_res_partner_porteur_project_group_user,access_res_partner_porteur_project_group_user,model_res_partner_porteur_project,base.group_user,1,1,1,1 access_res_partner_porteur_project_group_user,access_res_partner_porteur_project_group_user,model_res_partner_porteur_project,base.group_user,1,1,1,1
access_adefpat_project_statut_group_user,access_adefpat_project_statut_group_user,model_adefpat_project_statut,base.group_user,1,1,1,1 access_adefpat_project_statut_group_user,access_adefpat_project_statut_group_user,model_adefpat_project_statut,base.group_user,1,1,1,1
\ No newline at end of file access_adefpat_formateur_project_report_group_user,access_adefpat_formateur_project_report_group_user,model_adefpat_formateur_project_report,base.group_user,1,1,1,1
odoo.define('adefpat_project.update_kanban', function (require) {
'use strict';
var KanbanRecord = require('web_kanban.Record');
KanbanRecord.include({
_openRecord: function () {
if (this.modelName === 'project.project') {
this.$('.o_kanban_card_manage_section a').first().click();
} else {
this._super.apply(this, arguments);
}
},
});
});
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" name="project assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/adefpat_project/static/src/js/project.js"></script>
</xpath>
</template>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2022 Le Filament
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<data> <data>
<record id="view_task_tree2" model="ir.ui.view"> <record id="view_task_tree2" model="ir.ui.view">
<field name="name">project.task.tree.inherit</field> <field name="name">project.task.tree.inherit</field>
<field name="model">project.task</field> <field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_tree2"/> <field name="inherit_id" ref="project.view_task_tree2" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="date_deadline" position="after"> <field name="date_deadline" position="after">
<field name="duree_hr" sum="Durée"/> <field name="duree_hr" sum="Durée" />
</field> </field>
</field> </field>
</record> </record>
...@@ -16,38 +18,45 @@ ...@@ -16,38 +18,45 @@
<record id="view_task_form2" model="ir.ui.view"> <record id="view_task_form2" model="ir.ui.view">
<field name="name">view.task.form2.form.inherit</field> <field name="name">view.task.form2.form.inherit</field>
<field name="model">project.task</field> <field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_form2"/> <field name="inherit_id" ref="project.view_task_form2" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//notebook" position="before"> <xpath expr="//notebook" position="before">
<group> <group>
<field name="participant_ids" widget="one2many"> <field name="participant_ids" widget="one2many">
<tree string="Participants" editable="top" default_order='porteur_id'> <tree
<field name="porteur_id"/> string="Participants"
<field name="lastname"/> editable="top"
<field name="firstname"/> default_order='porteur_id'
<field name="commune"/> >
<field name="mobile"/> <field name="porteur_id" />
<field name="fixe"/> <field name="lastname" />
<field name="email" widget="email"/> <field name="firstname" />
<field name="h_theoriques"/> <field name="commune" />
<field name="h_pratiques"/> <field name="mobile" />
<field name="eligible"/> <field name="fixe" />
<field name="email" widget="email" />
<field name="h_theoriques" />
<field name="h_pratiques" />
<field name="eligible" />
</tree> </tree>
</field> </field>
</group> </group>
</xpath> </xpath>
<xpath expr="//field[@name='user_id']" position="after"> <xpath expr="//field[@name='user_id']" position="after">
<field name="formateur_id"/> <field name="formateur_id" />
</xpath> </xpath>
<xpath expr="//field[@name='date_deadline']" position="after"> <xpath expr="//field[@name='date_deadline']" position="after">
<field name="date_account"/> <field name="date_account" />
<field name="duree_jr"/> <field name="duree_jr" />
<field name="cout_seance"/> <field name="cout_seance" />
<field name="subtask_project_id" invisible="1" /> <field name="subtask_project_id" invisible="1" />
<field name="parent_id" invisible="1" /> <field name="parent_id" invisible="1" />
<field name="partner_id" invisible="1" /> <field name="partner_id" invisible="1" />
</xpath> </xpath>
<xpath expr="//notebook/page[@name='description_page']" position="attributes"> <xpath
expr="//notebook/page[@name='description_page']"
position="attributes"
>
<attribute name="invisible">1</attribute> <attribute name="invisible">1</attribute>
</xpath> </xpath>
<xpath expr="//notebook/page[@name='extra_info']" position="attributes"> <xpath expr="//notebook/page[@name='extra_info']" position="attributes">
...@@ -59,10 +68,10 @@ ...@@ -59,10 +68,10 @@
<record id="quick_create_task_form" model="ir.ui.view"> <record id="quick_create_task_form" model="ir.ui.view">
<field name="name">project.task.form.quick_create.inherit</field> <field name="name">project.task.form.quick_create.inherit</field>
<field name="model">project.task</field> <field name="model">project.task</field>
<field name="inherit_id" ref="project.quick_create_task_form"/> <field name="inherit_id" ref="project.quick_create_task_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="user_id" position="replace"> <field name="user_id" position="replace">
<field name="date_deadline"/> <field name="date_deadline" />
</field> </field>
</field> </field>
</record> </record>
...@@ -70,18 +79,21 @@ ...@@ -70,18 +79,21 @@
<record model="ir.ui.view" id="view_task_kanban"> <record model="ir.ui.view" id="view_task_kanban">
<field name="name">project.task.kanban</field> <field name="name">project.task.kanban</field>
<field name="model">project.task</field> <field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_kanban"/> <field name="inherit_id" ref="project.view_task_kanban" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<kanban position="attributes"> <kanban position="attributes">
<attribute name="default_order">date_deadline asc</attribute> <attribute name="default_order">date_deadline asc</attribute>
</kanban> </kanban>
<field name="user_id" position="after"> <field name="user_id" position="after">
<field name="cout_seance"/> <field name="cout_seance" />
</field> </field>
<xpath expr="//templates//div[@class='o_kanban_record_headings']//small" position="inside"> <xpath
<br/> expr="//templates//div[@class='o_kanban_record_headings']//small"
position="inside"
>
<br />
<t t-if="record.cout_seance.raw_value"> <t t-if="record.cout_seance.raw_value">
<span>Coût de la séance: </span><field name="cout_seance"/> <span>Coût de la séance: </span><field name="cout_seance" />
</t> </t>
</xpath> </xpath>
...@@ -89,4 +101,4 @@ ...@@ -89,4 +101,4 @@
</record> </record>
</data> </data>
</odoo> </odoo>
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020-2022 Le Filament
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record id="res_config_settings_view_form" model="ir.ui.view"> <record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.sale.legicoop</field> <field name="name">res.config.settings.view.form.inherit.sale.legicoop</field>
<field name="model">res.config.settings</field> <field name="model">res.config.settings</field>
<field name="priority" eval="10"/> <field name="priority" eval="10" />
<field name="inherit_id" ref="project.res_config_settings_view_form" /> <field name="inherit_id" ref="project.res_config_settings_view_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//div[@name='project_time']" position="after"> <xpath expr="//div[@name='project_time']" position="after">
<h2>Projet Adefpat Spécifique</h2> <h2>Projet Adefpat Spécifique</h2>
<div name="adefpat_project" class="row mt16 o_settings_container"> <div name="adefpat_project" class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box" > <div class="col-12 col-lg-6 o_setting_box">
<div > <div>
<label for="explication_financement"/> <label for="explication_financement" />
<div class="text-muted"> <div class="text-muted">
Texte pour le bloc Prestations Texte pour le bloc Prestations
</div> </div>
<div class="content-group" > <div class="content-group">
<div class="mt16"> <div class="mt16">
<field name="explication_financement" placeholder="Explication financement..."/> <field
name="explication_financement"
placeholder="Explication financement..."
/>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-12 col-lg-6 o_setting_box" > <div class="col-12 col-lg-6 o_setting_box">
<div > <div>
<label for="modalites_intervention"/> <label for="modalites_intervention" />
<div class="text-muted"> <div class="text-muted">
Texte pour les modalités d'intervention Texte pour les modalités d'intervention
</div> </div>
<div class="content-group" > <div class="content-group">
<div class="mt16"> <div class="mt16">
<field name="modalites_intervention" placeholder="Modalités d'intervention..."/> <field
name="modalites_intervention"
placeholder="Modalités d'intervention..."
/>
</div> </div>
</div> </div>
</div> </div>
<div > <div>
<label for="modalites_facturation"/> <label for="modalites_facturation" />
<div class="text-muted"> <div class="text-muted">
Texte pour les modalités de facturation Texte pour les modalités de facturation
</div> </div>
<div class="content-group" > <div class="content-group">
<div class="mt16"> <div class="mt16">
<field name="modalites_facturation" placeholder="Modalités de facturation..."/> <field
name="modalites_facturation"
placeholder="Modalités de facturation..."
/>
</div> </div>
</div> </div>
</div> </div>
<div > <div>
<label for="modalites_reponse"/> <label for="modalites_reponse" />
<div class="text-muted"> <div class="text-muted">
Texte pour les modalités de réponse Texte pour les modalités de réponse
</div> </div>
<div class="content-group" > <div class="content-group">
<div class="mt16"> <div class="mt16">
<field name="modalites_reponse" placeholder="Modalités de réponse..."/> <field
name="modalites_reponse"
placeholder="Modalités de réponse..."
/>
</div> </div>
</div> </div>
</div> </div>
<div > <div>
<label for="modalites_modif_marche"/> <label for="modalites_modif_marche" />
<div class="text-muted"> <div class="text-muted">
Texte pour les modalités de modification de marché Texte pour les modalités de modification de marché
</div> </div>
<div class="content-group" > <div class="content-group">
<div class="mt16"> <div class="mt16">
<field name="modalites_modif_marche" placeholder="Modalités de modification de marché..."/> <field
name="modalites_modif_marche"
placeholder="Modalités de modification de marché..."
/>
</div> </div>
</div> </div>
</div> </div>
...@@ -74,4 +91,4 @@ ...@@ -74,4 +91,4 @@
</field> </field>
</record> </record>
</odoo> </odoo>
\ No newline at end of file
<?xml version="1.0"?> <?xml version="1.0" ?>
<!-- Copyright 2020 Le Filament <!-- Copyright 2020-2022 Le Filament
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<data> <data>
<record id="view_res_partner_filter" model="ir.ui.view"> <record id="view_res_partner_filter" model="ir.ui.view">
<field name="name">res.partner.search</field> <field name="name">res.partner.search</field>
<field name="model">res.partner</field> <field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_res_partner_filter"/> <field name="inherit_id" ref="base.view_res_partner_filter" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//filter[@name='type_company']" position="after"> <xpath expr="//filter[@name='type_company']" position="after">
<separator/> <separator />
<filter string="Porteurs de projets" name="filt_porteurs" <filter
domain="[('project_count', '>', 0)]"/> string="Porteurs de projets"
name="filt_porteurs"
domain="[('project_count', '>', 0)]"
/>
</xpath> </xpath>
</field> </field>
</record> </record>
...@@ -21,15 +23,24 @@ ...@@ -21,15 +23,24 @@
<record id="view_partner_form" model="ir.ui.view"> <record id="view_partner_form" model="ir.ui.view">
<field name="name">view.partner.form.inherit</field> <field name="name">view.partner.form.inherit</field>
<field name="model">res.partner</field> <field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/> <field name="inherit_id" ref="base.view_partner_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<button name="toggle_active" position="before"> <button name="toggle_active" position="before">
<button class="oe_stat_button" type="object" name="action_view_partner_projects" <button
icon="fa-puzzle-piece" attrs="{'invisible': [('project_count', '=', 0)]}"> class="oe_stat_button"
<field string="Projects" name="project_count" widget="statinfo"/> type="object"
name="action_view_partner_projects"
icon="fa-puzzle-piece"
attrs="{'invisible': [('project_count', '=', 0)]}"
>
<field
string="Projects"
name="project_count"
widget="statinfo"
/>
</button> </button>
</button> </button>
</field> </field>
</record> </record>
</data> </data>
</odoo> </odoo>
\ No newline at end of file
# Copyright 2020-2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import adefpat_project_report_wizard
# Copyright 2022 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 AdefpatProjectReport(models.TransientModel):
_name = "adefpat.project.report.wizard"
_description = "Wizard rapports projets"
period_start = fields.Date("Début de période", required=True)
period_end = fields.Date(
"Fin de période", required=True, default=fields.Date.today()
)
export_type = fields.Selection(
[
("activity", "Activité"),
("benef", "Bénéficiaires"),
("cf", "Consultants Formateurs"),
("results", "Résultats"),
],
string="Type de rapport",
required=True,
default="activity",
)
is_fd = fields.Boolean("Convention FD uniquement", default=True)
is_closed = fields.Boolean("Projet clôturé sur la période uniquement", default=True)
@api.onchange("export_type")
def onchange_bools(self):
# Default values depending of export_type
if self.export_type in ["benef", "cf"]:
self.is_closed = False
else:
self.is_closed = True
# function will trigger from the show report button
@api.multi
def show_report(self):
# Get Projects with at least 1 task on period
project_ids = self.env["project.task"].search([
("date_deadline", "<=", self.period_end),
("date_deadline", ">=", self.period_start),
]).mapped("project_id")
if self.is_fd:
project_ids = project_ids.filtered(lambda p: p.type_convention_id.is_fd)
if self.is_closed:
project_ids = project_ids.filtered(
lambda p: p.closing_date and p.closing_date <= self.period_end
and p.closing_date >= self.period_start)
# Select view
res_model = "project.project"
domain = [("id", "in", project_ids.ids)]
limit = len(project_ids)
# Rapport Activité
if self.export_type == "activity":
tree_view = self.env.ref(
"adefpat_project.view_adefpat_project_reporting_tree"
)
# Rapport Porteurs de projets
elif self.export_type == "benef":
tree_view = self.env.ref(
"adefpat_project.view_adefpat_participant_reporting_tree"
)
res_model = "res.partner.porteur.project"
domain = [("project_id", "in", project_ids.ids)]
limit = self.env["res.partner.porteur.project"].search_count(domain)
# Rapport Formateurs
elif self.export_type == "cf":
tree_view = self.env.ref("adefpat_project.view_adefpat_formateur_reporting_tree")
res_model = "adefpat.formateur.project.report"
domain = [("project_id", "in", project_ids.ids)]
limit = self.env["adefpat.formateur.project.report"].search_count(domain)
elif self.export_type == "results":
tree_view = self.env.ref("adefpat_project.view_adefpat_project_result_tree")
action_name = "Rapport %s | Du %s au %s" % (
dict(self._fields["export_type"].selection).get(self.export_type),
fields.Date.to_string(self.period_start),
fields.Date.to_string(self.period_end),
)
return {
"type": "ir.actions.act_window",
"name": action_name,
"res_model": res_model,
"view_mode": "tree",
"views": [(tree_view.id, "tree")],
"target": "main",
"domain": domain,
"context": {
"period_start": self.period_start,
"period_end": self.period_end,
"is_fd": self.is_fd,
"is_closed": self.is_closed
},
"limit": limit,
}
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2022 Le Filament
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="adefpat_project_report_wizard_form" model="ir.ui.view">
<field name="name">adefpat.project.report.wizard.form</field>
<field name="model">adefpat.project.report.wizard</field>
<field name="arch" type="xml">
<form string="Génération du Rapport d'Activité">
<group>
<group>
<field name="export_type" widget="radio" />
</group>
<group>
<field name="period_start" />
<field name="period_end" />
<field name="is_fd" />
<field name="is_closed" />
</group>
</group>
<footer>
<button
class="btn btn-sm btn-primary"
name="show_report"
string="Générer le rapport"
type="object"
/>
<button
class="btn btn-sm btn-default"
special="cancel"
string="Fermer"
/>
</footer>
</form>
</field>
</record>
<record id="adefpat_project_report_action" model="ir.actions.act_window">
<field name="name">Rapport d'Activité</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">adefpat.project.report.wizard</field>
<field name="view_id" ref="adefpat_project_report_wizard_form" />
<field name="target">new</field>
</record>
<menuitem
id="adefpat_project.menu_activity_report"
name="Rapport d'Activité"
parent="project.menu_project_report"
action="adefpat_project_report_action"
sequence="20"
/>
</odoo>