<commit_before>r"""Functions for exclusive $B\to P\ell^+\ell^-$ decays."""

from math import sqrt,pi
from flavio.physics.bdecays.common import lambda_K, beta_l, meson_quark, meson_ff
from flavio.physics import ckm
from flavio.classes import AuxiliaryQuantity
from flavio.config import config
from flavio.physics.running import running
from flavio.physics.common import conjugate_par, conjugate_wc, add_dict
from flavio.physics.bdecays import matrixelements, angular
from flavio.physics.bdecays.wilsoncoefficients import get_wceff, wctot_dict
from scipy.integrate import quad
from flavio.classes import Observable, Prediction

def prefactor(q2, par, B, P, lep):
    GF = par['GF']
    ml = par['m_'+lep]
    scale = config['renormalization scale']['bpll']
    alphaem = running.get_alpha(par, scale)['alpha_e']
    di_dj = meson_quark[(B,P)]
    xi_t = ckm.xi('t',di_dj)(par)
    if q2 <= 4*ml**2:
        return 0
    return 4*GF/sqrt(2)*xi_t*alphaem/(4*pi)

# form factors
def get_ff(q2, par, B, P):
    ff_name = meson_ff[(B,P)] + ' form factor'
    return AuxiliaryQuantity.get_instance(ff_name).prediction(par_dict=par, wc_obj=None, q2=q2)

# get subleading hadronic contribution
def get_subleading(q2, wc_obj, par_dict, B, P, lep, cp_conjugate):
    if q2 <= 9:
        sub_name = B+'->'+P+lep+lep + ' subleading effects at low q2'
        return AuxiliaryQuantity.get_instance(sub_name).prediction(par_dict=par_dict, wc_obj=wc_obj, q2=q2, cp_conjugate=cp_conjugate)
    elif q2 > 14:
        sub_name = B+'->'+P+lep+lep + ' subleading effects at high q2'
        return AuxiliaryQuantity.get_instance(sub_name).prediction(par_dict=par_dict, wc_obj=wc_obj, q2=q2, cp_conjugate=cp_conjugate)
    else:
        return {}

def helicity_amps_ff(q2, wc_obj, par_dict, B, P, lep, cp_conjugate):
    par = par_dict.copy()
    if cp_conjugate:
        par = conjugate_par(par)
    scale = config['renormalization scale']['bpll']
    label = meson_quark[(B,P)] + lep + lep # e.g. bsmumu, bdtautau
    wc = wctot_dict(wc_obj, label, scale, par)
    if cp_conjugate:
        wc = conjugate_wc(wc)
    wc_eff = get_wceff(q2, wc, par, B, P, lep, scale)
    ml = par['m_'+lep]
    mB = par['m_'+B]
    mP = par['m_'+P]
    mb = running.get_mb(par, scale)
    N = prefactor(q2, par, B, P, lep)
    ff = get_ff(q2, par, B, P)
    h = angular.helicity_amps_p(q2, mB, mP, mb, 0, ml, ml, ff, wc_eff, N)
    return h

def helicity_amps(q2, wc_obj, par, B, P, lep):
    if q2 >= 8.7 and q2 < 14:
        warnings.warn("The predictions in the region of narrow charmonium resonances are not meaningful")
    return add_dict((
        helicity_amps_ff(q2, wc_obj, par, B, P, lep, cp_conjugate=False),
        get_subleading(q2, wc_obj, par, B, P, lep, cp_conjugate=False)
        ))

def helicity_amps_bar(q2, wc_obj, par, B, P, lep):
    if q2 >= 8.7 and q2 < 14:
        warnings.warn("The predictions in the region of narrow charmonium resonances are not meaningful")
    return add_dict((
        helicity_amps_ff(q2, wc_obj, par, B, P, lep, cp_conjugate=True),
        get_subleading(q2, wc_obj, par, B, P, lep, cp_conjugate=True)
        ))

def bpll_obs(function, q2, wc_obj, par, B, P, lep):
    ml = par['m_'+lep]
    mB = par['m_'+B]
    mP = par['m_'+P]
    if q2 < 4*ml**2 or q2 > (mB-mP)**2:
        return 0
    scale = config['renormalization scale']['bpll']
    mb = running.get_mb(par, scale)
    h     = helicity_amps(q2, wc_obj, par, B, P, lep)
    h_bar = helicity_amps_bar(q2, wc_obj, par, B, P, lep)
    J     = angular.angularcoeffs_general_p(h, q2, mB, mP, mb, 0, ml, ml)
    J_bar = angular.angularcoeffs_general_p(h_bar, q2, mB, mP, mb, 0, ml, ml)
    return function(J, J_bar)

def dGdq2(J):
    return 2 * (J['a'] + J['c']/3.)

def AFB_num(J):
    return J['b']

def FH_num(J):
    return 2 * (J['a'] + J['c'])

def dGdq2_cpaverage(J, J_bar):
    return (dGdq2(J) + dGdq2(J_bar))/2.

def AFB_cpaverage_num(J, J_bar):
    return (AFB_num(J) + AFB_num(J_bar))/2.

def FH_cpaverage_num(J, J_bar):
    return (FH_num(J) + FH_num(J_bar))/2.

# denominator of normalized observables
def denominator(J, J_bar):
    return 2*dGdq2_cpaverage(J, J_bar)

def bpll_obs_int(function, q2min, q2max, wc_obj, par, B, P, lep):
    def obs(q2):
        return bpll_obs(function, q2, wc_obj, par, B, P, lep)
    return quad(obs, q2min, q2max, epsrel=0.01, epsabs=0)[0]

def bpll_dbrdq2(q2, wc_obj, par, B, P, lep):
    tauB = par['tau_'+B]
    return tauB * bpll_obs(dGdq2_cpaverage, q2, wc_obj, par, B, P, lep)

def bpll_dbrdq2_int(q2min, q2max, wc_obj, par, B, P, lep):
    def obs(q2):
        return bpll_dbrdq2(q2, wc_obj, par, B, P, lep)
    return quad(obs, q2min, q2max, epsrel=0.01, epsabs=0)[0]/(q2max-q2min)

# Functions returning functions needed for Prediction instances

def bpll_dbrdq2_int_func(B, P, lep):
    def fct(wc_obj, par, q2min, q2max):
        return bpll_dbrdq2_int(q2min, q2max, wc_obj, par, B, P, lep)
    return fct

def bpll_dbrdq2_func(B, P, lep):
    def fct(wc_obj, par, q2):
        return bpll_dbrdq2(q2, wc_obj, par, B, P, lep)
    return fct

def bpll_obs_int_ratio_func(func_num, func_den, B, P, lep):
    def fct(wc_obj, par, q2min, q2max):
        num = bpll_obs_int(func_num, q2min, q2max, wc_obj, par, B, P, lep)
        if num == 0:
            return 0
        den = bpll_obs_int(func_den, q2min, q2max, wc_obj, par, B, P, lep)
        return num/den
    return fct

def bpll_obs_int_ratio_leptonflavour(func, B, P, l1, l2):
    def fct(wc_obj, par, q2min, q2max):
        num = bpll_obs_int(func, q2min, q2max, wc_obj, par, B, P, l1)
        if num == 0:
            return 0
        denom = bpll_obs_int(func, q2min, q2max, wc_obj, par, B, P, l2)
        return num/denom
    return fct

def bpll_obs_ratio_func(func_num, func_den, B, P, lep):
    def fct(wc_obj, par, q2):
        num = bpll_obs(func_num, q2, wc_obj, par, B, P, lep)
        if num == 0:
            return 0
        den = bpll_obs(func_den, q2, wc_obj, par, B, P, lep)
        return num/den
    return fct

# Observable and Prediction instances

_tex = {'e': 'e', 'mu': '\mu', 'tau': r'\tau'}
_observables = {
'AFB': {'func_num': AFB_cpaverage_num, 'tex': r'A_\text{FB}', 'desc': 'forward-backward asymmetry'},
'FH': {'func_num': FH_cpaverage_num, 'tex': r'F_H', 'desc': 'flat term'},
}
_hadr = {
'B0->K': {'tex': r"B^0\to K^0", 'B': 'B0', 'P': 'K0', },
'B+->K': {'tex': r"B^+\to K^+", 'B': 'B+', 'P': 'K+', },
}

for l in ['e', 'mu', 'tau']:
    for M in _hadr.keys():
        for obs in sorted(_observables.keys()):
            _obs_name = "<" + obs + ">("+M+l+l+")"
            _obs = Observable(name=_obs_name, arguments=['q2min', 'q2max'])
            _obs.set_description('Binned ' + _observables[obs]['desc'] + r" in $" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-$")
            _obs.tex = r"$\langle " + _observables[obs]['tex'] + r"\rangle(" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-)$"
            Prediction(_obs_name, bpll_obs_int_ratio_func(_observables[obs]['func_num'], denominator, _hadr[M]['B'], _hadr[M]['P'], l))

            _obs_name = obs + "("+M+l+l+")"
            _obs = Observable(name=_obs_name, arguments=['q2'])
            _obs.set_description(_observables[obs]['desc'][0].capitalize() + _observables[obs]['desc'][1:] + r" in $" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-$")
            _obs.tex = r"$" + _observables[obs]['tex'] + r"(" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-)$"
            Prediction(_obs_name, bpll_obs_ratio_func(_observables[obs]['func_num'], denominator, _hadr[M]['B'], _hadr[M]['P'], l))

        # binned branching ratio
        _obs_name = "<dBR/dq2>("+M+l+l+")"
        _obs = Observable(name=_obs_name, arguments=['q2min', 'q2max'])
        _obs.set_description(r"Binned differential branching ratio of $" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-$")
        _obs.tex = r"$\langle \text{BR} \rangle(" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-)$"
        Prediction(_obs_name, bpll_dbrdq2_int_func(_hadr[M]['B'], _hadr[M]['P'], l))

        # differential branching ratio
        _obs_name = "dBR/dq2("+M+l+l+")"
        _obs = Observable(name=_obs_name, arguments=['q2'])
        _obs.set_description(r"Differntial branching ratio of $" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-$")
        _obs.tex = r"$\frac{d\text{BR}}{dq^2}(" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-)$"
        Prediction(_obs_name, bpll_dbrdq2_func(_hadr[M]['B'], _hadr[M]['P'], l))

# Lepton flavour ratios
for l in [('mu','e'), ('tau','mu'),]:
    for M in _hadr.keys():

            # binned ratio of BRs
            _obs_name = "<R"+l[0]+l[1]+">("+M+"ll)"
            _obs = Observable(name=_obs_name, arguments=['q2min', 'q2max'])
            _obs.set_description(r"Ratio of partial branching ratios of $" + _hadr[M]['tex'] +_tex[l[0]]+r"^+ "+_tex[l[0]]+r"^-$" + " and " + r"$" + _hadr[M]['tex'] +_tex[l[1]]+r"^+ "+_tex[l[1]]+"^-$")
            _obs.tex = r"$\langle R_{" + _tex[l[0]] + ' ' + _tex[l[1]] + r"} \rangle(" + _hadr[M]['tex'] + r"\ell^+\ell^-)$"
            Prediction(_obs_name, bpll_obs_int_ratio_leptonflavour(dGdq2_cpaverage, _hadr[M]['B'], _hadr[M]['P'], *l))
<commit_msg>[bdecays] Missing import added<commit_after>r"""Functions for exclusive $B\to P\ell^+\ell^-$ decays."""

from math import sqrt,pi
from flavio.physics.bdecays.common import lambda_K, beta_l, meson_quark, meson_ff
from flavio.physics import ckm
from flavio.classes import AuxiliaryQuantity
from flavio.config import config
from flavio.physics.running import running
from flavio.physics.common import conjugate_par, conjugate_wc, add_dict
from flavio.physics.bdecays import matrixelements, angular
from flavio.physics.bdecays.wilsoncoefficients import get_wceff, wctot_dict
from scipy.integrate import quad
from flavio.classes import Observable, Prediction
import warnings

def prefactor(q2, par, B, P, lep):
    GF = par['GF']
    ml = par['m_'+lep]
    scale = config['renormalization scale']['bpll']
    alphaem = running.get_alpha(par, scale)['alpha_e']
    di_dj = meson_quark[(B,P)]
    xi_t = ckm.xi('t',di_dj)(par)
    if q2 <= 4*ml**2:
        return 0
    return 4*GF/sqrt(2)*xi_t*alphaem/(4*pi)

# form factors
def get_ff(q2, par, B, P):
    ff_name = meson_ff[(B,P)] + ' form factor'
    return AuxiliaryQuantity.get_instance(ff_name).prediction(par_dict=par, wc_obj=None, q2=q2)

# get subleading hadronic contribution
def get_subleading(q2, wc_obj, par_dict, B, P, lep, cp_conjugate):
    if q2 <= 9:
        sub_name = B+'->'+P+lep+lep + ' subleading effects at low q2'
        return AuxiliaryQuantity.get_instance(sub_name).prediction(par_dict=par_dict, wc_obj=wc_obj, q2=q2, cp_conjugate=cp_conjugate)
    elif q2 > 14:
        sub_name = B+'->'+P+lep+lep + ' subleading effects at high q2'
        return AuxiliaryQuantity.get_instance(sub_name).prediction(par_dict=par_dict, wc_obj=wc_obj, q2=q2, cp_conjugate=cp_conjugate)
    else:
        return {}

def helicity_amps_ff(q2, wc_obj, par_dict, B, P, lep, cp_conjugate):
    par = par_dict.copy()
    if cp_conjugate:
        par = conjugate_par(par)
    scale = config['renormalization scale']['bpll']
    label = meson_quark[(B,P)] + lep + lep # e.g. bsmumu, bdtautau
    wc = wctot_dict(wc_obj, label, scale, par)
    if cp_conjugate:
        wc = conjugate_wc(wc)
    wc_eff = get_wceff(q2, wc, par, B, P, lep, scale)
    ml = par['m_'+lep]
    mB = par['m_'+B]
    mP = par['m_'+P]
    mb = running.get_mb(par, scale)
    N = prefactor(q2, par, B, P, lep)
    ff = get_ff(q2, par, B, P)
    h = angular.helicity_amps_p(q2, mB, mP, mb, 0, ml, ml, ff, wc_eff, N)
    return h

def helicity_amps(q2, wc_obj, par, B, P, lep):
    if q2 >= 8.7 and q2 < 14:
        warnings.warn("The predictions in the region of narrow charmonium resonances are not meaningful")
    return add_dict((
        helicity_amps_ff(q2, wc_obj, par, B, P, lep, cp_conjugate=False),
        get_subleading(q2, wc_obj, par, B, P, lep, cp_conjugate=False)
        ))

def helicity_amps_bar(q2, wc_obj, par, B, P, lep):
    if q2 >= 8.7 and q2 < 14:
        warnings.warn("The predictions in the region of narrow charmonium resonances are not meaningful")
    return add_dict((
        helicity_amps_ff(q2, wc_obj, par, B, P, lep, cp_conjugate=True),
        get_subleading(q2, wc_obj, par, B, P, lep, cp_conjugate=True)
        ))

def bpll_obs(function, q2, wc_obj, par, B, P, lep):
    ml = par['m_'+lep]
    mB = par['m_'+B]
    mP = par['m_'+P]
    if q2 < 4*ml**2 or q2 > (mB-mP)**2:
        return 0
    scale = config['renormalization scale']['bpll']
    mb = running.get_mb(par, scale)
    h     = helicity_amps(q2, wc_obj, par, B, P, lep)
    h_bar = helicity_amps_bar(q2, wc_obj, par, B, P, lep)
    J     = angular.angularcoeffs_general_p(h, q2, mB, mP, mb, 0, ml, ml)
    J_bar = angular.angularcoeffs_general_p(h_bar, q2, mB, mP, mb, 0, ml, ml)
    return function(J, J_bar)

def dGdq2(J):
    return 2 * (J['a'] + J['c']/3.)

def AFB_num(J):
    return J['b']

def FH_num(J):
    return 2 * (J['a'] + J['c'])

def dGdq2_cpaverage(J, J_bar):
    return (dGdq2(J) + dGdq2(J_bar))/2.

def AFB_cpaverage_num(J, J_bar):
    return (AFB_num(J) + AFB_num(J_bar))/2.

def FH_cpaverage_num(J, J_bar):
    return (FH_num(J) + FH_num(J_bar))/2.

# denominator of normalized observables
def denominator(J, J_bar):
    return 2*dGdq2_cpaverage(J, J_bar)

def bpll_obs_int(function, q2min, q2max, wc_obj, par, B, P, lep):
    def obs(q2):
        return bpll_obs(function, q2, wc_obj, par, B, P, lep)
    return quad(obs, q2min, q2max, epsrel=0.01, epsabs=0)[0]

def bpll_dbrdq2(q2, wc_obj, par, B, P, lep):
    tauB = par['tau_'+B]
    return tauB * bpll_obs(dGdq2_cpaverage, q2, wc_obj, par, B, P, lep)

def bpll_dbrdq2_int(q2min, q2max, wc_obj, par, B, P, lep):
    def obs(q2):
        return bpll_dbrdq2(q2, wc_obj, par, B, P, lep)
    return quad(obs, q2min, q2max, epsrel=0.01, epsabs=0)[0]/(q2max-q2min)

# Functions returning functions needed for Prediction instances

def bpll_dbrdq2_int_func(B, P, lep):
    def fct(wc_obj, par, q2min, q2max):
        return bpll_dbrdq2_int(q2min, q2max, wc_obj, par, B, P, lep)
    return fct

def bpll_dbrdq2_func(B, P, lep):
    def fct(wc_obj, par, q2):
        return bpll_dbrdq2(q2, wc_obj, par, B, P, lep)
    return fct

def bpll_obs_int_ratio_func(func_num, func_den, B, P, lep):
    def fct(wc_obj, par, q2min, q2max):
        num = bpll_obs_int(func_num, q2min, q2max, wc_obj, par, B, P, lep)
        if num == 0:
            return 0
        den = bpll_obs_int(func_den, q2min, q2max, wc_obj, par, B, P, lep)
        return num/den
    return fct

def bpll_obs_int_ratio_leptonflavour(func, B, P, l1, l2):
    def fct(wc_obj, par, q2min, q2max):
        num = bpll_obs_int(func, q2min, q2max, wc_obj, par, B, P, l1)
        if num == 0:
            return 0
        denom = bpll_obs_int(func, q2min, q2max, wc_obj, par, B, P, l2)
        return num/denom
    return fct

def bpll_obs_ratio_func(func_num, func_den, B, P, lep):
    def fct(wc_obj, par, q2):
        num = bpll_obs(func_num, q2, wc_obj, par, B, P, lep)
        if num == 0:
            return 0
        den = bpll_obs(func_den, q2, wc_obj, par, B, P, lep)
        return num/den
    return fct

# Observable and Prediction instances

_tex = {'e': 'e', 'mu': '\mu', 'tau': r'\tau'}
_observables = {
'AFB': {'func_num': AFB_cpaverage_num, 'tex': r'A_\text{FB}', 'desc': 'forward-backward asymmetry'},
'FH': {'func_num': FH_cpaverage_num, 'tex': r'F_H', 'desc': 'flat term'},
}
_hadr = {
'B0->K': {'tex': r"B^0\to K^0", 'B': 'B0', 'P': 'K0', },
'B+->K': {'tex': r"B^+\to K^+", 'B': 'B+', 'P': 'K+', },
}

for l in ['e', 'mu', 'tau']:
    for M in _hadr.keys():
        for obs in sorted(_observables.keys()):
            _obs_name = "<" + obs + ">("+M+l+l+")"
            _obs = Observable(name=_obs_name, arguments=['q2min', 'q2max'])
            _obs.set_description('Binned ' + _observables[obs]['desc'] + r" in $" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-$")
            _obs.tex = r"$\langle " + _observables[obs]['tex'] + r"\rangle(" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-)$"
            Prediction(_obs_name, bpll_obs_int_ratio_func(_observables[obs]['func_num'], denominator, _hadr[M]['B'], _hadr[M]['P'], l))

            _obs_name = obs + "("+M+l+l+")"
            _obs = Observable(name=_obs_name, arguments=['q2'])
            _obs.set_description(_observables[obs]['desc'][0].capitalize() + _observables[obs]['desc'][1:] + r" in $" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-$")
            _obs.tex = r"$" + _observables[obs]['tex'] + r"(" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-)$"
            Prediction(_obs_name, bpll_obs_ratio_func(_observables[obs]['func_num'], denominator, _hadr[M]['B'], _hadr[M]['P'], l))

        # binned branching ratio
        _obs_name = "<dBR/dq2>("+M+l+l+")"
        _obs = Observable(name=_obs_name, arguments=['q2min', 'q2max'])
        _obs.set_description(r"Binned differential branching ratio of $" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-$")
        _obs.tex = r"$\langle \text{BR} \rangle(" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-)$"
        Prediction(_obs_name, bpll_dbrdq2_int_func(_hadr[M]['B'], _hadr[M]['P'], l))

        # differential branching ratio
        _obs_name = "dBR/dq2("+M+l+l+")"
        _obs = Observable(name=_obs_name, arguments=['q2'])
        _obs.set_description(r"Differntial branching ratio of $" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-$")
        _obs.tex = r"$\frac{d\text{BR}}{dq^2}(" + _hadr[M]['tex'] +_tex[l]+r"^+"+_tex[l]+"^-)$"
        Prediction(_obs_name, bpll_dbrdq2_func(_hadr[M]['B'], _hadr[M]['P'], l))

# Lepton flavour ratios
for l in [('mu','e'), ('tau','mu'),]:
    for M in _hadr.keys():

            # binned ratio of BRs
            _obs_name = "<R"+l[0]+l[1]+">("+M+"ll)"
            _obs = Observable(name=_obs_name, arguments=['q2min', 'q2max'])
            _obs.set_description(r"Ratio of partial branching ratios of $" + _hadr[M]['tex'] +_tex[l[0]]+r"^+ "+_tex[l[0]]+r"^-$" + " and " + r"$" + _hadr[M]['tex'] +_tex[l[1]]+r"^+ "+_tex[l[1]]+"^-$")
            _obs.tex = r"$\langle R_{" + _tex[l[0]] + ' ' + _tex[l[1]] + r"} \rangle(" + _hadr[M]['tex'] + r"\ell^+\ell^-)$"
            Prediction(_obs_name, bpll_obs_int_ratio_leptonflavour(dGdq2_cpaverage, _hadr[M]['B'], _hadr[M]['P'], *l))
<|endoftext|>


<commit_before># Copyright 2018 Tecnativa - David Vidal
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
    'name': 'Portal Partner Select All',
    'version': '12.0.1.0.1',
    'category': 'Custom',
    'author': 'Tecnativa,'
              'Odoo Community Association (OCA)',
    'website': 'https://www.github.com/OCA/partner-contact',
    "license": "AGPL-3",
    'depends': [
        'portal',
    ],
    'data': [
        'wizard/portal_wizard.xml',
    ],
    'installable': True,
}
<commit_msg>portal_partner_select_all 12.0.1.0.2<commit_after># Copyright 2018 Tecnativa - David Vidal
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
    'name': 'Portal Partner Select All',
    'version': '12.0.1.0.2',
    'category': 'Custom',
    'author': 'Tecnativa,'
              'Odoo Community Association (OCA)',
    'website': 'https://www.github.com/OCA/partner-contact',
    "license": "AGPL-3",
    'depends': [
        'portal',
    ],
    'data': [
        'wizard/portal_wizard.xml',
    ],
    'installable': True,
}
<|endoftext|>


<commit_before># Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
{
    "name": """POS: rewards for shifts""",
    "summary": """Rewards for shifts in POS Debt & Credit notebook""",
    "category": "Point of Sale",
    # "live_test_url": "",
    "images": ['images/pos_debt_notebook_rewards.jpg'],
    "version": "12.0.1.0.0",
    "application": False,

    "author": "IT-Projects LLC, Kolushov Alexandr",
    "support": "pos@it-projects.info",
    "website": "https://apps.odoo.com/apps/modules/12.0/pos_debt_notebook_rewards/",
    "license": "LGPL-3",
    # "price": 9.00,
    # "currency": "EUR",

    "depends": [
        "pos_debt_notebook",
        "base_attendance",
        "barcodes",
    ],
    "external_dependencies": {"python": [], "bin": []},
    "data": [
        'security/pos_debt_notebook_reward_security.xml',
        'views/reward_view.xml',
        'views/reward_type_view.xml',
        'security/ir.model.access.csv',
    ],
    "qweb": [
    ],
    "demo": [
    ],

    "post_load": None,
    "pre_init_hook": None,
    "post_init_hook": None,
    "uninstall_hook": None,

    "auto_install": False,
    "installable": True,
}
<commit_msg>:sos: pos_debt_notebook_rewards<commit_after># Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
{
    "name": """POS: rewards for shifts""",
    "summary": """Rewards for shifts in POS Debt & Credit notebook""",
    "category": "Point of Sale",
    # "live_test_url": "",
    "images": ['images/pos_debt_notebook_rewards.jpg'],
    "version": "12.0.1.0.0",
    "application": False,

    "author": "IT-Projects LLC, Kolushov Alexandr",
    "support": "pos@it-projects.info",
    "website": "https://apps.odoo.com/apps/modules/12.0/pos_debt_notebook_rewards/",
    "license": "LGPL-3",
    # "price": 9.00,
    # "currency": "EUR",

    "depends": [
        "pos_debt_notebook",
        "base_attendance",
        "barcodes",
    ],
    "external_dependencies": {"python": [], "bin": []},
    "data": [
        'security/pos_debt_notebook_reward_security.xml',
        'views/reward_view.xml',
        'views/reward_type_view.xml',
        'security/ir.model.access.csv',
    ],
    "qweb": [
    ],
    "demo": [
    ],

    "post_load": None,
    "pre_init_hook": None,
    "post_init_hook": None,
    "uninstall_hook": None,

    "auto_install": False,
    "installable": False,
}
<|endoftext|>


<commit_before># Copyright Hybrid Logic Ltd.  See LICENSE file for details.

"""Tests for :module:`flocker.node.gear`."""

from zope.interface.verify import verifyObject

from twisted.trial.unittest import TestCase

from ...testtools import random_name, make_with_init_tests
from ..gear import IGearClient, FakeGearClient, AlreadyExists, PortMap, Unit

def make_igearclient_tests(fixture):
    """
    Create a TestCase for IGearClient.

    :param fixture: A fixture that returns a :class:`IGearClient`
        provider.
    """
    class IGearClientTests(TestCase):
        """
        Tests for :class:`IGearClientTests`.

        These are functional tests if run against a real geard.
        """
        def test_interface(self):
            """The tested object provides :class:`IGearClient`."""
            client = fixture(self)
            self.assertTrue(verifyObject(IGearClient, client))

        def test_add_and_remove(self):
            """An added unit can be removed without an error."""
            client = fixture(self)
            name = random_name()
            d = client.add(name, u"busybox")
            d.addCallback(lambda _: client.remove(name))
            return d

        def test_no_double_add(self):
            """Adding a unit with name that already exists results in error."""
            client = fixture(self)
            name = random_name()
            d = client.add(name, u"busybox")

            def added(_):
                self.addCleanup(client.remove, name)
                return client.add(name, u"busybox")
            d.addCallback(added)
            d = self.assertFailure(d, AlreadyExists)
            d.addCallback(lambda exc: self.assertEqual(exc.args[0], name))
            return d

        def test_remove_nonexistent_is_ok(self):
            """Removing a non-existent unit does not result in a error."""
            client = fixture(self)
            name = random_name()
            return client.remove(name)

        def test_double_remove_is_ok(self):
            """Removing a unit twice in a row does not result in error."""
            client = fixture(self)
            name = random_name()
            d = client.add(name, u"busybox")
            d.addCallback(lambda _: client.remove(name))
            d.addCallback(lambda _: client.remove(name))
            return d

        def test_unknown_does_not_exist(self):
            """A unit that was never added does not exist."""
            client = fixture(self)
            name = random_name()
            d = client.exists(name)
            d.addCallback(self.assertFalse)
            return d

        def test_added_exists(self):
            """An added unit exists."""
            client = fixture(self)
            name = random_name()
            d = client.add(name, u"busybox")

            def added(_):
                self.addCleanup(client.remove, name)
                return client.exists(name)
            d.addCallback(added)
            d.addCallback(self.assertTrue)
            return d

        def test_removed_does_not_exist(self):
            """A removed unit does not exist."""
            client = fixture(self)
            name = random_name()
            d = client.add(name, u"busybox")
            d.addCallback(lambda _: client.remove(name))
            d.addCallback(lambda _: client.exists(name))
            d.addCallback(self.assertFalse)
            return d

        def test_added_is_listed(self):
            """An added unit is included in the output of ``list()``."""
            client = fixture(self)
            name = b'rjw' + random_name()
            self.addCleanup(client.remove, name)
            expected_container_image = u"openshift/busybox-http-app"
            d = client.add(name, expected_container_image)
            d.addCallback(lambda _: client.list())

            def got_list(units):
                import pdb; pdb.set_trace()
                activating = Unit(name=name, activation_state=u"activating",
                                  container_image=expected_container_image)
                active = Unit(name=name, activation_state=u"active",
                              container_image=expected_container_image)
                self.assertTrue((activating in units) or
                                (active in units),
                                "Added unit not in %r: %r, %r" % (units, active, activating))
            d.addCallback(got_list)
            return d

        def test_removed_is_not_listed(self):
            """A removed unit is not included in the output of ``list()``."""
            client = fixture(self)
            name = random_name()

            d = client.add(name, u"openshift/busybox-http-ap")
            d.addCallback(lambda _: client.remove(name))
            d.addCallback(lambda _: client.list())

            def got_list(units):
                self.assertNotIn(name, [unit.name for unit in units])
            d.addCallback(got_list)
            return d

    return IGearClientTests

class FakeIGearClientTests(make_igearclient_tests(lambda t: FakeGearClient())):
    """
    ``IGearClient`` tests for ``FakeGearClient``.
    """

class FakeGearClientImplementationTests(TestCase):
    """
    Tests for implementation details of ``FakeGearClient``.
    """
    def test_units_default(self):
        """
        ``FakeGearClient._units`` is an empty dict by default.
        """
        self.assertEqual({}, FakeGearClient()._units)

    def test_units_override(self):
        """
        ``FakeGearClient._units`` can be supplied in the constructor.
        """
        units = {u'foo': Unit(name=u'foo', activation_state=u'active',
                              container_image=u'flocker/flocker:v1.0.0')}
        self.assertEqual(units, FakeGearClient(units=units)._units)

class PortMapInitTests(
        make_with_init_tests(
            record_type=PortMap,
            kwargs=dict(
                internal_port=5678,
                external_port=910,
            )
        )
):
    """
    Tests for ``PortMap.__init__``.
    """

class PortMapTests(TestCase):
    """
    Tests for ``PortMap``.

    XXX: The equality tests in this case are incomplete. See
    https://github.com/hynek/characteristic/issues/4 for a proposed solution to
    this.
    """
    def test_repr(self):
        """
        ``PortMap.__repr__`` shows the internal and external ports.
        """
        self.assertEqual(
            "<PortMap(internal_port=5678, external_port=910)>",
            repr(PortMap(internal_port=5678, external_port=910))
        )

    def test_equal(self):
        """
        ``PortMap`` instances with the same internal and external ports compare
        equal.
        """
        self.assertEqual(
            PortMap(internal_port=5678, external_port=910),
            PortMap(internal_port=5678, external_port=910),
        )

    def test_not_equal(self):
        """
        ``PortMap`` instances with the different internal and external ports do
        not compare equal.
        """
        self.assertNotEqual(
            PortMap(internal_port=5678, external_port=910),
            PortMap(internal_port=1516, external_port=1718)
        )

class UnitInitTests(
        make_with_init_tests(
            record_type=Unit,
            kwargs=dict(
                name=u'site-example.com',
                activation_state=u'active',
                container_image=u'flocker/flocker:v1.0.0',
                ports=(PortMap(internal_port=80, external_port=8080),),
                links=(PortMap(internal_port=3306, external_port=103306),),
            ),
            expected_defaults=dict(ports=(), links=())
        )
):
    """
    Tests for ``Unit.__init__``.
    """

class UnitTests(TestCase):
    """
    Tests for ``Unit``.

    XXX: The equality tests in this case are incomplete. See
    https://github.com/hynek/characteristic/issues/4 for a proposed solution to
    this.
    """
    def test_repr(self):
        """
        ``Unit.__repr__`` shows the name, activation_state, container_image,
        ports and links.
        """
        self.assertEqual(
            "<Unit(name=u'site-example.com', activation_state=u'active', "
            "container_image=u'flocker/flocker:v1.0.0', ports=[], links=[])>",
            repr(Unit(name=u'site-example.com', activation_state=u'active',
                      container_image=u'flocker/flocker:v1.0.0',
                      ports=[], links=[]))
        )
<commit_msg>remove debug ines<commit_after># Copyright Hybrid Logic Ltd.  See LICENSE file for details.

"""Tests for :module:`flocker.node.gear`."""

from zope.interface.verify import verifyObject

from twisted.trial.unittest import TestCase

from ...testtools import random_name, make_with_init_tests
from ..gear import IGearClient, FakeGearClient, AlreadyExists, PortMap, Unit

def make_igearclient_tests(fixture):
    """
    Create a TestCase for IGearClient.

    :param fixture: A fixture that returns a :class:`IGearClient`
        provider.
    """
    class IGearClientTests(TestCase):
        """
        Tests for :class:`IGearClientTests`.

        These are functional tests if run against a real geard.
        """
        def test_interface(self):
            """The tested object provides :class:`IGearClient`."""
            client = fixture(self)
            self.assertTrue(verifyObject(IGearClient, client))

        def test_add_and_remove(self):
            """An added unit can be removed without an error."""
            client = fixture(self)
            name = random_name()
            d = client.add(name, u"busybox")
            d.addCallback(lambda _: client.remove(name))
            return d

        def test_no_double_add(self):
            """Adding a unit with name that already exists results in error."""
            client = fixture(self)
            name = random_name()
            d = client.add(name, u"busybox")

            def added(_):
                self.addCleanup(client.remove, name)
                return client.add(name, u"busybox")
            d.addCallback(added)
            d = self.assertFailure(d, AlreadyExists)
            d.addCallback(lambda exc: self.assertEqual(exc.args[0], name))
            return d

        def test_remove_nonexistent_is_ok(self):
            """Removing a non-existent unit does not result in a error."""
            client = fixture(self)
            name = random_name()
            return client.remove(name)

        def test_double_remove_is_ok(self):
            """Removing a unit twice in a row does not result in error."""
            client = fixture(self)
            name = random_name()
            d = client.add(name, u"busybox")
            d.addCallback(lambda _: client.remove(name))
            d.addCallback(lambda _: client.remove(name))
            return d

        def test_unknown_does_not_exist(self):
            """A unit that was never added does not exist."""
            client = fixture(self)
            name = random_name()
            d = client.exists(name)
            d.addCallback(self.assertFalse)
            return d

        def test_added_exists(self):
            """An added unit exists."""
            client = fixture(self)
            name = random_name()
            d = client.add(name, u"busybox")

            def added(_):
                self.addCleanup(client.remove, name)
                return client.exists(name)
            d.addCallback(added)
            d.addCallback(self.assertTrue)
            return d

        def test_removed_does_not_exist(self):
            """A removed unit does not exist."""
            client = fixture(self)
            name = random_name()
            d = client.add(name, u"busybox")
            d.addCallback(lambda _: client.remove(name))
            d.addCallback(lambda _: client.exists(name))
            d.addCallback(self.assertFalse)
            return d

        def test_added_is_listed(self):
            """An added unit is included in the output of ``list()``."""
            client = fixture(self)
            name = random_name()
            self.addCleanup(client.remove, name)
            expected_container_image = u"openshift/busybox-http-app"
            d = client.add(name, expected_container_image)
            d.addCallback(lambda _: client.list())

            def got_list(units):
                activating = Unit(name=name, activation_state=u"activating",
                                  container_image=expected_container_image)
                active = Unit(name=name, activation_state=u"active",
                              container_image=expected_container_image)
                self.assertTrue((activating in units) or
                                (active in units),
                                "Added unit not in %r: %r, %r" % (units, active, activating))
            d.addCallback(got_list)
            return d

        def test_removed_is_not_listed(self):
            """A removed unit is not included in the output of ``list()``."""
            client = fixture(self)
            name = random_name()

            d = client.add(name, u"openshift/busybox-http-ap")
            d.addCallback(lambda _: client.remove(name))
            d.addCallback(lambda _: client.list())

            def got_list(units):
                self.assertNotIn(name, [unit.name for unit in units])
            d.addCallback(got_list)
            return d

    return IGearClientTests

class FakeIGearClientTests(make_igearclient_tests(lambda t: FakeGearClient())):
    """
    ``IGearClient`` tests for ``FakeGearClient``.
    """

class FakeGearClientImplementationTests(TestCase):
    """
    Tests for implementation details of ``FakeGearClient``.
    """
    def test_units_default(self):
        """
        ``FakeGearClient._units`` is an empty dict by default.
        """
        self.assertEqual({}, FakeGearClient()._units)

    def test_units_override(self):
        """
        ``FakeGearClient._units`` can be supplied in the constructor.
        """
        units = {u'foo': Unit(name=u'foo', activation_state=u'active',
                              container_image=u'flocker/flocker:v1.0.0')}
        self.assertEqual(units, FakeGearClient(units=units)._units)

class PortMapInitTests(
        make_with_init_tests(
            record_type=PortMap,
            kwargs=dict(
                internal_port=5678,
                external_port=910,
            )
        )
):
    """
    Tests for ``PortMap.__init__``.
    """

class PortMapTests(TestCase):
    """
    Tests for ``PortMap``.

    XXX: The equality tests in this case are incomplete. See
    https://github.com/hynek/characteristic/issues/4 for a proposed solution to
    this.
    """
    def test_repr(self):
        """
        ``PortMap.__repr__`` shows the internal and external ports.
        """
        self.assertEqual(
            "<PortMap(internal_port=5678, external_port=910)>",
            repr(PortMap(internal_port=5678, external_port=910))
        )

    def test_equal(self):
        """
        ``PortMap`` instances with the same internal and external ports compare
        equal.
        """
        self.assertEqual(
            PortMap(internal_port=5678, external_port=910),
            PortMap(internal_port=5678, external_port=910),
        )

    def test_not_equal(self):
        """
        ``PortMap`` instances with the different internal and external ports do
        not compare equal.
        """
        self.assertNotEqual(
            PortMap(internal_port=5678, external_port=910),
            PortMap(internal_port=1516, external_port=1718)
        )

class UnitInitTests(
        make_with_init_tests(
            record_type=Unit,
            kwargs=dict(
                name=u'site-example.com',
                activation_state=u'active',
                container_image=u'flocker/flocker:v1.0.0',
                ports=(PortMap(internal_port=80, external_port=8080),),
                links=(PortMap(internal_port=3306, external_port=103306),),
            ),
            expected_defaults=dict(ports=(), links=())
        )
):
    """
    Tests for ``Unit.__init__``.
    """

class UnitTests(TestCase):
    """
    Tests for ``Unit``.

    XXX: The equality tests in this case are incomplete. See
    https://github.com/hynek/characteristic/issues/4 for a proposed solution to
    this.
    """
    def test_repr(self):
        """
        ``Unit.__repr__`` shows the name, activation_state, container_image,
        ports and links.
        """
        self.assertEqual(
            "<Unit(name=u'site-example.com', activation_state=u'active', "
            "container_image=u'flocker/flocker:v1.0.0', ports=[], links=[])>",
            repr(Unit(name=u'site-example.com', activation_state=u'active',
                      container_image=u'flocker/flocker:v1.0.0',
                      ports=[], links=[]))
        )
<|endoftext|>


<commit_before>
from errno import EPIPE
from time import sleep
from uuid import UUID
import logging
import socket
import shlex
import json
import io

from fluxclient.robot import connect_robot
from fluxclient.upnp.task import UpnpTask
from fluxclient.fcode.g_to_f import GcodeToFcode
from .base import WebSocketBase, WebsocketBinaryHelperMixin, ST_NORMAL

logger = logging.getLogger("WS.CONTROL")

"""
Control printer

Javascript Example:

ws = new WebSocket("ws://localhost:8000/ws/control/RLFPAPI7E8KXG64KG5NOWWY3T");
ws.onmessage = function(v) { console.log(v.data);}
ws.onclose = function(v) { console.log("CONNECTION CLOSED, code=" + v.code +
    "; reason=" + v.reason); }

// After recive connected...
ws.send("ls")
"""

STAGE_DISCOVER = '{"status": "connecting", "stage": "discover"}'
STAGE_AUTH = '{"status": "connecting", "stage": "auth"}'
STAGE_ROBOT_INIT = '{"status": "connecting", "stage": "initial"}'
STAGE_ROBOT_LAUNGING = '{"status": "connecting", "stage": "launching"}'
STAGE_ROBOT_LAUNCHED = '{"status": "connecting", "stage": "launched"}'
STAGE_ROBOT_CONNECTING = '{"status": "connecting", "stage": "connecting"}'
STAGE_CONNECTED = '{"status": "connected"}'
STAGE_TIMEOUT = '{"status": "error", "error": "TIMEOUT"}'

class WebsocketControlBase(WebSocketBase):
    robot = None
    simple_mapping = None
    cmd_mapping = None

    def __init__(self, *args, serial):
        WebSocketBase.__init__(self, *args)
        self.uuid = UUID(hex=serial)

        self.send_text(STAGE_DISCOVER)
        logger.debug("DISCOVER")
        task = self._discover(self.uuid)

        self.send_text(STAGE_ROBOT_CONNECTING)
        self.robot = connect_robot((self.ipaddr, 23811),
                                   server_key=task.slave_key,
                                   conn_callback=self._conn_callback)

        self.send_text(STAGE_CONNECTED)

    def _fix_auth_error(self, task):
        self.send_text(STAGE_DISCOVER)
        if task.timedelta < -15:
            logger.warn("Auth error, try fix time delta")
            old_td = task.timedelta
            task.reload_remote_profile(lookup_timeout=30.)
            if task.timedelta - old_td > 0.5:
                # Fix timedelta issue let's retry
                p = self.server.discover_devices.get(self.uuid)
                if p:
                    p["timedelta"] = task.timedelta
                    self.server.discover_devices[self.uuid] = p
                    return True
        return False

    def on_closed(self):
        if self.robot:
            self.robot.close()
            self.robot = None
        self.simple_mapping = None
        self.cmd_mapping = None

    def _disc_callback(self, *args):
        self.send_text(STAGE_DISCOVER)
        return True

    def _conn_callback(self, *args):
        self.send_text(STAGE_ROBOT_CONNECTING)
        return True

    def _discover(self, uuid):
        profile = self.server.discover_devices.get(uuid)
        if profile:
            task = UpnpTask(self.uuid, remote_profile=profile,
                            lookup_timeout=4.0)
        else:
            task = UpnpTask(self.uuid, lookup_callback=self._disc_callback)

        self.ipaddr = task.endpoint[0]
        return task

class WebsocketControl(WebsocketControlBase):
    binary_sock = None
    raw_sock = None
    convert = None

    def __init__(self, *args, serial):
        WebsocketControlBase.__init__(self, *args, serial=serial)
        self.set_hooks()

    def set_hooks(self):
        self.simple_mapping = {
            "start": self.robot.start_play,
            "pause": self.robot.pause_play,
            "resume": self.robot.resume_play,
            "abort": self.robot.abort_play,
            "quit": self.robot.quit_task,

            "scan": self.robot.begin_scan,
            "scan_backward": self.robot.scan_backward,
            "scan_next": self.robot.scan_next,
            "kick": self.robot.kick,

            "maintain": self.robot.begin_maintain,
            "home": self.robot.maintain_home,
        }

        self.cmd_mapping = {
            "position": self.position,

            "ls": self.list_file,
            "select": self.select_file,
            "mkdir": self.mkdir,
            "rmdir": self.rmdir,
            "rmfile": self.rmfile,
            "cpfile": self.cpfile,
            "fileinfo": self.fileinfo,
            "upload": self.upload_file,
            "upload_g": self.upload_file,
            "update_fw": self.update_fw,
            "oneshot": self.oneshot,
            "scanimages": self.scanimages,
            "raw": self.begin_raw,

            "report": self.play_report,
            "eadj": self.maintain_eadj,
            "cor_h": self.maintain_corh
        }

    def on_binary_message(self, buf):
        if self.binary_sock or isinstance(self.convert, io.BytesIO):
            if isinstance(self.convert, io.BytesIO):
                self.binary_sent += self.convert.write(buf)
            else:
                self.binary_sent += self.binary_sock.send(buf)

            if self.binary_sent < self.binary_length:
                pass
            elif self.binary_sent == self.binary_length:
                if isinstance(self.convert, io.BytesIO):
                    f_buf = self.g_to_f()
                    print('f_buf', len(f_buf), self.uploadto)
                    self.binary_sock = self.robot.begin_upload('application/fcode', len(f_buf), uploadto=self.uploadto)
                    self.binary_sock.send(f_buf)
                    del self.uploadto
                    self.convert = None

                self.binary_sock = None

                resp = self.robot.get_resp().decode("ascii", "ignore")
                if resp == "ok":
                    self.send_text('{"status": "ok"}')
                else:
                    errargs = resp.split(" ")
                    self.send_error(*(errargs[1:]))
            else:
                self.binary_sock = None
                self.send_fatal("NOT_MATCH", "binary data length error")
        else:
            self.binary_sock = None
            self.send_fatal("PROTOCOL_ERROR", "Can not accept binary data")

    def on_text_message(self, message):
        if message == "ping":
            self.send_text('{"status": "pong"}')
            return

        if message == "over_my_dead_body":
            import tempfile
            import os
            import gc
            fn = os.path.join(tempfile.gettempdir(), "over_my_dead_body.dump")
            with open(fn, "w") as f:
                for o in gc.get_objects():
                    f.write(repr(o) + "\n")
            self.send_text("ok " + fn)
            return

        if self.raw_sock:
            self.on_raw_message(message)
            return

        args = shlex.split(message)
        cmd = args.pop(0)

        try:
            if cmd in self.simple_mapping:
                self.simple_cmd(self.simple_mapping[cmd], *args)
            elif cmd in self.cmd_mapping:
                func_ptr = self.cmd_mapping[cmd]
                func_ptr(*args)
            else:
                logger.error("Unknow Command: %s" % message)
                self.send_error("UNKNOW_COMMAND", "ws")

        except RuntimeError as e:
            logger.debug("RuntimeError%s" % repr(e.args))
            self.send_error(*e.args)

        except socket.error as e:
            if e.args[0] == EPIPE:
                self.send_fatal("DISCONNECTED", repr(e.__class__))
            else:
                logger.exception("Unknow Error")
                self.send_fatal("UNKNOW_ERROR", repr(e.__class__))

        except Exception as e:
            logger.exception("Unknow Error")
            self.send_error("UNKNOW_ERROR", repr(e.__class__))

    def simple_cmd(self, func, *args):
        try:
            self.send_text('{"status":"%s"}' % func(*args))
        except RuntimeError as e:
            self.send_error(*e.args)
        except Exception as e:
            logger.exception("Unknow Error")
            self.send_error("UNKNOW_ERROR", repr(e.__class__))

    def position(self):
        try:
            location = self.robot.position()
            self.send_text('{"status": "position", "location": "%s"}' %
                           location)
        except RuntimeError as e:
            self.send_error(*e.args)
        except Exception as e:
            logger.exception("Unknow Error")
            self.send_error("UNKNOW_ERROR", repr(e.__class__))

    def list_file(self, location=None):
        if location:
            params = location.split("/", 1)
            dirs = []
            files = []
            for is_dir, name in self.robot.list_files(*params):
                if is_dir:
                    dirs.append(name)
                else:
                    files.append(name)

            payload = {"status": "ok", "path": location, "directories": dirs,
                       "files": files}
            self.send_text(json.dumps(payload))
        else:
            self.send_text('{"status": "ok", "path": "", "directories": '
                           '["SD", "USB"], "files": []}')

    def select_file(self, file):
        entry, path = file.split("/", 1)
        self.robot.select_file(entry, path)
        self.send_text('{"status": "ok"}')

    def fileinfo(self, file):
        entry, path = file.split("/", 1)
        info, binary = self.robot.fileinfo(entry, path)
        if binary:
            self.send_text(json.dumps({
                "status": "binary", "mimetype": binary[0],
                "size": len(binary[1])
            }))
            self.send_binary(binary[1])

        info["status"] = "ok"
        self.send_text(json.dumps(info))

    def mkdir(self, file):
        if file.startswith("SD/"):
            self.simple_cmd(self.robot.mkdir, "SD", file[3:])
        else:
            self.send_text('{"status": "error", "error": "NOT_SUPPORT"}')

    def rmdir(self, file):
        if file.startswith("SD/"):
            self.simple_cmd(self.robot.rmdir, "SD", file[3:])
        else:
            self.send_text('{"status": "error", "error": "NOT_SUPPORT"}')

    def rmfile(self, file):
        if file.startswith("SD/"):
            self.simple_cmd(self.robot.rmfile, "SD", file[3:])
        else:
            self.send_text('{"status": "error", "error": "NOT_SUPPORT"}')

    def cpfile(self, args):
        if args.startswith("@"):
            source, target = args[1:].split("#")
        else:
            source, target = args.split("\x00")
        params = source.split("/", 1) + target.split("/", 1)
        self.simple_cmd(self.robot.cpfile, *params)

    def upload_file(self, mimetype, size, uploadto="#", convert='0'):
        if uploadto == "#":
            pass
        elif uploadto.startswith("SD/"):
            uploadto = "SD " + uploadto[3:]
        elif uploadto.startswith("USB/"):
            uploadto = "USB " + uploadto[4:]

        if mimetype == "text/gcode" and convert != '1':
            self.send_text('{"status":"error", "error": "FCODE_ONLY"}')
            return
        if mimetype == "text/gcode" and convert == '1':
            self.convert = io.BytesIO()
            self.uploadto = uploadto
        else:
            self.convert = None
            self.binary_sock = self.robot.begin_upload(mimetype, int(size),
                                                       uploadto=uploadto)

        self.binary_length = int(size)
        self.binary_sent = 0
        self.send_text('{"status":"continue"}')

    def update_fw(self, mimetype, size):
        self.binary_sock = self.robot.begin_upload(mimetype, int(size),
                                                   cmd="update_fw")
        self.binary_length = int(size)
        self.binary_sent = 0
        self.send_text('{"status":"continue"}')

    def maintain_eadj(self, *args):
        def callback(nav):
            self.send_text("DEBUG: %s" % nav)
        if "clean" in args:
            ret = self.robot.maintain_eadj(navigate_callback=callback,
                                           clean=True)
        else:
            ret = self.robot.maintain_eadj(navigate_callback=callback)
        self.send_text(json.dumps({
            "status": "ok", "data": ret, "error": (max(*ret) - min(*ret))
        }))

    def maintain_corh(self, *args):
        def callback(nav):
            self.send_text("DEBUG: %s" % nav)

        if len(args) > 0:
            ret = self.robot.maintain_hadj(navigate_callback=callback,
                                           manual_h=float(args[0]))
        else:
            ret = self.robot.maintain_hadj(navigate_callback=callback)

        self.send_text(json.dumps({"status": "ok", "data": ret}))

    def play_report(self):
        # TODO
        data = self.robot.report_play()
        if isinstance(data, dict):
            data["status"] = "ok"
            data["cmd"] = "report"
            self.send_text(json.dumps(data))
        else:
            self.send_text(data)

    def oneshot(self):
        images = self.robot.oneshot()
        for mime, buf in images:
            size = len(buf)
            self.send_text('{"status": "binary", "mimetype": %s, '
                           '"size": %i}' % (mime, size))
            view = memoryview(buf)
            sent = 0
            while sent < size:
                self.send_binary(view[sent:sent + 4016])
                sent += 4016
        self.send_ok()

    def scanimages(self):
        images = self.robot.scanimages()
        for mime, buf in images:
            size = len(buf)
            self.send_text('{"status": "binary", "mimetype": %s, '
                           '"size": %i}' % (mime, size))
            view = memoryview(buf)
            sent = 0
            while sent < size:
                self.send_binary(view[sent:sent + 4016])
                sent += 4016
        self.send_ok()

    def begin_raw(self):
        self.raw_sock = RawSock(self.robot.raw_mode(), self)
        self.rlist.append(self.raw_sock)
        self.send_ok()

    def on_raw_message(self, message):
        if message == "quit":
            self.rlist.remove(self.raw_sock)
            self.raw_sock = None
            self.robot.quit_raw_mode()
            self.send_ok()
        else:
            self.raw_sock.sock.send(message.encode() + b"\n")

    def g_to_f(self):
        fcode_output = io.BytesIO()
        m_GcodeToFcode = GcodeToFcode()
        # print((self.convert.getvalue().decode()))
        m_GcodeToFcode.process(self.convert.getvalue().decode().split('\n'),
                               fcode_output)
        self.convert = None
        return fcode_output.getvalue()

class RawSock(object):
    def __init__(self, sock, ws):
        self.sock = sock
        self.ws = ws

    def fileno(self):
        return self.sock.fileno()

    def on_read(self):
        buf = self.sock.recv(128)
        if buf:
            self.ws.send_text(buf.decode("ascii", "replace"))
        else:
            self.ws.rlist.remove(self)
            self.ws.send_fatal("DISCONNECTED")
<commit_msg>Control: fix error handling<commit_after>
from errno import EPIPE
from time import sleep
from uuid import UUID
import logging
import socket
import shlex
import json
import io

from fluxclient.robot import connect_robot
from fluxclient.upnp.task import UpnpTask
from fluxclient.fcode.g_to_f import GcodeToFcode
from .base import WebSocketBase, WebsocketBinaryHelperMixin, ST_NORMAL

logger = logging.getLogger("WS.CONTROL")

"""
Control printer

Javascript Example:

ws = new WebSocket("ws://localhost:8000/ws/control/RLFPAPI7E8KXG64KG5NOWWY3T");
ws.onmessage = function(v) { console.log(v.data);}
ws.onclose = function(v) { console.log("CONNECTION CLOSED, code=" + v.code +
    "; reason=" + v.reason); }

// After recive connected...
ws.send("ls")
"""

STAGE_DISCOVER = '{"status": "connecting", "stage": "discover"}'
STAGE_AUTH = '{"status": "connecting", "stage": "auth"}'
STAGE_ROBOT_INIT = '{"status": "connecting", "stage": "initial"}'
STAGE_ROBOT_LAUNGING = '{"status": "connecting", "stage": "launching"}'
STAGE_ROBOT_LAUNCHED = '{"status": "connecting", "stage": "launched"}'
STAGE_ROBOT_CONNECTING = '{"status": "connecting", "stage": "connecting"}'
STAGE_CONNECTED = '{"status": "connected"}'
STAGE_TIMEOUT = '{"status": "error", "error": "TIMEOUT"}'

class WebsocketControlBase(WebSocketBase):
    robot = None
    simple_mapping = None
    cmd_mapping = None

    def __init__(self, *args, serial):
        WebSocketBase.__init__(self, *args)
        self.uuid = UUID(hex=serial)

        self.send_text(STAGE_DISCOVER)
        logger.debug("DISCOVER")
        task = self._discover(self.uuid)

        try:
            self.send_text(STAGE_ROBOT_CONNECTING)
            self.robot = connect_robot((self.ipaddr, 23811),
                                       server_key=task.slave_key,
                                       conn_callback=self._conn_callback)
        except RuntimeError as err:
            self.send_fatal(err.args[0], )
            raise

        self.send_text(STAGE_CONNECTED)

    def _fix_auth_error(self, task):
        self.send_text(STAGE_DISCOVER)
        if task.timedelta < -15:
            logger.warn("Auth error, try fix time delta")
            old_td = task.timedelta
            task.reload_remote_profile(lookup_timeout=30.)
            if task.timedelta - old_td > 0.5:
                # Fix timedelta issue let's retry
                p = self.server.discover_devices.get(self.uuid)
                if p:
                    p["timedelta"] = task.timedelta
                    self.server.discover_devices[self.uuid] = p
                    return True
        return False

    def on_closed(self):
        if self.robot:
            self.robot.close()
            self.robot = None
        self.simple_mapping = None
        self.cmd_mapping = None

    def _disc_callback(self, *args):
        self.send_text(STAGE_DISCOVER)
        return True

    def _conn_callback(self, *args):
        self.send_text(STAGE_ROBOT_CONNECTING)
        return True

    def _discover(self, uuid):
        profile = self.server.discover_devices.get(uuid)
        if profile:
            task = UpnpTask(self.uuid, remote_profile=profile,
                            lookup_timeout=4.0)
        else:
            task = UpnpTask(self.uuid, lookup_callback=self._disc_callback)

        self.ipaddr = task.endpoint[0]
        return task

class WebsocketControl(WebsocketControlBase):
    binary_sock = None
    raw_sock = None
    convert = None

    def __init__(self, *args, serial):
        WebsocketControlBase.__init__(self, *args, serial=serial)
        self.set_hooks()

    def set_hooks(self):
        self.simple_mapping = {
            "start": self.robot.start_play,
            "pause": self.robot.pause_play,
            "resume": self.robot.resume_play,
            "abort": self.robot.abort_play,
            "quit": self.robot.quit_task,

            "scan": self.robot.begin_scan,
            "scan_backward": self.robot.scan_backward,
            "scan_next": self.robot.scan_next,
            "kick": self.robot.kick,

            "maintain": self.robot.begin_maintain,
            "home": self.robot.maintain_home,
        }

        self.cmd_mapping = {
            "position": self.position,

            "ls": self.list_file,
            "select": self.select_file,
            "mkdir": self.mkdir,
            "rmdir": self.rmdir,
            "rmfile": self.rmfile,
            "cpfile": self.cpfile,
            "fileinfo": self.fileinfo,
            "upload": self.upload_file,
            "upload_g": self.upload_file,
            "update_fw": self.update_fw,
            "oneshot": self.oneshot,
            "scanimages": self.scanimages,
            "raw": self.begin_raw,

            "report": self.play_report,
            "eadj": self.maintain_eadj,
            "cor_h": self.maintain_corh
        }

    def on_binary_message(self, buf):
        if self.binary_sock or isinstance(self.convert, io.BytesIO):
            if isinstance(self.convert, io.BytesIO):
                self.binary_sent += self.convert.write(buf)
            else:
                self.binary_sent += self.binary_sock.send(buf)

            if self.binary_sent < self.binary_length:
                pass
            elif self.binary_sent == self.binary_length:
                if isinstance(self.convert, io.BytesIO):
                    f_buf = self.g_to_f()
                    print('f_buf', len(f_buf), self.uploadto)
                    self.binary_sock = self.robot.begin_upload('application/fcode', len(f_buf), uploadto=self.uploadto)
                    self.binary_sock.send(f_buf)
                    del self.uploadto
                    self.convert = None

                self.binary_sock = None

                resp = self.robot.get_resp().decode("ascii", "ignore")
                if resp == "ok":
                    self.send_text('{"status": "ok"}')
                else:
                    errargs = resp.split(" ")
                    self.send_error(*(errargs[1:]))
            else:
                self.binary_sock = None
                self.send_fatal("NOT_MATCH", "binary data length error")
        else:
            self.binary_sock = None
            self.send_fatal("PROTOCOL_ERROR", "Can not accept binary data")

    def on_text_message(self, message):
        if message == "ping":
            self.send_text('{"status": "pong"}')
            return

        if message == "over_my_dead_body":
            import tempfile
            import os
            import gc
            fn = os.path.join(tempfile.gettempdir(), "over_my_dead_body.dump")
            with open(fn, "w") as f:
                for o in gc.get_objects():
                    f.write(repr(o) + "\n")
            self.send_text("ok " + fn)
            return

        if self.raw_sock:
            self.on_raw_message(message)
            return

        args = shlex.split(message)
        cmd = args.pop(0)

        try:
            if cmd in self.simple_mapping:
                self.simple_cmd(self.simple_mapping[cmd], *args)
            elif cmd in self.cmd_mapping:
                func_ptr = self.cmd_mapping[cmd]
                func_ptr(*args)
            else:
                logger.error("Unknow Command: %s" % message)
                self.send_error("UNKNOW_COMMAND", "ws")

        except RuntimeError as e:
            logger.debug("RuntimeError%s" % repr(e.args))
            self.send_error(*e.args)

        except socket.error as e:
            if e.args[0] == EPIPE:
                self.send_fatal("DISCONNECTED", repr(e.__class__))
            else:
                logger.exception("Unknow Error")
                self.send_fatal("UNKNOW_ERROR", repr(e.__class__))

        except Exception as e:
            logger.exception("Unknow Error")
            self.send_error("UNKNOW_ERROR", repr(e.__class__))

    def simple_cmd(self, func, *args):
        try:
            self.send_text('{"status":"%s"}' % func(*args))
        except RuntimeError as e:
            self.send_error(*e.args)
        except Exception as e:
            logger.exception("Unknow Error")
            self.send_error("UNKNOW_ERROR", repr(e.__class__))

    def position(self):
        try:
            location = self.robot.position()
            self.send_text('{"status": "position", "location": "%s"}' %
                           location)
        except RuntimeError as e:
            self.send_error(*e.args)
        except Exception as e:
            logger.exception("Unknow Error")
            self.send_error("UNKNOW_ERROR", repr(e.__class__))

    def list_file(self, location=None):
        if location:
            params = location.split("/", 1)
            dirs = []
            files = []
            for is_dir, name in self.robot.list_files(*params):
                if is_dir:
                    dirs.append(name)
                else:
                    files.append(name)

            payload = {"status": "ok", "path": location, "directories": dirs,
                       "files": files}
            self.send_text(json.dumps(payload))
        else:
            self.send_text('{"status": "ok", "path": "", "directories": '
                           '["SD", "USB"], "files": []}')

    def select_file(self, file):
        entry, path = file.split("/", 1)
        self.robot.select_file(entry, path)
        self.send_text('{"status": "ok"}')

    def fileinfo(self, file):
        entry, path = file.split("/", 1)
        info, binary = self.robot.fileinfo(entry, path)
        if binary:
            self.send_text(json.dumps({
                "status": "binary", "mimetype": binary[0],
                "size": len(binary[1])
            }))
            self.send_binary(binary[1])

        info["status"] = "ok"
        self.send_text(json.dumps(info))

    def mkdir(self, file):
        if file.startswith("SD/"):
            self.simple_cmd(self.robot.mkdir, "SD", file[3:])
        else:
            self.send_text('{"status": "error", "error": "NOT_SUPPORT"}')

    def rmdir(self, file):
        if file.startswith("SD/"):
            self.simple_cmd(self.robot.rmdir, "SD", file[3:])
        else:
            self.send_text('{"status": "error", "error": "NOT_SUPPORT"}')

    def rmfile(self, file):
        if file.startswith("SD/"):
            self.simple_cmd(self.robot.rmfile, "SD", file[3:])
        else:
            self.send_text('{"status": "error", "error": "NOT_SUPPORT"}')

    def cpfile(self, args):
        if args.startswith("@"):
            source, target = args[1:].split("#")
        else:
            source, target = args.split("\x00")
        params = source.split("/", 1) + target.split("/", 1)
        self.simple_cmd(self.robot.cpfile, *params)

    def upload_file(self, mimetype, size, uploadto="#", convert='0'):
        if uploadto == "#":
            pass
        elif uploadto.startswith("SD/"):
            uploadto = "SD " + uploadto[3:]
        elif uploadto.startswith("USB/"):
            uploadto = "USB " + uploadto[4:]

        if mimetype == "text/gcode" and convert != '1':
            self.send_text('{"status":"error", "error": "FCODE_ONLY"}')
            return
        if mimetype == "text/gcode" and convert == '1':
            self.convert = io.BytesIO()
            self.uploadto = uploadto
        else:
            self.convert = None
            self.binary_sock = self.robot.begin_upload(mimetype, int(size),
                                                       uploadto=uploadto)

        self.binary_length = int(size)
        self.binary_sent = 0
        self.send_text('{"status":"continue"}')

    def update_fw(self, mimetype, size):
        self.binary_sock = self.robot.begin_upload(mimetype, int(size),
                                                   cmd="update_fw")
        self.binary_length = int(size)
        self.binary_sent = 0
        self.send_text('{"status":"continue"}')

    def maintain_eadj(self, *args):
        def callback(nav):
            self.send_text("DEBUG: %s" % nav)
        if "clean" in args:
            ret = self.robot.maintain_eadj(navigate_callback=callback,
                                           clean=True)
        else:
            ret = self.robot.maintain_eadj(navigate_callback=callback)
        self.send_text(json.dumps({
            "status": "ok", "data": ret, "error": (max(*ret) - min(*ret))
        }))

    def maintain_corh(self, *args):
        def callback(nav):
            self.send_text("DEBUG: %s" % nav)

        if len(args) > 0:
            ret = self.robot.maintain_hadj(navigate_callback=callback,
                                           manual_h=float(args[0]))
        else:
            ret = self.robot.maintain_hadj(navigate_callback=callback)

        self.send_text(json.dumps({"status": "ok", "data": ret}))

    def play_report(self):
        # TODO
        data = self.robot.report_play()
        if isinstance(data, dict):
            data["status"] = "ok"
            data["cmd"] = "report"
            self.send_text(json.dumps(data))
        else:
            self.send_text(data)

    def oneshot(self):
        images = self.robot.oneshot()
        for mime, buf in images:
            size = len(buf)
            self.send_text('{"status": "binary", "mimetype": %s, '
                           '"size": %i}' % (mime, size))
            view = memoryview(buf)
            sent = 0
            while sent < size:
                self.send_binary(view[sent:sent + 4016])
                sent += 4016
        self.send_ok()

    def scanimages(self):
        images = self.robot.scanimages()
        for mime, buf in images:
            size = len(buf)
            self.send_text('{"status": "binary", "mimetype": %s, '
                           '"size": %i}' % (mime, size))
            view = memoryview(buf)
            sent = 0
            while sent < size:
                self.send_binary(view[sent:sent + 4016])
                sent += 4016
        self.send_ok()

    def begin_raw(self):
        self.raw_sock = RawSock(self.robot.raw_mode(), self)
        self.rlist.append(self.raw_sock)
        self.send_ok()

    def on_raw_message(self, message):
        if message == "quit":
            self.rlist.remove(self.raw_sock)
            self.raw_sock = None
            self.robot.quit_raw_mode()
            self.send_ok()
        else:
            self.raw_sock.sock.send(message.encode() + b"\n")

    def g_to_f(self):
        fcode_output = io.BytesIO()
        m_GcodeToFcode = GcodeToFcode()
        # print((self.convert.getvalue().decode()))
        m_GcodeToFcode.process(self.convert.getvalue().decode().split('\n'),
                               fcode_output)
        self.convert = None
        return fcode_output.getvalue()

class RawSock(object):
    def __init__(self, sock, ws):
        self.sock = sock
        self.ws = ws

    def fileno(self):
        return self.sock.fileno()

    def on_read(self):
        buf = self.sock.recv(128)
        if buf:
            self.ws.send_text(buf.decode("ascii", "replace"))
        else:
            self.ws.rlist.remove(self)
            self.ws.send_fatal("DISCONNECTED")
<|endoftext|>


<commit_before># -*- encoding: utf-8 -*-
##############################################################################
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU 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 General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see http://www.gnu.org/licenses/.
#
##############################################################################

from openerp import models, fields

class ProductAttribute(models.Model):
    _inherit = "product.attribute"

    attr_type = fields.Selection(required=True, selection=[
        ('select', 'Select'),
        ('range', 'Range'),
        ('numeric', 'Numeric')], string="Type", default='select')

class ProductAttributeLine(models.Model):
    _inherit = "product.attribute.line"

    required = fields.Boolean('Required')
    default = fields.Many2one('product.attribute.value', 'Default')
    attr_type = fields.Selection(string='Type',
                                 related='attribute_id.attr_type')

class ProductAttributeValue(models.Model):
    _inherit = "product.attribute.value"

    attr_type = fields.Selection(string='Type',
                                 related='attribute_id.attr_type')
    numeric_value = fields.Float('Numeric Value', digits=(12, 6))
    min_range = fields.Float('Min', digits=(12, 6))
    max_range = fields.Float('Max', digits=(12, 6))
<commit_msg>[MOD]<commit_after># -*- encoding: utf-8 -*-
##############################################################################
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU 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 General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see http://www.gnu.org/licenses/.
#
##############################################################################

from openerp import models, fields

class ProductAttribute(models.Model):
    _inherit = "product.attribute"

    attr_type = fields.Selection(required=True, selection=[
        ('select', 'Select'),
        ('range', 'Range'),
        ('numeric', 'Numeric')], string="Type", default='select')

class ProductAttributeLine(models.Model):
    _inherit = "product.attribute.line"

    required = fields.Boolean('Required')
    default = fields.Many2one('product.attribute.value', 'Default')
    attr_type = fields.Selection(string='Type', store=False,
                                 related='attribute_id.attr_type')

class ProductAttributeValue(models.Model):
    _inherit = "product.attribute.value"

    attr_type = fields.Selection(string='Type',
                                 related='attribute_id.attr_type')
    numeric_value = fields.Float('Numeric Value', digits=(12, 6))
    min_range = fields.Float('Min', digits=(12, 6))
    max_range = fields.Float('Max', digits=(12, 6))
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2004-2012 Pexego Sistemas Informáticos All Rights Reserved
#    $Marta Vázquez Rodríguez$ <marta@pexego.es>
#
#    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/>.
#
##############################################################################
from openerp.osv import osv, fields
import openerp.addons.decimal_precision as dp
import time
from openerp.tools.translate import _

def rounding(f, r):
    if not r:
        return f
    return round(f / r) * r

class product_product(osv.osv):
    _inherit = 'product.product'
    _columns = {
        'cost_structure_id': fields.many2one('cost.structure',
                                             'Cost Structure'),
    }

    def action_show_product_costs(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        prod_cost_line_obj = self.pool.get('product.costs.line')
        value = prod_cost_line_obj.show_product_costs(cr, uid, ids, context)

        return value

    def action_get_product_costs(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        prod_cost_line_obj = self.pool.get('product.costs.line')
        value = prod_cost_line_obj.get_product_costs(cr, uid, ids, context)

        return value

    def action_update_product_costs(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        prod_cost = self.pool.get('product.cost')
        line = self.pool.get('product.cost.lines')
        prod = self.pool.get('product.product')
        vals = {}

        if context.get('product_id', False):
            pro = [context['product_id']]
        else:
            pro = prod.search(cr, uid, [])
        for product in prod.browse(cr, uid, pro):
            if product.cost_structure_id and product.cost_structure_id.elements:
                cost_ids = prod_cost.search(cr,
                                            uid,
                                            [('product_id', '=', product.id)],
                                            order="date desc")
                if cost_ids:
                    lines = line.search(cr,
                                        uid,
                                        [('product_cost_id', '=', cost_ids[0]),
                                         ('total', '=', True),
                                         ('inventory', '=', True)],
                                        order="sequence desc")
                    if lines:
                        line_cost = line.browse(cr, uid, lines[0])
                        vals = {'theoric_cost':
                                line_cost.theoric_cost}
        return vals

class product_cost(osv.osv):
    _name = 'product.cost'
    _rec_name = "product_id"

    _columns = {
        'product_id': fields.many2one('product.product', 'Product Cost',
                                      required=True),
        'product_cost_lines': fields.one2many('product.cost.lines',
                                              'product_cost_id', 'Costs'),
        'date': fields.datetime('Date', required=True),
        'company_id': fields.many2one('res.company', 'Company', required=True),
    }
    _defaults = {
        'company_id': lambda s, cr, uid, c:
        s.pool.get('res.company')._company_default_get(cr, uid,
                                                       'product.cost',
                                                       context=c),
    }

class product_cost_lines(osv.osv):
    _name = 'product.cost.lines'

    def _cost_percent(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for prod_cost_line in self.browse(cr, uid, ids, context):
            res[prod_cost_line.id] = {
                'tc_rc_percent': 0.0,
            }

            if prod_cost_line.real_cost:
                res[prod_cost_line.id]['tc_rc_percent'] = 100 * ((prod_cost_line.theoric_cost / prod_cost_line.real_cost) - 1)
            else:
                res[prod_cost_line.id]['tc_rc_percent'] = 100

        return res

    _columns = {
        'product_cost_id': fields.many2one('product.cost', 'Cost', required=True, ondelete='cascade'),
        'sequence': fields.integer('Sequence', required=True),
        'name': fields.char('Name', size=255, required=True),
        'theoric_cost': fields.float('Theoric Cost', required=True, digits=(16,3)),
        'real_cost': fields.float('Real Cost', required=True, digits=(16, 3)),
        'tc_rc_percent': fields.function(_cost_percent, method=True,
                                         string=_('TC vs RC (%)'), type='float',
                                         digits=(4, 2), multi='cost_percent'),
        'inventory': fields.boolean('Inventory'),
        'total': fields.boolean('Total'),
        'company_id': fields.related('product_cost_id', 'company_id',
                                     type='many2one', relation='res.company',
                                     string='Company', store=True, readonly=True),
    }
    _defaults = {
        'theoric_cost': 0.0,
        'real_cost': 0.0,
        'inventory': False,
        'total': False,
    }
<commit_msg>[FIX]product_cost_management: Campo estructura de costes property.<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2004-2012 Pexego Sistemas Informáticos All Rights Reserved
#    $Marta Vázquez Rodríguez$ <marta@pexego.es>
#
#    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/>.
#
##############################################################################
from openerp.osv import osv, fields
import openerp.addons.decimal_precision as dp
import time
from openerp.tools.translate import _

def rounding(f, r):
    if not r:
        return f
    return round(f / r) * r

class product_product(osv.osv):
    _inherit = 'product.product'
    _columns = {
        'cost_structure_id': fields.property(type='many2one',
                                             relation='cost.structure',
                                             string="Cost Structure")
    }

    def action_show_product_costs(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        prod_cost_line_obj = self.pool.get('product.costs.line')
        value = prod_cost_line_obj.show_product_costs(cr, uid, ids, context)

        return value

    def action_get_product_costs(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        prod_cost_line_obj = self.pool.get('product.costs.line')
        value = prod_cost_line_obj.get_product_costs(cr, uid, ids, context)

        return value

    def action_update_product_costs(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        prod_cost = self.pool.get('product.cost')
        line = self.pool.get('product.cost.lines')
        prod = self.pool.get('product.product')
        vals = {}

        if context.get('product_id', False):
            pro = [context['product_id']]
        else:
            pro = prod.search(cr, uid, [])
        for product in prod.browse(cr, uid, pro):
            if product.cost_structure_id and product.cost_structure_id.elements:
                cost_ids = prod_cost.search(cr,
                                            uid,
                                            [('product_id', '=', product.id)],
                                            order="date desc")
                if cost_ids:
                    lines = line.search(cr,
                                        uid,
                                        [('product_cost_id', '=', cost_ids[0]),
                                         ('total', '=', True),
                                         ('inventory', '=', True)],
                                        order="sequence desc")
                    if lines:
                        line_cost = line.browse(cr, uid, lines[0])
                        vals = {'theoric_cost':
                                line_cost.theoric_cost}
        return vals

class product_cost(osv.osv):
    _name = 'product.cost'
    _rec_name = "product_id"

    _columns = {
        'product_id': fields.many2one('product.product', 'Product Cost',
                                      required=True),
        'product_cost_lines': fields.one2many('product.cost.lines',
                                              'product_cost_id', 'Costs'),
        'date': fields.datetime('Date', required=True),
        'company_id': fields.many2one('res.company', 'Company', required=True),
    }
    _defaults = {
        'company_id': lambda s, cr, uid, c:
        s.pool.get('res.company')._company_default_get(cr, uid,
                                                       'product.cost',
                                                       context=c),
    }

class product_cost_lines(osv.osv):
    _name = 'product.cost.lines'

    def _cost_percent(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for prod_cost_line in self.browse(cr, uid, ids, context):
            res[prod_cost_line.id] = {
                'tc_rc_percent': 0.0,
            }

            if prod_cost_line.real_cost:
                res[prod_cost_line.id]['tc_rc_percent'] = 100 * ((prod_cost_line.theoric_cost / prod_cost_line.real_cost) - 1)
            else:
                res[prod_cost_line.id]['tc_rc_percent'] = 100

        return res

    _columns = {
        'product_cost_id': fields.many2one('product.cost', 'Cost', required=True, ondelete='cascade'),
        'sequence': fields.integer('Sequence', required=True),
        'name': fields.char('Name', size=255, required=True),
        'theoric_cost': fields.float('Theoric Cost', required=True, digits=(16,3)),
        'real_cost': fields.float('Real Cost', required=True, digits=(16, 3)),
        'tc_rc_percent': fields.function(_cost_percent, method=True,
                                         string=_('TC vs RC (%)'), type='float',
                                         digits=(4, 2), multi='cost_percent'),
        'inventory': fields.boolean('Inventory'),
        'total': fields.boolean('Total'),
        'company_id': fields.related('product_cost_id', 'company_id',
                                     type='many2one', relation='res.company',
                                     string='Company', store=True, readonly=True),
    }
    _defaults = {
        'theoric_cost': 0.0,
        'real_cost': 0.0,
        'inventory': False,
        'total': False,
    }
<|endoftext|>


<commit_before># -*- coding: utf8 -*-
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import logging

from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import tables as horizon_tables
from horizon.utils import memoized
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.images.images import views

from tuskar_ui import api as tuskar_api
from tuskar_ui.infrastructure.images import forms
from tuskar_ui.infrastructure.images import tables
import tuskar_ui.infrastructure.views as infrastructure_views
from tuskar_ui.utils import utils

LOG = logging.getLogger(__name__)

class IndexView(infrastructure_views.ItemCountMixin,
                horizon_tables.DataTableView):
    table_class = tables.ImagesTable
    template_name = "infrastructure/images/index.html"

    @memoized.memoized_method
    def get_data(self):
        images = []
        filters = self.get_filters()

        sort_dir = 'desc'
        try:
            images, self._more, self._prev = api.glance.image_list_detailed(
                self.request,
                paginate=False,
                filters=filters,
                sort_dir=sort_dir)
            images = [image for image in images
                      if utils.check_image_type(image,
                                                'overcloud provisioning')]
        except Exception:
            msg = _('Unable to retrieve image list.')
            exceptions.handle(self.request, msg)

        plan = tuskar_api.tuskar.Plan.get_the_plan(self.request)
        for image in images:
            image.role = tuskar_api.tuskar.Role.get_by_image(
                self.request, plan, image)

        return images

    def get_filters(self):
        filters = {'is_public': None}
        filter_field = self.table.get_filter_field()
        filter_string = self.table.get_filter_string()
        filter_action = self.table._meta._filter_action
        if filter_field and filter_string and (
                filter_action.is_api_filter(filter_field)):
            if filter_field in ['size_min', 'size_max']:
                invalid_msg = ('API query is not valid and is ignored: %s=%s'
                               % (filter_field, filter_string))
                try:
                    filter_string = long(float(filter_string) * (1024 ** 2))
                    if filter_string >= 0:
                        filters[filter_field] = filter_string
                    else:
                        LOG.warning(invalid_msg)
                except ValueError:
                    LOG.warning(invalid_msg)
            else:
                filters[filter_field] = filter_string
        return filters

class UpdateView(views.UpdateView):
    template_name = 'infrastructure/images/update.html'
    form_class = forms.UpdateImageForm
    success_url = reverse_lazy('horizon:infrastructure:images:index')
    submit_label = _("Update Image")

    @memoized.memoized_method
    def get_object(self):
        try:
            return api.glance.image_get(self.request, self.kwargs['image_id'])
        except Exception:
            msg = _('Unable to retrieve image.')
            url = reverse_lazy('horizon:infrastructure:images:index')
            exceptions.handle(self.request, msg, redirect=url)
<commit_msg>Override submit_url on images.UpdateView<commit_after># -*- coding: utf8 -*-
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import logging

from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import tables as horizon_tables
from horizon.utils import memoized
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.images.images import views

from tuskar_ui import api as tuskar_api
from tuskar_ui.infrastructure.images import forms
from tuskar_ui.infrastructure.images import tables
import tuskar_ui.infrastructure.views as infrastructure_views
from tuskar_ui.utils import utils

LOG = logging.getLogger(__name__)

class IndexView(infrastructure_views.ItemCountMixin,
                horizon_tables.DataTableView):
    table_class = tables.ImagesTable
    template_name = "infrastructure/images/index.html"

    @memoized.memoized_method
    def get_data(self):
        images = []
        filters = self.get_filters()

        sort_dir = 'desc'
        try:
            images, self._more, self._prev = api.glance.image_list_detailed(
                self.request,
                paginate=False,
                filters=filters,
                sort_dir=sort_dir)
            images = [image for image in images
                      if utils.check_image_type(image,
                                                'overcloud provisioning')]
        except Exception:
            msg = _('Unable to retrieve image list.')
            exceptions.handle(self.request, msg)

        plan = tuskar_api.tuskar.Plan.get_the_plan(self.request)
        for image in images:
            image.role = tuskar_api.tuskar.Role.get_by_image(
                self.request, plan, image)

        return images

    def get_filters(self):
        filters = {'is_public': None}
        filter_field = self.table.get_filter_field()
        filter_string = self.table.get_filter_string()
        filter_action = self.table._meta._filter_action
        if filter_field and filter_string and (
                filter_action.is_api_filter(filter_field)):
            if filter_field in ['size_min', 'size_max']:
                invalid_msg = ('API query is not valid and is ignored: %s=%s'
                               % (filter_field, filter_string))
                try:
                    filter_string = long(float(filter_string) * (1024 ** 2))
                    if filter_string >= 0:
                        filters[filter_field] = filter_string
                    else:
                        LOG.warning(invalid_msg)
                except ValueError:
                    LOG.warning(invalid_msg)
            else:
                filters[filter_field] = filter_string
        return filters

class UpdateView(views.UpdateView):
    template_name = 'infrastructure/images/update.html'
    form_class = forms.UpdateImageForm
    success_url = reverse_lazy('horizon:infrastructure:images:index')
    submit_url = "horizon:infrastructure:images:update"
    submit_label = _("Update Image")

    @memoized.memoized_method
    def get_object(self):
        try:
            return api.glance.image_get(self.request, self.kwargs['image_id'])
        except Exception:
            msg = _('Unable to retrieve image.')
            url = reverse_lazy('horizon:infrastructure:images:index')
            exceptions.handle(self.request, msg, redirect=url)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
"""
Head-Motion Estimation and Correction (HMC) of BOLD images
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. autofunction:: init_bold_hmc_wf

"""

from nipype.pipeline import engine as pe
from nipype.interfaces import utility as niu, fsl
from niworkflows.interfaces import NormalizeMotionParams
from ...engine import Workflow
from ...interfaces import MCFLIRT2ITK

DEFAULT_MEMORY_MIN_GB = 0.01

# pylint: disable=R0914
def init_bold_hmc_wf(mem_gb, omp_nthreads, name='bold_hmc_wf'):
    """
    This workflow estimates the motion parameters to perform
    :abbr:`HMC (head motion correction)` over the input
    :abbr:`BOLD (blood-oxygen-level dependent)` image.

    .. workflow::
        :graph2use: orig
        :simple_form: yes

        from fmriprep.workflows.bold import init_bold_hmc_wf
        wf = init_bold_hmc_wf(
            mem_gb=3,
            omp_nthreads=1)

    **Parameters**

        mem_gb : float
            Size of BOLD file in GB
        omp_nthreads : int
            Maximum number of threads an individual process may use
        name : str
            Name of workflow (default: ``bold_hmc_wf``)

    **Inputs**

        bold_file
            BOLD series NIfTI file
        raw_ref_image
            Reference image to which BOLD series is motion corrected

    **Outputs**

        xforms
            ITKTransform file aligning each volume to ``ref_image``
        movpar_file
            MCFLIRT motion parameters, normalized to SPM format (X, Y, Z, Rx, Ry, Rz)

    """
    workflow = Workflow(name=name)
    workflow.__desc__ = """\
Head-motion parameters with respect to the BOLD reference
(transformation matrices, and six corresponding rotation and translation
parameters) are estimated before any spatiotemporal filtering using
`mcflirt` [FSL {fsl_ver}, @mcflirt].
""".format(fsl_ver=fsl.Info().version() or '<ver>')

    inputnode = pe.Node(niu.IdentityInterface(fields=['bold_file', 'raw_ref_image']),
                        name='inputnode')
    outputnode = pe.Node(
        niu.IdentityInterface(fields=['xforms', 'movpar_file']),
        name='outputnode')

    # Head motion correction (hmc)
    mcflirt = pe.Node(fsl.MCFLIRT(save_mats=True, save_plots=True, args="sdfsdf"),
                      name='mcflirt', mem_gb=mem_gb * 3)

    fsl2itk = pe.Node(MCFLIRT2ITK(), name='fsl2itk',
                      mem_gb=0.05, n_procs=omp_nthreads)

    normalize_motion = pe.Node(NormalizeMotionParams(format='FSL'),
                               name="normalize_motion",
                               mem_gb=DEFAULT_MEMORY_MIN_GB)

    workflow.connect([
        (inputnode, mcflirt, [('raw_ref_image', 'ref_file'),
                              ('bold_file', 'in_file')]),
        (inputnode, fsl2itk, [('raw_ref_image', 'in_source'),
                              ('raw_ref_image', 'in_reference')]),
        (mcflirt, fsl2itk, [('mat_file', 'in_files')]),
        (mcflirt, normalize_motion, [('par_file', 'in_file')]),
        (fsl2itk, outputnode, [('out_file', 'xforms')]),
        (normalize_motion, outputnode, [('out_file', 'movpar_file')]),
    ])

    return workflow
<commit_msg>remove test "fail"<commit_after># -*- coding: utf-8 -*-
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
"""
Head-Motion Estimation and Correction (HMC) of BOLD images
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. autofunction:: init_bold_hmc_wf

"""

from nipype.pipeline import engine as pe
from nipype.interfaces import utility as niu, fsl
from niworkflows.interfaces import NormalizeMotionParams
from ...engine import Workflow
from ...interfaces import MCFLIRT2ITK

DEFAULT_MEMORY_MIN_GB = 0.01

# pylint: disable=R0914
def init_bold_hmc_wf(mem_gb, omp_nthreads, name='bold_hmc_wf'):
    """
    This workflow estimates the motion parameters to perform
    :abbr:`HMC (head motion correction)` over the input
    :abbr:`BOLD (blood-oxygen-level dependent)` image.

    .. workflow::
        :graph2use: orig
        :simple_form: yes

        from fmriprep.workflows.bold import init_bold_hmc_wf
        wf = init_bold_hmc_wf(
            mem_gb=3,
            omp_nthreads=1)

    **Parameters**

        mem_gb : float
            Size of BOLD file in GB
        omp_nthreads : int
            Maximum number of threads an individual process may use
        name : str
            Name of workflow (default: ``bold_hmc_wf``)

    **Inputs**

        bold_file
            BOLD series NIfTI file
        raw_ref_image
            Reference image to which BOLD series is motion corrected

    **Outputs**

        xforms
            ITKTransform file aligning each volume to ``ref_image``
        movpar_file
            MCFLIRT motion parameters, normalized to SPM format (X, Y, Z, Rx, Ry, Rz)

    """
    workflow = Workflow(name=name)
    workflow.__desc__ = """\
Head-motion parameters with respect to the BOLD reference
(transformation matrices, and six corresponding rotation and translation
parameters) are estimated before any spatiotemporal filtering using
`mcflirt` [FSL {fsl_ver}, @mcflirt].
""".format(fsl_ver=fsl.Info().version() or '<ver>')

    inputnode = pe.Node(niu.IdentityInterface(fields=['bold_file', 'raw_ref_image']),
                        name='inputnode')
    outputnode = pe.Node(
        niu.IdentityInterface(fields=['xforms', 'movpar_file']),
        name='outputnode')

    # Head motion correction (hmc)
    mcflirt = pe.Node(fsl.MCFLIRT(save_mats=True, save_plots=True),
                      name='mcflirt', mem_gb=mem_gb * 3)

    fsl2itk = pe.Node(MCFLIRT2ITK(), name='fsl2itk',
                      mem_gb=0.05, n_procs=omp_nthreads)

    normalize_motion = pe.Node(NormalizeMotionParams(format='FSL'),
                               name="normalize_motion",
                               mem_gb=DEFAULT_MEMORY_MIN_GB)

    workflow.connect([
        (inputnode, mcflirt, [('raw_ref_image', 'ref_file'),
                              ('bold_file', 'in_file')]),
        (inputnode, fsl2itk, [('raw_ref_image', 'in_source'),
                              ('raw_ref_image', 'in_reference')]),
        (mcflirt, fsl2itk, [('mat_file', 'in_files')]),
        (mcflirt, normalize_motion, [('par_file', 'in_file')]),
        (fsl2itk, outputnode, [('out_file', 'xforms')]),
        (normalize_motion, outputnode, [('out_file', 'movpar_file')]),
    ])

    return workflow
<|endoftext|>