<commit_before>"""EcoData Retriever Tools

This module contains miscellaneous classes and functions used in Retriever
scripts.

"""

import difflib
import os
import sys
import warnings
import unittest
import shutil
import os
from decimal import Decimal
from hashlib import md5
from retriever import HOME_DIR
from retriever.lib.models import *

warnings.filterwarnings("ignore")

TEST_ENGINES = dict()

def name_matches(scripts, arg):
    matches = []
    for script in scripts:
        if arg.lower() == script.shortname.lower(): return [script]
        max_ratio = max([difflib.SequenceMatcher(None, arg.lower(), factor).ratio() for factor in (script.shortname.lower(), script.name.lower(), script.filename.lower())] +
                        [difflib.SequenceMatcher(None, arg.lower(), factor).ratio() for factor in [tag.strip().lower() for tagset in script.tags for tag in tagset]]
                        )
        if arg.lower() == 'all': max_ratio = 1.0
        matches.append((script, max_ratio))
    matches = [m for m in sorted(matches, key=lambda m: m[1], reverse=True) if m[1] > 0.6]
    return [match[0] for match in matches]

def getmd5(lines):
    """Get MD5 value of a set of lines."""
    sum = md5()
    for line in lines:
        sum.update(line)
    return sum.hexdigest()

def checkagainstfile(lines, filename):
    """Checks a set of lines against a file, and prints all lines that don't
    match."""
    TEST_DATA_LOCATION = "test_data"

    testfile = open(os.path.join(TEST_DATA_LOCATION, filename), 'rb')
    i = 0
    for line in lines:
        i += 1
        print i
        line2 = testfile.readline()
        if line != line2:
            print i
            print "LINE1: " + line
            print "LINE2: " + line2
            values1 = line.split(',')
            values2 = line2.split(',')
            for i in range(0, len(values1)):
                if values1[i] != values2[i]:
                    print str(i) + ": " + values1[i] + ", " + values2[i]
    testfile.close()

def final_cleanup(engine):
    """Perform final cleanup operations after all scripts have run."""
    pass

config_path = os.path.join(HOME_DIR, 'connections.config')

def get_saved_connection(engine_name):
    """Given the name of an engine, returns the stored connection for that engine
    from connections.config."""
    parameters = {}
    if os.path.isfile(config_path):
        config = open(config_path, "rb")
        for line in config:
            values = line.rstrip('\n').split(',')
            if values[0] == engine_name:
                try:
                    parameters = eval(','.join(values[1:]))
                except:
                    pass
    return parameters

def save_connection(engine_name, values_dict):
    """Saves connection information for an engine in connections.config."""
    lines = []
    if os.path.isfile(config_path):
        config = open(config_path, "rb")
        for line in config:
            if line.split(',')[0] != engine_name:
                lines.append('\n' + line.rstrip('\n'))
        config.close()
        os.remove(config_path)
        config = open(config_path, "wb")
    else:
        config = open(config_path, "wb")
    if "file" in values_dict:
        values_dict["file"] = os.path.abspath(values_dict["file"])
    config.write(engine_name + "," + str(values_dict))
    for line in lines:
        config.write(line)
    config.close()

def get_default_connection():
    """Gets the first (most recently used) stored connection from
    connections.config."""
    if os.path.isfile(config_path):
        config = open(config_path, "rb")
        default_connection = config.readline().split(",")[0]
        config.close()
        return default_connection
    else:
        return None

def choose_engine(opts, choice=True):
    """Prompts the user to select a database engine"""
    from retriever.engines import engine_list

    if "engine" in opts.keys():
        enginename = opts["engine"]
    elif opts["command"] == "download":
        enginename = "download"
    else:
        if not choice: return None
        print "Choose a database engine:"
        for engine in engine_list:
            if engine.abbreviation:
                abbreviation = "(" + engine.abbreviation + ") "
            else:
                abbreviation = ""
            print "    " + abbreviation + engine.name
        enginename = raw_input(": ")
    enginename = enginename.lower()

    engine = Engine()
    if not enginename:
        engine = engine_list[0]
    else:
        for thisengine in engine_list:
            if (enginename == thisengine.name.lower()
                              or thisengine.abbreviation
                              and enginename == thisengine.abbreviation):
                engine = thisengine

    engine.opts = opts
    return engine

def reset_retriever(scope):
    """Remove stored information on scripts, data, and connections"""

    warning_messages= {'all': "This will remove existing scripts, cached data, and information on database connections. Specifically it will remove the scripts and raw_data folders and the connections.config file in {}. Do you want to proceed? (y/N)\n",
                       'scripts': "This will remove existing scripts. Specifically it will remove the scripts folder in {}. Do you want to proceed? (y/N)\n",
                       'data': "This will remove raw data cached by the Retriever. Specifically it will remove the raw_data folder in {}. Do you want to proceed? (y/N)\n",
                       'connections': "This will remove stored information on database connections. Specifically it will remove the connections.config file in {}. Do you want to proceed? (y/N)\n"
    }

    warn_msg = warning_messages[scope].format(HOME_DIR)
    confirm = raw_input(warn_msg)
    while not (confirm.lower() in ['y', 'n', '']):
        print("Please enter either y or n.")
        confirm = raw_input()
    if confirm.lower() == 'y':
        if scope in ['data', 'all']:
            shutil.rmtree(os.path.join(HOME_DIR, 'raw_data'))
        if scope in ['scripts', 'all']:
            shutil.rmtree(os.path.join(HOME_DIR, 'scripts'))
        if scope in ['connections', 'all']:
            try:
                os.remove(os.path.join(HOME_DIR, 'connections.config'))
            except:
                pass
<commit_msg>Remove unused checkagainstfile function<commit_after>"""EcoData Retriever Tools

This module contains miscellaneous classes and functions used in Retriever
scripts.

"""

import difflib
import os
import sys
import warnings
import unittest
import shutil
import os
from decimal import Decimal
from hashlib import md5
from retriever import HOME_DIR
from retriever.lib.models import *

warnings.filterwarnings("ignore")

TEST_ENGINES = dict()

def name_matches(scripts, arg):
    matches = []
    for script in scripts:
        if arg.lower() == script.shortname.lower(): return [script]
        max_ratio = max([difflib.SequenceMatcher(None, arg.lower(), factor).ratio() for factor in (script.shortname.lower(), script.name.lower(), script.filename.lower())] +
                        [difflib.SequenceMatcher(None, arg.lower(), factor).ratio() for factor in [tag.strip().lower() for tagset in script.tags for tag in tagset]]
                        )
        if arg.lower() == 'all': max_ratio = 1.0
        matches.append((script, max_ratio))
    matches = [m for m in sorted(matches, key=lambda m: m[1], reverse=True) if m[1] > 0.6]
    return [match[0] for match in matches]

def getmd5(lines):
    """Get MD5 value of a set of lines."""
    sum = md5()
    for line in lines:
        sum.update(line)
    return sum.hexdigest()

def final_cleanup(engine):
    """Perform final cleanup operations after all scripts have run."""
    pass

config_path = os.path.join(HOME_DIR, 'connections.config')

def get_saved_connection(engine_name):
    """Given the name of an engine, returns the stored connection for that engine
    from connections.config."""
    parameters = {}
    if os.path.isfile(config_path):
        config = open(config_path, "rb")
        for line in config:
            values = line.rstrip('\n').split(',')
            if values[0] == engine_name:
                try:
                    parameters = eval(','.join(values[1:]))
                except:
                    pass
    return parameters

def save_connection(engine_name, values_dict):
    """Saves connection information for an engine in connections.config."""
    lines = []
    if os.path.isfile(config_path):
        config = open(config_path, "rb")
        for line in config:
            if line.split(',')[0] != engine_name:
                lines.append('\n' + line.rstrip('\n'))
        config.close()
        os.remove(config_path)
        config = open(config_path, "wb")
    else:
        config = open(config_path, "wb")
    if "file" in values_dict:
        values_dict["file"] = os.path.abspath(values_dict["file"])
    config.write(engine_name + "," + str(values_dict))
    for line in lines:
        config.write(line)
    config.close()

def get_default_connection():
    """Gets the first (most recently used) stored connection from
    connections.config."""
    if os.path.isfile(config_path):
        config = open(config_path, "rb")
        default_connection = config.readline().split(",")[0]
        config.close()
        return default_connection
    else:
        return None

def choose_engine(opts, choice=True):
    """Prompts the user to select a database engine"""
    from retriever.engines import engine_list

    if "engine" in opts.keys():
        enginename = opts["engine"]
    elif opts["command"] == "download":
        enginename = "download"
    else:
        if not choice: return None
        print "Choose a database engine:"
        for engine in engine_list:
            if engine.abbreviation:
                abbreviation = "(" + engine.abbreviation + ") "
            else:
                abbreviation = ""
            print "    " + abbreviation + engine.name
        enginename = raw_input(": ")
    enginename = enginename.lower()

    engine = Engine()
    if not enginename:
        engine = engine_list[0]
    else:
        for thisengine in engine_list:
            if (enginename == thisengine.name.lower()
                              or thisengine.abbreviation
                              and enginename == thisengine.abbreviation):
                engine = thisengine

    engine.opts = opts
    return engine

def reset_retriever(scope):
    """Remove stored information on scripts, data, and connections"""

    warning_messages= {'all': "This will remove existing scripts, cached data, and information on database connections. Specifically it will remove the scripts and raw_data folders and the connections.config file in {}. Do you want to proceed? (y/N)\n",
                       'scripts': "This will remove existing scripts. Specifically it will remove the scripts folder in {}. Do you want to proceed? (y/N)\n",
                       'data': "This will remove raw data cached by the Retriever. Specifically it will remove the raw_data folder in {}. Do you want to proceed? (y/N)\n",
                       'connections': "This will remove stored information on database connections. Specifically it will remove the connections.config file in {}. Do you want to proceed? (y/N)\n"
    }

    warn_msg = warning_messages[scope].format(HOME_DIR)
    confirm = raw_input(warn_msg)
    while not (confirm.lower() in ['y', 'n', '']):
        print("Please enter either y or n.")
        confirm = raw_input()
    if confirm.lower() == 'y':
        if scope in ['data', 'all']:
            shutil.rmtree(os.path.join(HOME_DIR, 'raw_data'))
        if scope in ['scripts', 'all']:
            shutil.rmtree(os.path.join(HOME_DIR, 'scripts'))
        if scope in ['connections', 'all']:
            try:
                os.remove(os.path.join(HOME_DIR, 'connections.config'))
            except:
                pass
<|endoftext|>


<commit_before>"""
Read UrQMD output files.
"""

import fileinput
import math

from .particle import Particle

# urqmd particle lines are 435 chars long [including the two chars of '\n']
PARTICLE_LINE_LENGTH = 435

# dictionary to convert from urqmd ityp and 2*I3 to monte carlo ID
# adapted from ityp2pdg.f in the urqmd source
# structure is ityp:{2i3:mcid}
PARTICLE_DICT = {
    # nucleons
    1: {-1: 2112, 1: 2212},
    # N*
    2: {-1: 12112, 1: 12212},
    3: {-1: 1214, 1: 2124},
    4: {-1: 22112, 1: 22212},
    5: {-1: 32112, 1: 32212},
    6: {-1: 2116, 1: 2216},
    7: {-1: 12116, 1: 12216},
    8: {-1: 21214, 1: 22124},
    9: {-1: 42112, 1: 42212},
    10: {-1: 31214, 1: 32124},
    14: {-1: 1218, 1: 2128},
    # Delta
    17: {-3: 1114, -1: 2114, 1: 2214, 3: 2224},
    18: {-3: 31114, -1: 32114, 1: 32214, 3: 32224},
    19: {-3: 1112, -1: 1212, 1: 2122, 3: 2222},
    20: {-3: 11114, -1: 12114, 1: 12214, 3: 12224},
    21: {-3: 11112, -1: 11212, 1: 12122, 3: 12222},
    22: {-3: 1116, -1: 1216, 1: 2126, 3: 2226},
    23: {-3: 21112, -1: 21212, 1: 22122, 3: 22222},
    24: {-3: 21114, -1: 22114, 1: 22214, 3: 22224},
    25: {-3: 11116, -1: 11216, 1: 12126, 3: 12226},
    26: {-3: 1118, -1: 2118, 1: 2218, 3: 2228},
    # Lambda
    27: {0: 3122},
    28: {0: 13122},
    29: {0: 3124},
    30: {0: 23122},
    31: {0: 33122},
    32: {0: 13124},
    33: {0: 43122},
    34: {0: 53122},
    35: {0: 3126},
    36: {0: 13126},
    37: {0: 23124},
    38: {0: 3128},
    39: {0: 23126},
    # Sigma
    40: {-2: 3112, 0: 3212, 2: 3222},
    41: {-2: 3114, 0: 3214, 2: 3224},
    42: {-2: 13112, 0: 13212, 2: 13222},
    43: {-2: 13114, 0: 13214, 2: 13224},
    44: {-2: 23112, 0: 23212, 2: 23222},
    45: {-2: 3116, 0: 3216, 2: 3226},
    46: {-2: 13116, 0: 13216, 2: 13226},
    47: {-2: 23114, 0: 23214, 2: 23224},
    48: {-2: 3118, 0: 3218, 2: 3228},
    # Xi
    49: {-1: 3312, 1: 3322},
    50: {-1: 3314, 1: 3324},
    52: {-1: 13314, 1: 13324},
    # Omega
    55: {0: 3334},
    # gamma
    100: {0: 22},
    # pion
    101: {-2: -211, 0: 111, 2: 211},
    # eta
    102: {0: 221},
    # omega
    103: {0: 223},
    # rho
    104: {-2: -213, 0: 113, 2: 213},
    # f0(980)
    105: {0: 10221},
    # kaon
    106: {-1: 311, 1: 321},
    # eta
    107: {0: 331},
    # k*(892)
    108: {-1: 313, 1: 323},
    # phi
    109: {0: 333},
    # k0*(1430)
    110: {-1: 10313, 1: 10323},
    # a0(980)
    111: {-2: -10211, 0: 10111, 2: 10211},
    # f0(1370)
    112: {0: 20221},
    # k1(1270)
    113: {-1: 10313, 1: 10323},
    # a1(1260)
    114: {-2: -20213, 0: 20113, 2: 20213},
    # f1(1285)
    115: {0: 20223},
    # f1'(1510)
    116: {0: 40223},
    # k2*(1430)
    117: {-1: 315, 1: 325},
    # a2(1329)
    118: {-2: -215, 0: 115, 2: 215},
    # f2(1270)
    119: {0: 225},
    # f2'(1525)
    120: {0: 335},
    # k1(1400)
    121: {-1: 20313, 1: 20323},
    # b1
    122: {-2: -10213, 0: 10113, 2: 10213},
    # h1
    123: {0: 10223},
    # K* (1410)
    125: {-1: 30313, 1: 30323},
    # rho (1450)
    126: {-2: -40213, 0: 40113, 2: 40213},
    # omega (1420)
    127: {0: 50223},
    # phi(1680)
    128: {0: 10333},
    # k*(1680)
    129: {-1: 40313, 1: 40323},
    # rho(1700)
    130: {-2: -30213, 0: 30113, 2: 30213},
    # omega(1600)
    131: {0: 60223},
    # phi(1850)
    132: {0: 337}
}

def _ffloat(x):
    # convert a fortran double to a python float
    # python does not understand 'D' in fortran doubles so replace it with 'E'

    # must handle bytes / string cases separately
    if isinstance(x,bytes):
        return float(x.replace(b'D',b'E'))
    else:
        return float(x.replace('D','E'))

def particles_from_files(files=None,sqrt=math.sqrt,atan2=math.atan2,log=math.log):
    """
    Generate Particle objects from UrQMD files.

    Arguments
    ---------
    files -- list of filenames to read, passed directly to fileinput

    Yields
    ------
    Particle() or None

    Where None is a separator between events.

    """

    # use this boolean to keep track of event headers
    # files should begin with a header
    header = True

    with fileinput.input(files=files,openhook=fileinput.hook_compressed) as f:
        for l in f:
            # determine if this is a particle line via its length

            if len(l) == PARTICLE_LINE_LENGTH:
                # this is a particle line

                if header:
                    # switch out of header mode
                    header = False

                # extract necessary values

                # loops are not efficient for only a few calls
                # neither is map()
                # faster to manually call the functions
                # faster to extract values separately than e.g. l.split()

                # momenta
                px = _ffloat(l[121:144])
                py = _ffloat(l[145:168])
                pz = _ffloat(l[169:192])

                # UrQMD ityp and 2*I3
                ityp = int(l[218:221])
                iso = int(l[222:224])

                # determine Monte Carlo ID
                # for antiparticles (ityp<0), negate 2*I3 and MCID
                # checked for speed:  faster than using int(copysign(...))
                sign = 1 if ityp > 0 else -1
                ID = sign * PARTICLE_DICT[abs(ityp)][sign*iso]

                # transverse momentum
                pT = sqrt(px*px + py*py)

                # azimuthal angle
                phi = atan2(py,px)

                # rapidity
                pmag = sqrt(px*px + py*py + pz*pz)
                eta = 0.5*log((pmag+pz)/max(pmag-pz,1e-10))   # avoid division by zero

                # yield the Particle
                yield Particle(ID,pT,phi,eta)

            else:
                # this is a header line

                if not header:
                    # switch to header mode
                    header = True
                    # yield None to separate events
                    yield
<commit_msg>Edit urqmd reader docstring.<commit_after>"""
Read UrQMD output files.
"""

import fileinput
import math

from .particle import Particle

# urqmd particle lines are 435 chars long [including the two chars of '\n']
PARTICLE_LINE_LENGTH = 435

# dictionary to convert from urqmd ityp and 2*I3 to monte carlo ID
# adapted from ityp2pdg.f in the urqmd source
# structure is ityp:{2i3:mcid}
PARTICLE_DICT = {
    # nucleons
    1: {-1: 2112, 1: 2212},
    # N*
    2: {-1: 12112, 1: 12212},
    3: {-1: 1214, 1: 2124},
    4: {-1: 22112, 1: 22212},
    5: {-1: 32112, 1: 32212},
    6: {-1: 2116, 1: 2216},
    7: {-1: 12116, 1: 12216},
    8: {-1: 21214, 1: 22124},
    9: {-1: 42112, 1: 42212},
    10: {-1: 31214, 1: 32124},
    14: {-1: 1218, 1: 2128},
    # Delta
    17: {-3: 1114, -1: 2114, 1: 2214, 3: 2224},
    18: {-3: 31114, -1: 32114, 1: 32214, 3: 32224},
    19: {-3: 1112, -1: 1212, 1: 2122, 3: 2222},
    20: {-3: 11114, -1: 12114, 1: 12214, 3: 12224},
    21: {-3: 11112, -1: 11212, 1: 12122, 3: 12222},
    22: {-3: 1116, -1: 1216, 1: 2126, 3: 2226},
    23: {-3: 21112, -1: 21212, 1: 22122, 3: 22222},
    24: {-3: 21114, -1: 22114, 1: 22214, 3: 22224},
    25: {-3: 11116, -1: 11216, 1: 12126, 3: 12226},
    26: {-3: 1118, -1: 2118, 1: 2218, 3: 2228},
    # Lambda
    27: {0: 3122},
    28: {0: 13122},
    29: {0: 3124},
    30: {0: 23122},
    31: {0: 33122},
    32: {0: 13124},
    33: {0: 43122},
    34: {0: 53122},
    35: {0: 3126},
    36: {0: 13126},
    37: {0: 23124},
    38: {0: 3128},
    39: {0: 23126},
    # Sigma
    40: {-2: 3112, 0: 3212, 2: 3222},
    41: {-2: 3114, 0: 3214, 2: 3224},
    42: {-2: 13112, 0: 13212, 2: 13222},
    43: {-2: 13114, 0: 13214, 2: 13224},
    44: {-2: 23112, 0: 23212, 2: 23222},
    45: {-2: 3116, 0: 3216, 2: 3226},
    46: {-2: 13116, 0: 13216, 2: 13226},
    47: {-2: 23114, 0: 23214, 2: 23224},
    48: {-2: 3118, 0: 3218, 2: 3228},
    # Xi
    49: {-1: 3312, 1: 3322},
    50: {-1: 3314, 1: 3324},
    52: {-1: 13314, 1: 13324},
    # Omega
    55: {0: 3334},
    # gamma
    100: {0: 22},
    # pion
    101: {-2: -211, 0: 111, 2: 211},
    # eta
    102: {0: 221},
    # omega
    103: {0: 223},
    # rho
    104: {-2: -213, 0: 113, 2: 213},
    # f0(980)
    105: {0: 10221},
    # kaon
    106: {-1: 311, 1: 321},
    # eta
    107: {0: 331},
    # k*(892)
    108: {-1: 313, 1: 323},
    # phi
    109: {0: 333},
    # k0*(1430)
    110: {-1: 10313, 1: 10323},
    # a0(980)
    111: {-2: -10211, 0: 10111, 2: 10211},
    # f0(1370)
    112: {0: 20221},
    # k1(1270)
    113: {-1: 10313, 1: 10323},
    # a1(1260)
    114: {-2: -20213, 0: 20113, 2: 20213},
    # f1(1285)
    115: {0: 20223},
    # f1'(1510)
    116: {0: 40223},
    # k2*(1430)
    117: {-1: 315, 1: 325},
    # a2(1329)
    118: {-2: -215, 0: 115, 2: 215},
    # f2(1270)
    119: {0: 225},
    # f2'(1525)
    120: {0: 335},
    # k1(1400)
    121: {-1: 20313, 1: 20323},
    # b1
    122: {-2: -10213, 0: 10113, 2: 10213},
    # h1
    123: {0: 10223},
    # K* (1410)
    125: {-1: 30313, 1: 30323},
    # rho (1450)
    126: {-2: -40213, 0: 40113, 2: 40213},
    # omega (1420)
    127: {0: 50223},
    # phi(1680)
    128: {0: 10333},
    # k*(1680)
    129: {-1: 40313, 1: 40323},
    # rho(1700)
    130: {-2: -30213, 0: 30113, 2: 30213},
    # omega(1600)
    131: {0: 60223},
    # phi(1850)
    132: {0: 337}
}

def _ffloat(x):
    # convert a fortran double to a python float
    # python does not understand 'D' in fortran doubles so replace it with 'E'

    # must handle bytes / string cases separately
    if isinstance(x,bytes):
        return float(x.replace(b'D',b'E'))
    else:
        return float(x.replace('D','E'))

def particles_from_files(files=None,sqrt=math.sqrt,atan2=math.atan2,log=math.log):
    """
    Generate Particle objects from UrQMD files.  Yield None to separate events.

    Arguments
    ---------
    files -- list of filenames to read, passed directly to fileinput

    Yields
    ------
    Particle() or None

    """

    # use this boolean to keep track of event headers
    # files should begin with a header
    header = True

    with fileinput.input(files=files,openhook=fileinput.hook_compressed) as f:
        for l in f:
            # determine if this is a particle line via its length

            if len(l) == PARTICLE_LINE_LENGTH:
                # this is a particle line

                if header:
                    # switch out of header mode
                    header = False

                # extract necessary values

                # loops are not efficient for only a few calls
                # neither is map()
                # faster to manually call the functions
                # faster to extract values separately than e.g. l.split()

                # momenta
                px = _ffloat(l[121:144])
                py = _ffloat(l[145:168])
                pz = _ffloat(l[169:192])

                # UrQMD ityp and 2*I3
                ityp = int(l[218:221])
                iso = int(l[222:224])

                # determine Monte Carlo ID
                # for antiparticles (ityp<0), negate 2*I3 and MCID
                # checked for speed:  faster than using int(copysign(...))
                sign = 1 if ityp > 0 else -1
                ID = sign * PARTICLE_DICT[abs(ityp)][sign*iso]

                # transverse momentum
                pT = sqrt(px*px + py*py)

                # azimuthal angle
                phi = atan2(py,px)

                # rapidity
                pmag = sqrt(px*px + py*py + pz*pz)
                eta = 0.5*log((pmag+pz)/max(pmag-pz,1e-10))   # avoid division by zero

                # yield the Particle
                yield Particle(ID,pT,phi,eta)

            else:
                # this is a header line

                if not header:
                    # switch to header mode
                    header = True
                    # yield None to separate events
                    yield
<|endoftext|>


<commit_before>import argparse
import boto
from boto.utils import get_instance_metadata
from boto.exception import AWSConnectionError
import hipchat
import os
import subprocess
import traceback
import socket
import time

# Services that should be checked for migrations.
MIGRATION_COMMANDS = {
        'lms': "{python} {code_dir}/manage.py lms migrate --noinput --settings=aws --db-dry-run --merge",
        'cms': "{python} {code_dir}/manage.py cms migrate --noinput --settings=aws --db-dry-run --merge",
        'xqueue': "{python} {code_dir}/manage.py xqueue migrate --noinput --settings=aws --db-dry-run --merge",
    }
HIPCHAT_USER = "PreSupervisor"

# Max amount of time to wait for tags to be applied.
MAX_BACKOFF = 120
INITIAL_BACKOFF = 1

def services_for_instance(instance_id):
    """
    Get the list of all services named by the services tag in this
    instance's tags.
    """
    ec2 = boto.connect_ec2()
    reservations = ec2.get_all_instances(instance_ids=[instance_id])
    for reservation in reservations:
        for instance in reservation.instances:
            if instance.id == instance_id:
                try:
                    services = instance.tags['services'].split(',')
                except KeyError as ke:
                    msg = "Tag named 'services' not found on this instance({})".format(instance_id)
                    raise Exception(msg)

                for service in services:
                    yield service

def edp_for_instance(instance_id):
    ec2 = boto.connect_ec2()
    reservations = ec2.get_all_instances(instance_ids=[instance_id])
    for reservation in reservations:
        for instance in reservation.instances:
            if instance.id == instance_id:
                try:
                    environment = instance.tags['environment']
                    deployment = instance.tags['deployment']
                    play = instance.tags['play']
                except KeyError as ke:
                    msg = "{} tag not found on this instance({})".format(ke.message, instance_id)
                    raise Exception(msg)
                return (environment, deployment, play)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="Enable all services that are in the services tag of this ec2 instance.")
    parser.add_argument("-a","--available",
        help="The location of the available services.")
    parser.add_argument("-e","--enabled",
        help="The location of the enabled services.")

    migration_args = parser.add_argument_group("edxapp_migrations",
            "Args for running edxapp migration checks.")
    migration_args.add_argument("--edxapp-code-dir",
            help="Location of the edx-platform code.")
    migration_args.add_argument("--edxapp-python",
            help="Path to python to use for executing migration check.")

    xq_migration_args = parser.add_argument_group("xqueue_migrations",
            "Args for running xqueue migration checks.")
    xq_migration_args.add_argument("--xqueue-code-dir",
            help="Location of the edx-platform code.")
    xq_migration_args.add_argument("--xqueue-python",
            help="Path to python to use for executing migration check.")

    hipchat_args = parser.add_argument_group("hipchat",
            "Args for hipchat notification.")
    hipchat_args.add_argument("-c","--hipchat-api-key",
        help="Hipchat token if you want to receive notifications via hipchat.")
    hipchat_args.add_argument("-r","--hipchat-room",
        help="Room to send messages to.")

    args = parser.parse_args()

    report = []
    prefix = None
    notify = None

    try:
        if args.hipchat_api_key:
            hc = hipchat.HipChat(token=args.hipchat_api_key)
            notify = lambda message: hc.message_room(room_id=args.hipchat_room,
                message_from=HIPCHAT_USER, message=message)
    except Exception as e:
        print("Failed to initialize hipchat, {}".format(e))
        traceback.print_exc()

    instance_id = get_instance_metadata()['instance-id']
    prefix = instance_id

    ec2 = boto.connect_ec2()
    reservations = ec2.get_all_instances(instance_ids=[instance_id])
    instance = reservations[0].instances[0]
    if instance.instance_profile['arn'].endswith('/abbey'):
        print("Running an abbey build. Not starting any services.")
        # Needs to exit with 1 instead of 0 to prevent
        # services from starting.
        exit(1)
    time_left = MAX_BACKOFF
    backoff = INITIAL_BACKOFF

    environment = None
    deployment = None
    play = None
    while time_left > 0:
        try:
            environment, deployment, play = edp_for_instance(instance_id)
            prefix = "{environment}-{deployment}-{play}-{instance_id}".format(
                environment=environment,
                deployment=deployment,
                play=play,
                instance_id=instance_id)
            break
        except:
            print("Failed to get EDP for {}".format(instance_id))
            # With the time limit being 2 minutes we will
            # try 5 times before giving up.
            time.sleep(backoff)
            time_left -= backoff
            backoff = backoff * 2

    if environment is None or deployment is None or play is None:
        msg = "Unable to retrieve environment, deployment, or play tag."
        print(msg)
        notify("{} : {}".format(prefix, msg))
        exit(0)

    #get the hostname of the sandbox
    hostname = socket.gethostname()

    try:
        #get the list of the volumes, that are attached to the instance
        volumes = ec2.get_all_volumes(filters={'attachment.instance-id': instance_id})

        for volume in volumes:
            volume.add_tags({"hostname": hostname,
                             "environment": environment,
                             "deployment": deployment,
                             "cluster": play,
                             "instance-id": instance_id,
                             "created": volume.create_time })
    except:
        msg = "Failed to tag volumes associated with {}".format(instance_id)
        print(msg)
        notify(msg)

    try:
        for service in services_for_instance(instance_id):
            if service in MIGRATION_COMMANDS:
                # Do extra migration related stuff.
                if (service == 'lms' or service == 'cms') and args.edxapp_code_dir:
                    cmd = MIGRATION_COMMANDS[service].format(python=args.edxapp_python,
                        code_dir=args.edxapp_code_dir)
                    if os.path.exists(args.edxapp_code_dir):
                        os.chdir(args.edxapp_code_dir)
                        # Run migration check command.
                        output = subprocess.check_output(cmd, shell=True)
                        if 'Migrating' in output:
                            raise Exception("Migrations have not been run for {}".format(service))
                elif service == 'xqueue' and args.xqueue_code_dir:
                    cmd = MIGRATION_COMMANDS[service].format(python=args.xqueue_python,
                        code_dir=xqueue_code_dir)
                    if os.path.exists(args.xqueue_code_dir):
                        os.chdir(args.xqueue_code_dir)
                        # Run migration check command.
                        output = subprocess.check_output(cmd, shell=True)
                        if 'Migrating' in output:
                            raise Exception("Migrations have not been run for {}".format(service))

            # Link to available service.
            available_file = os.path.join(args.available, "{}.conf".format(service))
            link_location = os.path.join(args.enabled, "{}.conf".format(service))
            if os.path.exists(available_file):
                subprocess.call("ln -sf {} {}".format(available_file, link_location), shell=True)
                report.append("Linking service: {}".format(service))
            else:
                raise Exception("No conf available for service: {}".format(link_location))
    except AWSConnectionError as ae:
        msg = "{}: ERROR : {}".format(prefix, ae)
        if notify:
            notify(msg)
            notify(traceback.format_exc())
        raise ae
    except Exception as e:
        msg = "{}: ERROR : {}".format(prefix, e)
        print(msg)
        if notify:
            notify(msg)
        traceback.print_exc()
        raise e
    else:
        msg = "{}: {}".format(prefix, " | ".join(report))
        print(msg)
        if notify:
            notify(msg)
<commit_msg>Only notify when hipchat is setup.<commit_after>import argparse
import boto
from boto.utils import get_instance_metadata
from boto.exception import AWSConnectionError
import hipchat
import os
import subprocess
import traceback
import socket
import time

# Services that should be checked for migrations.
MIGRATION_COMMANDS = {
        'lms': "{python} {code_dir}/manage.py lms migrate --noinput --settings=aws --db-dry-run --merge",
        'cms': "{python} {code_dir}/manage.py cms migrate --noinput --settings=aws --db-dry-run --merge",
        'xqueue': "{python} {code_dir}/manage.py xqueue migrate --noinput --settings=aws --db-dry-run --merge",
    }
HIPCHAT_USER = "PreSupervisor"

# Max amount of time to wait for tags to be applied.
MAX_BACKOFF = 120
INITIAL_BACKOFF = 1

def services_for_instance(instance_id):
    """
    Get the list of all services named by the services tag in this
    instance's tags.
    """
    ec2 = boto.connect_ec2()
    reservations = ec2.get_all_instances(instance_ids=[instance_id])
    for reservation in reservations:
        for instance in reservation.instances:
            if instance.id == instance_id:
                try:
                    services = instance.tags['services'].split(',')
                except KeyError as ke:
                    msg = "Tag named 'services' not found on this instance({})".format(instance_id)
                    raise Exception(msg)

                for service in services:
                    yield service

def edp_for_instance(instance_id):
    ec2 = boto.connect_ec2()
    reservations = ec2.get_all_instances(instance_ids=[instance_id])
    for reservation in reservations:
        for instance in reservation.instances:
            if instance.id == instance_id:
                try:
                    environment = instance.tags['environment']
                    deployment = instance.tags['deployment']
                    play = instance.tags['play']
                except KeyError as ke:
                    msg = "{} tag not found on this instance({})".format(ke.message, instance_id)
                    raise Exception(msg)
                return (environment, deployment, play)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="Enable all services that are in the services tag of this ec2 instance.")
    parser.add_argument("-a","--available",
        help="The location of the available services.")
    parser.add_argument("-e","--enabled",
        help="The location of the enabled services.")

    migration_args = parser.add_argument_group("edxapp_migrations",
            "Args for running edxapp migration checks.")
    migration_args.add_argument("--edxapp-code-dir",
            help="Location of the edx-platform code.")
    migration_args.add_argument("--edxapp-python",
            help="Path to python to use for executing migration check.")

    xq_migration_args = parser.add_argument_group("xqueue_migrations",
            "Args for running xqueue migration checks.")
    xq_migration_args.add_argument("--xqueue-code-dir",
            help="Location of the edx-platform code.")
    xq_migration_args.add_argument("--xqueue-python",
            help="Path to python to use for executing migration check.")

    hipchat_args = parser.add_argument_group("hipchat",
            "Args for hipchat notification.")
    hipchat_args.add_argument("-c","--hipchat-api-key",
        help="Hipchat token if you want to receive notifications via hipchat.")
    hipchat_args.add_argument("-r","--hipchat-room",
        help="Room to send messages to.")

    args = parser.parse_args()

    report = []
    prefix = None
    notify = None

    try:
        if args.hipchat_api_key:
            hc = hipchat.HipChat(token=args.hipchat_api_key)
            notify = lambda message: hc.message_room(room_id=args.hipchat_room,
                message_from=HIPCHAT_USER, message=message)
    except Exception as e:
        print("Failed to initialize hipchat, {}".format(e))
        traceback.print_exc()

    instance_id = get_instance_metadata()['instance-id']
    prefix = instance_id

    ec2 = boto.connect_ec2()
    reservations = ec2.get_all_instances(instance_ids=[instance_id])
    instance = reservations[0].instances[0]
    if instance.instance_profile['arn'].endswith('/abbey'):
        print("Running an abbey build. Not starting any services.")
        # Needs to exit with 1 instead of 0 to prevent
        # services from starting.
        exit(1)
    time_left = MAX_BACKOFF
    backoff = INITIAL_BACKOFF

    environment = None
    deployment = None
    play = None
    while time_left > 0:
        try:
            environment, deployment, play = edp_for_instance(instance_id)
            prefix = "{environment}-{deployment}-{play}-{instance_id}".format(
                environment=environment,
                deployment=deployment,
                play=play,
                instance_id=instance_id)
            break
        except:
            print("Failed to get EDP for {}".format(instance_id))
            # With the time limit being 2 minutes we will
            # try 5 times before giving up.
            time.sleep(backoff)
            time_left -= backoff
            backoff = backoff * 2

    if environment is None or deployment is None or play is None:
        msg = "Unable to retrieve environment, deployment, or play tag."
        print(msg)
        if notify:
            notify("{} : {}".format(prefix, msg))
        exit(0)

    #get the hostname of the sandbox
    hostname = socket.gethostname()

    try:
        #get the list of the volumes, that are attached to the instance
        volumes = ec2.get_all_volumes(filters={'attachment.instance-id': instance_id})

        for volume in volumes:
            volume.add_tags({"hostname": hostname,
                             "environment": environment,
                             "deployment": deployment,
                             "cluster": play,
                             "instance-id": instance_id,
                             "created": volume.create_time })
    except:
        msg = "Failed to tag volumes associated with {}".format(instance_id)
        print(msg)
        if notify:
            notify(msg)

    try:
        for service in services_for_instance(instance_id):
            if service in MIGRATION_COMMANDS:
                # Do extra migration related stuff.
                if (service == 'lms' or service == 'cms') and args.edxapp_code_dir:
                    cmd = MIGRATION_COMMANDS[service].format(python=args.edxapp_python,
                        code_dir=args.edxapp_code_dir)
                    if os.path.exists(args.edxapp_code_dir):
                        os.chdir(args.edxapp_code_dir)
                        # Run migration check command.
                        output = subprocess.check_output(cmd, shell=True)
                        if 'Migrating' in output:
                            raise Exception("Migrations have not been run for {}".format(service))
                elif service == 'xqueue' and args.xqueue_code_dir:
                    cmd = MIGRATION_COMMANDS[service].format(python=args.xqueue_python,
                        code_dir=xqueue_code_dir)
                    if os.path.exists(args.xqueue_code_dir):
                        os.chdir(args.xqueue_code_dir)
                        # Run migration check command.
                        output = subprocess.check_output(cmd, shell=True)
                        if 'Migrating' in output:
                            raise Exception("Migrations have not been run for {}".format(service))

            # Link to available service.
            available_file = os.path.join(args.available, "{}.conf".format(service))
            link_location = os.path.join(args.enabled, "{}.conf".format(service))
            if os.path.exists(available_file):
                subprocess.call("ln -sf {} {}".format(available_file, link_location), shell=True)
                report.append("Linking service: {}".format(service))
            else:
                raise Exception("No conf available for service: {}".format(link_location))
    except AWSConnectionError as ae:
        msg = "{}: ERROR : {}".format(prefix, ae)
        if notify:
            notify(msg)
            notify(traceback.format_exc())
        raise ae
    except Exception as e:
        msg = "{}: ERROR : {}".format(prefix, e)
        print(msg)
        if notify:
            notify(msg)
        traceback.print_exc()
        raise e
    else:
        msg = "{}: {}".format(prefix, " | ".join(report))
        print(msg)
        if notify:
            notify(msg)
<|endoftext|>


<commit_before>##############################################################################
#
#    Copyright (C) 2016 Comunitea Servicios Tecnológicos S.L.
#    $Omar Castiñeira Saavedra$ <omar@comunitea.com>
#
#    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 odoo import models, fields, api
import odoo.addons.decimal_precision as dp

class ProductTemplate(models.Model):

    _inherit = "product.template"

    standard_price_2 = fields.Float(
        digits=dp.get_precision('Product Price'),
        string="Cost Price 2", company_dependent=True)

    def recalculate_standard_price_2(self):
        for product in self:
            moves = self.env['stock.move'].search(
                [('product_id', 'in', product.product_variant_ids._ids),
                ('remaining_qty', '>', 0)])
            if sum(moves.mapped('remaining_qty')) != 0:
                standard_price_2 = sum(moves.mapped('remaining_value')) / sum(moves.mapped('remaining_qty'))
                dp = self.env['decimal.precision'].search([('name', '=', 'Product Price')])
                standard_price_2 = round(standard_price_2, dp.digits)
                if standard_price_2 != round(product.standard_price_2, dp.digits):
                    product.standard_price_2 = standard_price_2 or product.standard_price
                elif not standard_price_2:
                    product.standard_price_2 = product.standard_price
            else:
                product.standard_price_2 = product.standard_price

class ProductProduct(models.Model):
    _inherit = 'product.product'

    @api.depends('list_price', 'pvd1_relation', 'pvd2_relation', 'pvd3_relation', 'pvd4_relation',
                 'standard_price_2', 'pvi1_price', 'pvi2_price', 'pvi3_price', 'pvi4_price')
    def _get_margins(self):
        for product in self:
            if product.list_price and product.pvd1_relation:
                product.margin_pvd1 = \
                    (1 - (product.standard_price_2 /
                        (product.list_price * product.pvd1_relation))) * 100.0

            if product.list_price2 and product.pvd2_relation:
                product.margin_pvd2 = \
                    (1 - (product.standard_price_2 /
                        (product.list_price2 * product.pvd2_relation))) * \
                    100.0

            if product.list_price3 and product.pvd3_relation:
                product.margin_pvd3 = \
                    (1 - (product.standard_price_2 /
                         (product.list_price3 * product.pvd3_relation))) * \
                    100.0

            if product.list_price4 and product.pvd4_relation:
                product.margin_pvd4 = \
                    (1 - (product.standard_price_2 /
                        (product.list_price4 * product.pvd4_relation))) * \
                    100.0

            if product.pvi1_price:
                product.margin_pvi1 = \
                    (1 - (product.standard_price_2 / product.pvi1_price)) * 100.0
                if product.pvd1_price:
                    product.margin_pvd_pvi_1 = \
                        ((product.pvd1_price - product.pvi1_price) / product.pvd1_price) * 100

            if product.pvi2_price:
                product.margin_pvi2 = \
                    (1 - (product.standard_price_2 / product.pvi2_price)) * 100.0
                if product.pvd2_price:
                    product.margin_pvd_pvi_2 = \
                        ((product.pvd2_price - product.pvi2_price) / product.pvd2_price) * 100

            if product.pvi3_price:
                product.margin_pvi3 = \
                    (1 - (product.standard_price_2 / product.pvi3_price)) * 100.0
                if product.pvd3_price:
                    product.margin_pvd_pvi_3 = \
                        ((product.pvd3_price - product.pvi3_price) / product.pvd3_price) * 100

            if product.pvi4_price:
                product.margin_pvi4 = \
                    (1 - (product.standard_price_2 / product.pvi4_price)) * 100.0
                if product.pvd4_price:
                    product.margin_pvd_pvi_4 = \
                        ((product.pvd4_price - product.pvi4_price) / product.pvd4_price) * 100

    list_price2 = fields.Float('Sale Price', digits=dp.get_precision('Product Price'))
    list_price3 = fields.Float('Sale Price 2', digits=dp.get_precision('Product Price'))
    list_price4 = fields.Float('Sale Price 3', digits=dp.get_precision('Product Price'))

    commercial_cost = fields.Float('Commercial Cost', digits=dp.get_precision('Product Price'))

    pvd1_relation = fields.Float('PVP/PVD 1 relation', digits=(4, 2), default=0.5)
    pvd2_relation = fields.Float('PVP 2 / PVD 2 relation', digits=(4, 2), default=0.5)
    pvd3_relation = fields.Float('PVP 3 / PVD 3 relation', digits=(4, 2), default=0.5)
    pvd4_relation = fields.Float('PVP 4 / PVD 4 relation', digits=(4, 2), default=0.5)

    pvd1_price = fields.Float('PVD 1 price', digits=dp.get_precision('Product Price'))
    pvd2_price = fields.Float('PVD 2 price', digits=dp.get_precision('Product Price'))
    pvd3_price = fields.Float('PVD 3 price', digits=dp.get_precision('Product Price'))
    pvd4_price = fields.Float('PVD 4 price', digits=dp.get_precision('Product Price'))

    pvi1_price = fields.Float('PVI 1 price', digits=dp.get_precision('Product Price'))
    pvi2_price = fields.Float('PVI 2 price', digits=dp.get_precision('Product Price'))
    pvi3_price = fields.Float('PVI 3 price', digits=dp.get_precision('Product Price'))

    pvi4_price = fields.Float('PVI 4 price', digits=dp.get_precision('Product Price'))
    margin_pvd1 = fields.Float(computed='_get_margins',
                               string="PVD 1 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvd2 = fields.Float(computed='_get_margins',
                               string="PVD 2 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvd3 = fields.Float(computed='_get_margins',
                               string="PVD 3 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvd4 = fields.Float(computed='_get_margins',
                               string="PVD 4 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvi1 = fields.Float(computed='_get_margins',
                               string="PVI 1 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvi2 = fields.Float(computed='_get_margins',
                               string="PVI 2 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvi3 = fields.Float(computed='_get_margins',
                               string="PVI 3 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvi4 = fields.Float(computed='_get_margins',
                               string="PVI 4 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvd_pvi_1 = fields.Float(computed='_get_margins',
                                    string='PVD/PVI 1 margin',
                                    digits=(5, 2),
                                    store=True)
    margin_pvd_pvi_2 = fields.Float(computed='_get_margins',
                                    string='PVD/PVI 2 margin',
                                    digits=(5, 2),
                                    store=True)
    margin_pvd_pvi_3 = fields.Float(computed='_get_margins',
                                    string='PVD/PVI 3 margin',
                                    digits=(5, 2),
                                    store=True)
    margin_pvd_pvi_4 = fields.Float(computed='_get_margins',
                                    string='PVD/PVI 4 margin',
                                    digits=(5, 2),
                                    store=True)

    @api.onchange('pvd1_price')
    def pvd1_price_change(self):
        pvd1_relation = 0.5
        if self.pvd1_price:
            self.lst_price = (1.0 / pvd1_relation) * self.pvd1_price
            self.margin_pvd1 = (1 - (self.standard_price_2 / self.pvd1_price)) * 100.0
            self.margin_pvd_pvi_1 = ((self.pvd1_price - self.pvi1_price) / self.pvd1_price) * 100
        else:
            self.lst_price = 0
            self.margin_pvd1 = 0
            self.margin_pvd_pvi_1 = 0

    @api.onchange('pvd2_price')
    def pvd2_price_change(self):
        pvd2_relation = 0.5
        if self.pvd2_price:
            self.list_price2 = (1.0 / pvd2_relation) * self.pvd2_price
            self.margin_pvd2 = (1 - (self.standard_price_2 / self.pvd2_price)) * 100.0
            self.margin_pvd_pvi_2 = ((self.pvd2_price - self.pvi2_price) / self.pvd2_price) * 100
        else:
            self.list_price2 = 0
            self.margin_pvd2 = 0
            self.margin_pvd_pvi_2 = 0

    @api.onchange('pvd3_price')
    def pvd3_price_change(self):
        pvd3_relation = 0.5
        if self.pvd3_price:
            self.list_price3 = (1.0 / pvd3_relation) * self.pvd3_price
            self.margin_pvd3 = (1 - (self.standard_price_2 / self.pvd3_price)) * 100.0
            self.margin_pvd_pvi_3 = ((self.pvd3_price - self.pvi3_price) / self.pvd3_price) * 100
        else:
            self.list_price3 = 0
            self.margin_pvd3 = 0
            self.margin_pvd_pvi_3 = 0

    @api.onchange('pvd4_price')
    def pvd4_price_change(self):
        pvd4_relation = 0.5
        if self.pvd4_price:
            self.list_price4 = (1.0 / pvd4_relation) * self.pvd4_price
            self.margin_pvd4 = (1 - (self.standard_price_2 / self.pvd4_price)) * 100.0
            self.margin_pvd_pvi_4 = ((self.pvd4_price - self.pvi4_price) / self.pvd4_price) * 100
        else:
            self.list_price4 = 0
            self.margin_pvd4 = 0
            self.margin_pvd_pvi_4 = 0

    @api.onchange('pvi1_price')
    def pvi1_price_change(self):
        if self.pvd1_price:
            self.margin_pvd_pvi_1 = ((self.pvd1_price - self.pvi1_price) / self.pvd1_price) * 100
        else:
            self.margin_pvd_pvi_1 = 0

        if self.pvi1_price:
            self.margin_pvi1 = (1 - (self.standard_price_2 / self.pvi1_price)) * 100.0
        else:
            self.margin_pvi1 = 0

    @api.onchange('pvi2_price')
    def pvi2_price_change(self):
        if self.pvd2_price:
            self.margin_pvd_pvi_2 = ((self.pvd2_price - self.pvi2_price) / self.pvd2_price) * 100
        else:
            self.margin_pvd_pvi_2 = 0

        if self.pvi2_price:
            self.margin_pvi2 = (1 - (self.standard_price_2 / self.pvi2_price)) * 100.0
        else:
            self.margin_pvi2 = 0

    @api.onchange('pvi3_price')
    def pvi3_price_change(self):
        if self.pvd3_price:
            self.margin_pvd_pvi_3 = ((self.pvd3_price - self.pvi3_price) / self.pvd3_price) * 100
        else:
            self.margin_pvd_pvi_3 = 0

        if self.pvi3_price:
            self.margin_pvi3 = (1 - (self.standard_price_2 / self.pvi3_price)) * 100.0
        else:
            self.margin_pvi3 = 0

    @api.onchange('pvi4_price')
    def pvi4_price_change(self):
        if self.pvd4_price:
            self.margin_pvd_pvi_4 = ((self.pvd4_price - self.pvi4_price) / self.pvd4_price) * 100
        else:
            self.margin_pvd_pvi_4 = 0

        if self.pvi4_price:
            self.margin_pvi4 = (1 - (self.standard_price_2 / self.pvi4_price)) * 100.0
        else:
            self.margin_pvi4 = 0
<commit_msg>[IMP] sale_customer_discount: Campos nuevos de precios en productos<commit_after>##############################################################################
#
#    Copyright (C) 2016 Comunitea Servicios Tecnológicos S.L.
#    $Omar Castiñeira Saavedra$ <omar@comunitea.com>
#
#    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 odoo import models, fields, api
import odoo.addons.decimal_precision as dp

class ProductTemplate(models.Model):

    _inherit = "product.template"

    standard_price_2 = fields.Float(
        digits=dp.get_precision('Product Price'),
        string="Cost Price 2", company_dependent=True)

    def recalculate_standard_price_2(self):
        for product in self:
            moves = self.env['stock.move'].search(
                [('product_id', 'in', product.product_variant_ids._ids),
                ('remaining_qty', '>', 0)])
            if sum(moves.mapped('remaining_qty')) != 0:
                standard_price_2 = sum(moves.mapped('remaining_value')) / sum(moves.mapped('remaining_qty'))
                dp = self.env['decimal.precision'].search([('name', '=', 'Product Price')])
                standard_price_2 = round(standard_price_2, dp.digits)
                if standard_price_2 != round(product.standard_price_2, dp.digits):
                    product.standard_price_2 = standard_price_2 or product.standard_price
                elif not standard_price_2:
                    product.standard_price_2 = product.standard_price
            else:
                product.standard_price_2 = product.standard_price

class ProductProduct(models.Model):
    _inherit = 'product.product'

    @api.depends('list_price', 'pvd1_relation', 'pvd2_relation', 'pvd3_relation', 'pvd4_relation',
                 'standard_price_2', 'pvi1_price', 'pvi2_price', 'pvi3_price', 'pvi4_price')
    def _get_margins(self):
        for product in self:
            if product.list_price and product.pvd1_relation:
                product.margin_pvd1 = \
                    (1 - (product.standard_price_2 /
                        (product.list_price * product.pvd1_relation))) * 100.0

            if product.list_price2 and product.pvd2_relation:
                product.margin_pvd2 = \
                    (1 - (product.standard_price_2 /
                        (product.list_price2 * product.pvd2_relation))) * \
                    100.0

            if product.list_price3 and product.pvd3_relation:
                product.margin_pvd3 = \
                    (1 - (product.standard_price_2 /
                         (product.list_price3 * product.pvd3_relation))) * \
                    100.0

            if product.list_price4 and product.pvd4_relation:
                product.margin_pvd4 = \
                    (1 - (product.standard_price_2 /
                        (product.list_price4 * product.pvd4_relation))) * \
                    100.0

            if product.pvi1_price:
                product.margin_pvi1 = \
                    (1 - (product.standard_price_2 / product.pvi1_price)) * 100.0
                if product.pvd1_price:
                    product.margin_pvd_pvi_1 = \
                        ((product.pvd1_price - product.pvi1_price) / product.pvd1_price) * 100

            if product.pvi2_price:
                product.margin_pvi2 = \
                    (1 - (product.standard_price_2 / product.pvi2_price)) * 100.0
                if product.pvd2_price:
                    product.margin_pvd_pvi_2 = \
                        ((product.pvd2_price - product.pvi2_price) / product.pvd2_price) * 100

            if product.pvi3_price:
                product.margin_pvi3 = \
                    (1 - (product.standard_price_2 / product.pvi3_price)) * 100.0
                if product.pvd3_price:
                    product.margin_pvd_pvi_3 = \
                        ((product.pvd3_price - product.pvi3_price) / product.pvd3_price) * 100

            if product.pvi4_price:
                product.margin_pvi4 = \
                    (1 - (product.standard_price_2 / product.pvi4_price)) * 100.0
                if product.pvd4_price:
                    product.margin_pvd_pvi_4 = \
                        ((product.pvd4_price - product.pvi4_price) / product.pvd4_price) * 100

    list_price1 = fields.Float('Sale Price 1', digits=dp.get_precision('Product Price'))
    list_price2 = fields.Float('Sale Price 2', digits=dp.get_precision('Product Price'))
    list_price3 = fields.Float('Sale Price 3', digits=dp.get_precision('Product Price'))
    list_price4 = fields.Float('Sale Price 4', digits=dp.get_precision('Product Price'))

    commercial_cost = fields.Float('Commercial Cost', digits=dp.get_precision('Product Price'))

    pvd1_relation = fields.Float('PVP/PVD 1 relation', digits=(4, 2), default=0.5)
    pvd2_relation = fields.Float('PVP 2 / PVD 2 relation', digits=(4, 2), default=0.5)
    pvd3_relation = fields.Float('PVP 3 / PVD 3 relation', digits=(4, 2), default=0.5)
    pvd4_relation = fields.Float('PVP 4 / PVD 4 relation', digits=(4, 2), default=0.5)

    pvd1_price = fields.Float('PVD 1 price', digits=dp.get_precision('Product Price'))
    pvd2_price = fields.Float('PVD 2 price', digits=dp.get_precision('Product Price'))
    pvd3_price = fields.Float('PVD 3 price', digits=dp.get_precision('Product Price'))
    pvd4_price = fields.Float('PVD 4 price', digits=dp.get_precision('Product Price'))

    pvi1_price = fields.Float('PVI 1 price', digits=dp.get_precision('Product Price'))
    pvi2_price = fields.Float('PVI 2 price', digits=dp.get_precision('Product Price'))
    pvi3_price = fields.Float('PVI 3 price', digits=dp.get_precision('Product Price'))
    pvi4_price = fields.Float('PVI 4 price', digits=dp.get_precision('Product Price'))

    pvm1_price = fields.Float('PVM 1 price', digits=dp.get_precision('Product Price'))
    pvm2_price = fields.Float('PVM 2 price', digits=dp.get_precision('Product Price'))
    pvm3_price = fields.Float('PVM 3 price', digits=dp.get_precision('Product Price'))

    margin_pvd1 = fields.Float(computed='_get_margins',
                               string="PVD 1 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvd2 = fields.Float(computed='_get_margins',
                               string="PVD 2 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvd3 = fields.Float(computed='_get_margins',
                               string="PVD 3 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvd4 = fields.Float(computed='_get_margins',
                               string="PVD 4 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvi1 = fields.Float(computed='_get_margins',
                               string="PVI 1 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvi2 = fields.Float(computed='_get_margins',
                               string="PVI 2 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvi3 = fields.Float(computed='_get_margins',
                               string="PVI 3 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvi4 = fields.Float(computed='_get_margins',
                               string="PVI 4 Margin",
                               digits=(5, 2),
                               store=True)
    margin_pvd_pvi_1 = fields.Float(computed='_get_margins',
                                    string='PVD/PVI 1 margin',
                                    digits=(5, 2),
                                    store=True)
    margin_pvd_pvi_2 = fields.Float(computed='_get_margins',
                                    string='PVD/PVI 2 margin',
                                    digits=(5, 2),
                                    store=True)
    margin_pvd_pvi_3 = fields.Float(computed='_get_margins',
                                    string='PVD/PVI 3 margin',
                                    digits=(5, 2),
                                    store=True)
    margin_pvd_pvi_4 = fields.Float(computed='_get_margins',
                                    string='PVD/PVI 4 margin',
                                    digits=(5, 2),
                                    store=True)

    @api.onchange('pvd1_price')
    def pvd1_price_change(self):
        pvd1_relation = 0.5
        if self.pvd1_price:
            self.lst_price = (1.0 / pvd1_relation) * self.pvd1_price
            self.margin_pvd1 = (1 - (self.standard_price_2 / self.pvd1_price)) * 100.0
            self.margin_pvd_pvi_1 = ((self.pvd1_price - self.pvi1_price) / self.pvd1_price) * 100
        else:
            self.lst_price = 0
            self.margin_pvd1 = 0
            self.margin_pvd_pvi_1 = 0

    @api.onchange('pvd2_price')
    def pvd2_price_change(self):
        pvd2_relation = 0.5
        if self.pvd2_price:
            self.list_price2 = (1.0 / pvd2_relation) * self.pvd2_price
            self.margin_pvd2 = (1 - (self.standard_price_2 / self.pvd2_price)) * 100.0
            self.margin_pvd_pvi_2 = ((self.pvd2_price - self.pvi2_price) / self.pvd2_price) * 100
        else:
            self.list_price2 = 0
            self.margin_pvd2 = 0
            self.margin_pvd_pvi_2 = 0

    @api.onchange('pvd3_price')
    def pvd3_price_change(self):
        pvd3_relation = 0.5
        if self.pvd3_price:
            self.list_price3 = (1.0 / pvd3_relation) * self.pvd3_price
            self.margin_pvd3 = (1 - (self.standard_price_2 / self.pvd3_price)) * 100.0
            self.margin_pvd_pvi_3 = ((self.pvd3_price - self.pvi3_price) / self.pvd3_price) * 100
        else:
            self.list_price3 = 0
            self.margin_pvd3 = 0
            self.margin_pvd_pvi_3 = 0

    @api.onchange('pvd4_price')
    def pvd4_price_change(self):
        pvd4_relation = 0.5
        if self.pvd4_price:
            self.list_price4 = (1.0 / pvd4_relation) * self.pvd4_price
            self.margin_pvd4 = (1 - (self.standard_price_2 / self.pvd4_price)) * 100.0
            self.margin_pvd_pvi_4 = ((self.pvd4_price - self.pvi4_price) / self.pvd4_price) * 100
        else:
            self.list_price4 = 0
            self.margin_pvd4 = 0
            self.margin_pvd_pvi_4 = 0

    @api.onchange('pvi1_price')
    def pvi1_price_change(self):
        if self.pvd1_price:
            self.margin_pvd_pvi_1 = ((self.pvd1_price - self.pvi1_price) / self.pvd1_price) * 100
        else:
            self.margin_pvd_pvi_1 = 0

        if self.pvi1_price:
            self.margin_pvi1 = (1 - (self.standard_price_2 / self.pvi1_price)) * 100.0
        else:
            self.margin_pvi1 = 0

    @api.onchange('pvi2_price')
    def pvi2_price_change(self):
        if self.pvd2_price:
            self.margin_pvd_pvi_2 = ((self.pvd2_price - self.pvi2_price) / self.pvd2_price) * 100
        else:
            self.margin_pvd_pvi_2 = 0

        if self.pvi2_price:
            self.margin_pvi2 = (1 - (self.standard_price_2 / self.pvi2_price)) * 100.0
        else:
            self.margin_pvi2 = 0

    @api.onchange('pvi3_price')
    def pvi3_price_change(self):
        if self.pvd3_price:
            self.margin_pvd_pvi_3 = ((self.pvd3_price - self.pvi3_price) / self.pvd3_price) * 100
        else:
            self.margin_pvd_pvi_3 = 0

        if self.pvi3_price:
            self.margin_pvi3 = (1 - (self.standard_price_2 / self.pvi3_price)) * 100.0
        else:
            self.margin_pvi3 = 0

    @api.onchange('pvi4_price')
    def pvi4_price_change(self):
        if self.pvd4_price:
            self.margin_pvd_pvi_4 = ((self.pvd4_price - self.pvi4_price) / self.pvd4_price) * 100
        else:
            self.margin_pvd_pvi_4 = 0

        if self.pvi4_price:
            self.margin_pvi4 = (1 - (self.standard_price_2 / self.pvi4_price)) * 100.0
        else:
            self.margin_pvi4 = 0
<|endoftext|>


<commit_before>import numpy

from chainer import cuda
from chainer import function
from chainer.functions import sigmoid
from chainer import utils
from chainer.utils import type_check

class SigmoidCrossEntropy(function.Function):

    """Sigmoid activation followed by a sigmoid cross entropy loss."""

    ignore_label = -1

    def __init__(self, use_cudnn=True, normalize=True, reduce='mean'):
        self.use_cudnn = use_cudnn
        self.normalize = normalize
        if reduce not in ('mean', 'no'):
            raise ValueError(
                "only 'mean' and 'no' are valid for 'reduce', but '%s' is "
                'given' % reduce)
        self.reduce = reduce

    def check_type_forward(self, in_types):
        type_check.expect(in_types.size() == 2)

        x_type, t_type = in_types
        type_check.expect(
            x_type.dtype == numpy.float32,
            t_type.dtype == numpy.int32,
            x_type.shape == t_type.shape
        )

    def forward(self, inputs):
        xp = cuda.get_array_module(*inputs)
        x, t = inputs
        self.ignore_mask = (t != self.ignore_label)

        # stable computation of the cross entropy.
        loss = -(
            self.ignore_mask *
            (x * (t - (x >= 0)) - xp.log1p(xp.exp(-xp.abs(x)))))

        if not self.reduce == 'mean':
            return utils.force_array(loss.astype(x.dtype)),

        if self.normalize:
            count = xp.maximum(1, self.ignore_mask.sum())
        else:
            count = max(1, len(x))
        self.count = count

        return utils.force_array(
            xp.divide(xp.sum(loss), self.count, dtype=x.dtype)),

    def backward(self, inputs, grad_outputs):
        xp = cuda.get_array_module(*inputs)
        x, t = inputs
        gloss = grad_outputs[0]
        y, = sigmoid.Sigmoid(self.use_cudnn).forward((x,))
        if self.reduce == 'mean':
            gx = xp.divide(
                gloss * self.ignore_mask * (y - t), self.count,
                dtype=y.dtype)
        else:
            gx = (gloss * self.ignore_mask * (y - t)).astype(y.dtype)
        return gx, None

def sigmoid_cross_entropy(
        x, t, use_cudnn=True, normalize=True, reduce='mean'):
    """Computes cross entropy loss for pre-sigmoid activations.

    Args:
        x (Variable): A variable object holding a matrix whose (i, j)-th
            element indicates the unnormalized log probability of the j-th unit
            at the i-th example.
        t (Variable): Variable holding an int32 vector of ground truth labels.
            If ``t[i] == -1``, corresponding ``x[i]`` is ignored.
            Loss is zero if all ground truth labels are ``-1``.
        normalize (bool): Variable holding a boolean value which
            determines the normalization constant. If true, this function
            normalizes the cross entropy loss across all instances. If else,
            it only normalizes along a batch size.
        reduce (bool): Variable holding a boolean value which
            determines whether to reduce the shape of the input.
            If true, it computes the sum of cross entropy
            and normalize it according to ``normalize`` option.
            If else, this function computes cross entropy for each instance
            and does not normalize it (``normalize`` option is ignored).

    Returns:
        Variable: A variable object holding an array of the cross entropy.
        If ``reduce`` is True, it is a scalar array.
        If else, the shape is same as ``x``.

    .. note::

       This function is differentiable only by ``x``.

    """
    return SigmoidCrossEntropy(use_cudnn, normalize, reduce)(x, t)
<commit_msg>update docs<commit_after>import numpy

from chainer import cuda
from chainer import function
from chainer.functions import sigmoid
from chainer import utils
from chainer.utils import type_check

class SigmoidCrossEntropy(function.Function):

    """Sigmoid activation followed by a sigmoid cross entropy loss."""

    ignore_label = -1

    def __init__(self, use_cudnn=True, normalize=True, reduce='mean'):
        self.use_cudnn = use_cudnn
        self.normalize = normalize
        if reduce not in ('mean', 'no'):
            raise ValueError(
                "only 'mean' and 'no' are valid for 'reduce', but '%s' is "
                'given' % reduce)
        self.reduce = reduce

    def check_type_forward(self, in_types):
        type_check.expect(in_types.size() == 2)

        x_type, t_type = in_types
        type_check.expect(
            x_type.dtype == numpy.float32,
            t_type.dtype == numpy.int32,
            x_type.shape == t_type.shape
        )

    def forward(self, inputs):
        xp = cuda.get_array_module(*inputs)
        x, t = inputs
        self.ignore_mask = (t != self.ignore_label)

        # stable computation of the cross entropy.
        loss = -(
            self.ignore_mask *
            (x * (t - (x >= 0)) - xp.log1p(xp.exp(-xp.abs(x)))))

        if not self.reduce == 'mean':
            return utils.force_array(loss.astype(x.dtype)),

        if self.normalize:
            count = xp.maximum(1, self.ignore_mask.sum())
        else:
            count = max(1, len(x))
        self.count = count

        return utils.force_array(
            xp.divide(xp.sum(loss), self.count, dtype=x.dtype)),

    def backward(self, inputs, grad_outputs):
        xp = cuda.get_array_module(*inputs)
        x, t = inputs
        gloss = grad_outputs[0]
        y, = sigmoid.Sigmoid(self.use_cudnn).forward((x,))
        if self.reduce == 'mean':
            gx = xp.divide(
                gloss * self.ignore_mask * (y - t), self.count,
                dtype=y.dtype)
        else:
            gx = (gloss * self.ignore_mask * (y - t)).astype(y.dtype)
        return gx, None

def sigmoid_cross_entropy(
        x, t, use_cudnn=True, normalize=True, reduce='mean'):
    """Computes cross entropy loss for pre-sigmoid activations.

    Args:
        x (Variable): A variable object holding a matrix whose (i, j)-th
            element indicates the unnormalized log probability of the j-th unit
            at the i-th example.
        t (Variable): Variable holding an int32 vector of ground truth labels.
            If ``t[i] == -1``, corresponding ``x[i]`` is ignored.
            Loss is zero if all ground truth labels are ``-1``.
        normalize (bool): Variable holding a boolean value which
            determines the normalization constant. If true, this function
            normalizes the cross entropy loss across all instances. If else,
            it only normalizes along a batch size.
        reduce (bool): Variable holding a string value which
            determines whether to reduce the shape of the input.
            If it is `mean`, it computes the sum of cross entropy
            and normalize it according to ``normalize`` option.
            If is is `no`, this function computes cross entropy for each
            instance and does not normalize it (``normalize`` option is
            ignored). In this case, the loss value of the ignored instance,
            which has ``-1`` as its target value, is set to ``0``.

    Returns:
        Variable: A variable object holding an array of the cross entropy.
        If ``reduce`` is ``True``, it is a scalar array.
        If else, the shape is same as ``x``.

    .. note::

       This function is differentiable only by ``x``.

    """
    return SigmoidCrossEntropy(use_cudnn, normalize, reduce)(x, t)
<|endoftext|>


<commit_before><commit_msg>RES-838: Analyze dutycycle pruning<commit_after><|endoftext|>