Sélectionner une révision Git
Bifurcation depuis
Le Filament / Confédération Générale des SCOP / cgscop_expense
Le projet source a une visibilité limitée.
hr_expense.py 7,04 Kio
# © 2019 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import re
import requests
import logging
from math import ceil
from odoo import models, fields, api, exceptions
_logger = logging.getLogger(__name__)
class CGScopExpense(models.Model):
_inherit = 'hr.expense'
expense_gap = fields.Float(
string="Plafond de dépense",
related="product_id.expense_gap")
timesheet_id = fields.Many2one(
comodel_name="account.analytic.line",
string="Ligne de Temps",
ondelete="restrict")
analytic_account_id = fields.Many2one(
related="timesheet_id.account_id",
string="Code Activité UR",
store=True)
coop_id = fields.Many2one(
related="timesheet_id.partner_id",
string="Contact",
store=True)
ur_financial_system_id = fields.Many2one(
related="timesheet_id.ur_financial_system_id",
string='Dispositif Financier',
store=True)
ur_regional_convention_id = fields.Many2one(
related="timesheet_id.ur_regional_convention_id",
string='Convention Régionale',
store=True)
expense_formula = fields.Selection(
related='product_id.expense_formula')
is_ik = fields.Boolean(
related='product_id.is_ik')
quantity_computed = fields.Float(
string="Quantité",
compute="_compute_values")
unit_amount_computed = fields.Float(
string="Prix",
compute="_compute_values")
from_address = fields.Text(
string="Adresse de départ",
compute='_compute_from_address',
store=True)
to_address = fields.Text(
string="Adresse d'arrivée",
compute='_compute_to_address',
store=True)
is_return = fields.Boolean("Aller/Retour")
# ------------------------------------------------------
# Default Fields
# ------------------------------------------------------
def _default_from_address(self):
return self.env.uid
# ------------------------------------------------------
# Computed Fields
# ------------------------------------------------------
@api.depends('quantity', 'unit_amount')
def _compute_values(self):
for expense in self:
expense.quantity_computed = expense.quantity
expense.unit_amount_computed = expense.unit_amount
@api.depends('employee_id')
def _compute_from_address(self):
for expense in self:
if expense.employee_id:
expense.from_address = expense._format_address(
expense.employee_id.address_id)
@api.depends('timesheet_id')
def _compute_to_address(self):
for expense in self:
if expense.timesheet_id:
expense.to_address = expense._format_address(
expense.timesheet_id.partner_id)
# ------------------------------------------------------
# Onchange Fields
# ------------------------------------------------------
@api.onchange('total_amount')
def onchange_total_amount(self):
"""
Lève une alerte si le montant dépasse le plafond
"""
for exp in self:
if exp.product_id.expense_gap > 0:
if exp.total_amount > exp.product_id.expense_gap:
return {
'warning': {
'title': "Plafond dépassé",
'message': "Attention, le montant est supérieur \
au plafond autorisé"}}
@api.onchange('product_id')
def onchange_product_id(self):
"""
Change l'intégration de la NDF en fonction du type de produite
"""
if self.product_id.expense_formula == 'fixed_price':
self.unit_amount = self.product_id.standard_price
self.update({
'unit_amount': self.product_id.standard_price
})
elif self.product_id.expense_formula == 'fixed_rate':
self.quantity = 1.0
self.product_id.unit_amount = self.product_id.standard_price
@api.onchange('is_return')
def onchange_is_return(self):
"""
Définit le comportement lorsqu'on coche Aller/Retour
"""
if ((self.product_id.expense_formula == 'fixed_price') and
(self.product_id.is_ik)):
if self.is_return:
self.quantity = self.quantity * 2
elif not self.is_return:
self.quantity = self.quantity / 2
# ------------------------------------------------------
# Button function
# ------------------------------------------------------
def get_ik(self):
if not self.from_address or not self.to_address:
raise exceptions.Warning(
"Les adresses de départ et d'arrivée doivent être renseignées")
else:
# retourne la distance entre les 2 adresses
distance = self._get_distance(
self._get_coord(self.from_address),
self._get_coord(self.to_address))
quantity = ceil(distance/5)*5
if self.is_return:
self.quantity = quantity * 2
else:
self.quantity = quantity
# ------------------------------------------------------
# Global function
# ------------------------------------------------------
def _format_address(self, partner):
address = partner.street or ''
if partner.street2:
address += '\n' + partner.street2
if partner.street3:
address += '\n' + partner.street3
if partner.zip:
address += '\n' + partner.zip
if partner.city:
address += ' ' + partner.city
elif partner.city:
address += '\n' + partner.city
return address
def _get_coord(self, address):
addr = re.sub(r"\W", "+", address, flags=re.I)
url = 'https://api-adresse.data.gouv.fr/search/?q=' + addr
try:
response = requests.get(url)
coord = response.json().get('features')[0].get('geometry').get('coordinates')
return str(coord[0]) + ',' + str(coord[1])
except Exception as err:
_logger.warning(
"Erreur de connexion. URL: %s",
err.__str__(),
)
raise exceptions.Warning(
"Erreur de connexion avec l'API")
return False
def _get_distance(self, coord1, coord2):
url = ('http://router.project-osrm.org/route/v1/car/' + coord1 +
';' + coord2 + '?alternatives=false&overview=false')
try:
response = requests.get(url)
dist = response.json().get('routes')[0].get('legs')[0].get('distance')
return dist / 1000
except Exception as err:
_logger.warning(
"Erreur de connexion. URL: %s",
err.__str__(),
)
raise exceptions.Warning(
"Erreur de connexion avec l'API")
return False