<commit_before>#!/usr/bin/env python
# coding=utf-8
# Filename: __version__.py
# pylint: disable=C0103
"""
Pep 386 compliant version info.

    (major, minor, micro, alpha/beta/rc/final, #)
    (1, 1, 2, 'alpha', 0) => "1.1.2.dev"
    (1, 2, 0, 'beta', 2) => "1.2b2"

"""
import json
try:
    from urllib import urlopen
except ImportError:
    from urllib.request import urlopen

try:
    from km3pipe.config import Config
    config = Config()
except ImportError:
    config = None

from km3pipe.logger import logging

__author__ = 'tamasgal'

log = logging.getLogger(__name__)  # pylint: disable=C0103

version_info = (2, 0, 0, 'final', 0)

def _get_version(version_info):
    """Return a PEP 386-compliant version number."""
    assert len(version_info) == 5
    assert version_info[3] in ('alpha', 'beta', 'rc', 'final')

    parts = 2 if version_info[2] == 0 else 3
    main = '.'.join(map(str, version_info[:parts]))

    sub = ''
    if version_info[3] == 'alpha' and version_info[4] == 0:
        sub = '.dev'
    elif version_info[3] != 'final':
        mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'c'}
        sub = mapping[version_info[3]] + str(version_info[4])

    return str(main + sub)

def _get_latest_version():
    response = urlopen('https://pypi.python.org/pypi/km3pipe/json')
    content = response.read()
    latest_version = json.loads(content.decode())['info']['version']
    return str(latest_version)

def check_for_update():
    try:
        latest_version = _get_latest_version()
    except IOError:
        pass
    else:
        version = _get_version(version_info)
        if latest_version != version:
            log.warn("There is an update for km3pipe available.\n" +
                     "    Installed: {0}\n"
                     "    Latest: {1}\n".format(version, latest_version) +
                     "Please run `pip install --upgrade km3pipe` to update.")

version = _get_version(version_info)
if config is not None:
    if config.check_for_updates:
        check_for_update()
<commit_msg>Bumps the version number<commit_after>#!/usr/bin/env python
# coding=utf-8
# Filename: __version__.py
# pylint: disable=C0103
"""
Pep 386 compliant version info.

    (major, minor, micro, alpha/beta/rc/final, #)
    (1, 1, 2, 'alpha', 0) => "1.1.2.dev"
    (1, 2, 0, 'beta', 2) => "1.2b2"

"""
import json
try:
    from urllib import urlopen
except ImportError:
    from urllib.request import urlopen

try:
    from km3pipe.config import Config
    config = Config()
except ImportError:
    config = None

from km3pipe.logger import logging

__author__ = 'tamasgal'

log = logging.getLogger(__name__)  # pylint: disable=C0103

version_info = (2, 0, 1, 'final', 0)

def _get_version(version_info):
    """Return a PEP 386-compliant version number."""
    assert len(version_info) == 5
    assert version_info[3] in ('alpha', 'beta', 'rc', 'final')

    parts = 2 if version_info[2] == 0 else 3
    main = '.'.join(map(str, version_info[:parts]))

    sub = ''
    if version_info[3] == 'alpha' and version_info[4] == 0:
        sub = '.dev'
    elif version_info[3] != 'final':
        mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'c'}
        sub = mapping[version_info[3]] + str(version_info[4])

    return str(main + sub)

def _get_latest_version():
    response = urlopen('https://pypi.python.org/pypi/km3pipe/json')
    content = response.read()
    latest_version = json.loads(content.decode())['info']['version']
    return str(latest_version)

def check_for_update():
    try:
        latest_version = _get_latest_version()
    except IOError:
        pass
    else:
        version = _get_version(version_info)
        if latest_version != version:
            log.warn("There is an update for km3pipe available.\n" +
                     "    Installed: {0}\n"
                     "    Latest: {1}\n".format(version, latest_version) +
                     "Please run `pip install --upgrade km3pipe` to update.")

version = _get_version(version_info)
if config is not None:
    if config.check_for_updates:
        check_for_update()
<|endoftext|>


<commit_before># coding=utf-8
# Filename: __init__.py
"""
A collection of io for different kinds of data formats.

"""
from __future__ import division, absolute_import, print_function

import os.path
from six import string_types

import numpy as np

from .evt import EvtPump  # noqa
from .daq import DAQPump  # noqa
from .clb import CLBPump  # noqa
from .aanet import AanetPump  # noqa
from .jpp import EventPump  # noqa
from .ch import CHPump  # noqa
from .hdf5 import HDF5Pump  # noqa
from .hdf5 import HDF5Sink  # noqa
from .hdf5 import HDF5MetaData  # noqa
from .pickle import PicklePump  # noqa
from .pandas import (H5Chain, df_to_h5, map2df,  # noqa
                     read_group, write_table,)  # noqa

from km3pipe.tools import insert_prefix_to_dtype  # noqa
from km3pipe.core import Run
from km3pipe.logger import logging

__author__ = "Tamas Gal"
__copyright__ = "Copyright 2016, Tamas Gal and the KM3NeT collaboration."
__credits__ = []
__license__ = "MIT"
__maintainer__ = "Tamas Gal, Moritz Lotze"
__email__ = "tgal@km3net.de"
__status__ = "Development"

log = logging.getLogger(__name__)

def GenericPump(filenames, use_jppy=False, name="GenericPump", **kwargs):
    """A generic pump which utilises the appropriate pump."""
    if not isinstance(filenames, string_types):
        fn = filenames[0]
    else:
        fn = filenames
    extension = os.path.splitext(fn)[1]

    n_nonexist = 0
    for fn in filenames:
        if not os.path.exists(fn):
            n_nonexist += 1
            log.warning("File '{}' not found, skipping...".format(fn))
    if n_nonexist == len(filenames):
        log.critical("No pump found for '{0}'".format(extension))
        raise IOError("None of the input files exist! Exiting.")

    io = {
        '.evt': EvtPump,
        '.h5': HDF5Pump,
        '.root': EventPump if use_jppy else AanetPump,
        '.dat': DAQPump,
        '.dqd': CLBPump,
    }

    if extension not in io:
        log.critical("No pump found for '{0}'".format(extension))

    if isinstance(filenames, string_types):
        return io[extension](filename=filenames, name=name, **kwargs)
    else:
        if len(filenames) == 1:
            return io[extension](filename=filenames[0], name=name, **kwargs)
        return io[extension](filenames=filenames, name=name, **kwargs)

def read_calibration(detx=None, det_id=None, from_file=False,
                     det_id_table=None):
    """Retrive calibration from file, the DB."""
    from km3pipe.calib import Calibration  # noqa

    if not detx or det_id or from_file:
        return None
    if detx is not None:
        return Calibration(filename=detx)
    if from_file:
        det_ids = np.unique(det_id_table)
        if len(det_ids) > 1:
            log.critical("Multiple detector IDs found in events.")
        det_id = det_ids[0]
    if det_id is not None:
        if det_id < 0:
            log.warning("Negative detector ID found ({0}), skipping..."
                        .format(det_id))
            return None
        try:
            return Calibration(det_id=det_id)
        except ValueError:
            log.warning("Could not retrieve the calibration information.")
    return None

def read_hdf5(filename, detx=None, det_id=None, det_from_file=False):
    """Open HDF5 file and retrieve all relevant information.

    Optionally, a detector calibration can read by passing a detector file,
    or retrieved from the database by passing a detector ID, or by reading
    the detector id from the event info in the file.
    """
    import pandas as pd

    h5 = pd.HDFStore(filename, mode='r')
    opts = {}
    opts['event_info'] = h5.get('event_info')
    optional_keys = {'hits', 'mc_hits', 'mc_tracks'}       # noqa
    for k in optional_keys:
        try:
            opts[k] = h5.get(k)
        except KeyError:
            continue
    try:
        opts['reco'] = read_group(h5.root.reco)
    except (KeyError, ValueError):
        pass
    run = Run(**opts)

    det_id_table = opts['event_info']['det_id']
    run.calibration = read_calibration(detx, det_id, det_from_file,
                                       det_id_table=det_id_table)
<commit_msg>hide import of Run<commit_after># coding=utf-8
# Filename: __init__.py
"""
A collection of io for different kinds of data formats.

"""
from __future__ import division, absolute_import, print_function

import os.path
from six import string_types

import numpy as np

from .evt import EvtPump  # noqa
from .daq import DAQPump  # noqa
from .clb import CLBPump  # noqa
from .aanet import AanetPump  # noqa
from .jpp import EventPump  # noqa
from .ch import CHPump  # noqa
from .hdf5 import HDF5Pump  # noqa
from .hdf5 import HDF5Sink  # noqa
from .hdf5 import HDF5MetaData  # noqa
from .pickle import PicklePump  # noqa
from .pandas import (H5Chain, df_to_h5, map2df,  # noqa
                     read_group, write_table,)  # noqa

from km3pipe.logger import logging

__author__ = "Tamas Gal"
__copyright__ = "Copyright 2016, Tamas Gal and the KM3NeT collaboration."
__credits__ = []
__license__ = "MIT"
__maintainer__ = "Tamas Gal, Moritz Lotze"
__email__ = "tgal@km3net.de"
__status__ = "Development"

log = logging.getLogger(__name__)

def GenericPump(filenames, use_jppy=False, name="GenericPump", **kwargs):
    """A generic pump which utilises the appropriate pump."""
    if not isinstance(filenames, string_types):
        fn = filenames[0]
    else:
        fn = filenames
    extension = os.path.splitext(fn)[1]

    n_nonexist = 0
    for fn in filenames:
        if not os.path.exists(fn):
            n_nonexist += 1
            log.warning("File '{}' not found, skipping...".format(fn))
    if n_nonexist == len(filenames):
        log.critical("No pump found for '{0}'".format(extension))
        raise IOError("None of the input files exist! Exiting.")

    io = {
        '.evt': EvtPump,
        '.h5': HDF5Pump,
        '.root': EventPump if use_jppy else AanetPump,
        '.dat': DAQPump,
        '.dqd': CLBPump,
    }

    if extension not in io:
        log.critical("No pump found for '{0}'".format(extension))

    if isinstance(filenames, string_types):
        return io[extension](filename=filenames, name=name, **kwargs)
    else:
        if len(filenames) == 1:
            return io[extension](filename=filenames[0], name=name, **kwargs)
        return io[extension](filenames=filenames, name=name, **kwargs)

def read_calibration(detx=None, det_id=None, from_file=False,
                     det_id_table=None):
    """Retrive calibration from file, the DB."""
    from km3pipe.calib import Calibration  # noqa

    if not detx or det_id or from_file:
        return None
    if detx is not None:
        return Calibration(filename=detx)
    if from_file:
        det_ids = np.unique(det_id_table)
        if len(det_ids) > 1:
            log.critical("Multiple detector IDs found in events.")
        det_id = det_ids[0]
    if det_id is not None:
        if det_id < 0:
            log.warning("Negative detector ID found ({0}), skipping..."
                        .format(det_id))
            return None
        try:
            return Calibration(det_id=det_id)
        except ValueError:
            log.warning("Could not retrieve the calibration information.")
    return None

def read_hdf5(filename, detx=None, det_id=None, det_from_file=False):
    """Open HDF5 file and retrieve all relevant information.

    Optionally, a detector calibration can read by passing a detector file,
    or retrieved from the database by passing a detector ID, or by reading
    the detector id from the event info in the file.
    """
    import pandas as pd
    from km3pipe.core import Run

    h5 = pd.HDFStore(filename, mode='r')
    opts = {}
    opts['event_info'] = h5.get('event_info')
    optional_keys = {'hits', 'mc_hits', 'mc_tracks'}       # noqa
    for k in optional_keys:
        try:
            opts[k] = h5.get(k)
        except KeyError:
            continue
    try:
        opts['reco'] = read_group(h5.root.reco)
    except (KeyError, ValueError):
        pass
    run = Run(**opts)

    det_id_table = opts['event_info']['det_id']
    run.calibration = read_calibration(detx, det_id, det_from_file,
                                       det_id_table=det_id_table)
<|endoftext|>


<commit_before>from django.contrib.auth.models import User
from django.test import TestCase
from ..models import Contact
from ..models import Client

# Create your tests here.

class ContactTestCase(TestCase):

    def setUp(self):
        Contact.objects.create(active=True, first_name="Alex", last_name="Clark", pk=1)

    def test_create(self):
        contact = Contact.objects.get(pk=1)
        self.assertEqual(contact.active, True)
        self.assertEqual(contact.first_name, "Alex")
        self.assertEqual(contact.last_name, "Clark")

class ClientTestCase(TestCase):
    def setUp(self):
        Client.objects.create(active=True,
                              address="1234 Street",
                              description="The First Client",
                              name="Client 1", )

    def test_create(self):
        client = Client.objects.get(name="Client 1")
        self.assertEqual(client.active, True)
        self.assertEqual(client.address, "1234 Street")
        self.assertEqual(client.description, "The First Client")
        self.assertEqual(client.name, "Client 1")
<commit_msg>Update<commit_after>from django.contrib.auth.models import User
from django.test import TestCase
from ..models import Contact
from ..models import Client

# Create your tests here.

class ContactTestCase(TestCase):

    def setUp(self):
        Contact.objects.create(active=True, first_name="Alex", last_name="Clark", pk=1)

    def test_create(self):
        contact = Contact.objects.get(pk=1)
        self.assertEqual(contact.active, True)
        self.assertEqual(contact.first_name, "Alex")
        self.assertEqual(contact.last_name, "Clark")

class ClientTestCase(TestCase):

    def setUp(self):
        Client.objects.create(active=True,
                              address="1234 Street",
                              description="The First Client",
                              name="Client 1", )

    def test_create(self):
        client = Client.objects.get(name="Client 1")
        self.assertEqual(client.active, True)
        self.assertEqual(client.address, "1234 Street")
        self.assertEqual(client.description, "The First Client")
        self.assertEqual(client.name, "Client 1")
<|endoftext|>


<commit_before>from Framework.BancoDeDados import BancoDeDados
from Database.Models.Usuario import Usuario as ModelUsuario

class Usuario(object):

	def pegarUsuarios(self, condicao, valores):
		usuarios = []
		for usuario in BancoDeDados().consultarMultiplos("SELECT * FROM usuario %s" % (condicao), valores):
			usuarios.append(ModelUsuario(usuario))
		return usuarios

	def pegarUsuario(self, condicao, valores):
		usuario = BancoDeDados().consultarUnico("SELECT * FROM usuario %s" % (condicao), valores)
		if usuario is not None:
			return ModelUsuario(usuario)
		else:
			return None

	def inserirUsuario(self, usuario):
		BancoDeDados().executar("INSERT INTO usuario (matricula, nome, cpf, perfil, senha) VALUES (%s,%s,%s,%s,%s) RETURNING id", (usuario.matricula, usuario.nome, usuario.cpf, usuario.perfil, usuario.senha))
		usuario.id = BancoDeDados().pegarUltimoIDInserido()
		return usuario

	def removerUsuario(self, usuario):
		BancoDeDados().executar("DELETE FROM usuario WHERE id = %s", (str(usuario.id)))

	def alterarUsuario(self, usuario):
		SQL = "UPDATE usuario SET matricula = %s, nome = %s, cpf = %s, perfil = %s, senha = %s WHERE id = %s"
		BancoDeDados().executar(SQL, (usuario.matricula, usuario.nome, usuario.cpf, usuario.perfil, usuario.senha, usuario.id))
<commit_msg>Auto-committing 'Usuario.py'<commit_after>from Framework.BancoDeDados import BancoDeDados
from Database.Models.Usuario import Usuario as ModelUsuario

class Usuario(object):

	def pegarUsuarios(self, condicao, valores):
		usuarios = []
		for usuario in BancoDeDados().consultarMultiplos("SELECT * FROM usuario %s" % (condicao), valores):
			usuarios.append(ModelUsuario(usuario))
		return usuarios
		b

	def pegarUsuario(self, condicao, valores):
		usuario = BancoDeDados().consultarUnico("SELECT * FROM usuario %s" % (condicao), valores)
		if usuario is not None:
			return ModelUsuario(usuario)
		else:
			return None

	def inserirUsuario(self, usuario):
		BancoDeDados().executar("INSERT INTO usuario (matricula, nome, cpf, perfil, senha) VALUES (%s,%s,%s,%s,%s) RETURNING id", (usuario.matricula, usuario.nome, usuario.cpf, usuario.perfil, usuario.senha))
		usuario.id = BancoDeDados().pegarUltimoIDInserido()
		return usuario

	def removerUsuario(self, usuario):
		BancoDeDados().executar("DELETE FROM usuario WHERE id = %s", (str(usuario.id)))

	def alterarUsuario(self, usuario):
		SQL = "UPDATE usuario SET matricula = %s, nome = %s, cpf = %s, perfil = %s, senha = %s WHERE id = %s"
		BancoDeDados().executar(SQL, (usuario.matricula, usuario.nome, usuario.cpf, usuario.perfil, usuario.senha, usuario.id))<|endoftext|>


<commit_before><commit_msg>Update pep257 to v0.6.0<commit_after><|endoftext|>


<commit_before><commit_msg>Deleted overridden method that did nothing<commit_after><|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
#    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 osv import osv, fields
from tools.translate import _
import netsvc

class sale_order_line_make_invoice(osv.osv_memory):
    _name = "sale.order.line.make.invoice"
    _description = "Sale OrderLine Make_invoice"
    def make_invoices(self, cr, uid, ids, context=None):
        """
             To make invoices.

             @param self: The object pointer.
             @param cr: A database cursor
             @param uid: ID of the user currently logged in
             @param ids: the ID or list of IDs
             @param context: A standard dictionary

             @return: A dictionary which of fields with values.

        """
        if context is None: context = {}
        res = False
        invoices = {}

    #TODO: merge with sale.py/make_invoice
        def make_invoice(order, lines):
            """
                 To make invoices.

                 @param order:
                 @param lines:

                 @return:

            """
            a = order.partner_id.property_account_receivable.id
            if order.partner_id and order.partner_id.property_payment_term.id:
                pay_term = order.partner_id.property_payment_term.id
            else:
                pay_term = False
            inv = {
                'name': order.name,
                'origin': order.name,
                'type': 'out_invoice',
                'reference': "P%dSO%d" % (order.partner_id.id, order.id),
                'account_id': a,
                'partner_id': order.partner_invoice_id.id,
                'invoice_line': [(6, 0, lines)],
                'currency_id' : order.pricelist_id.currency_id.id,
                'comment': order.note,
                'payment_term': pay_term,
                'fiscal_position': order.fiscal_position.id or order.partner_id.property_account_position.id,
                'user_id': order.user_id and order.user_id.id or False,
                'company_id': order.company_id and order.company_id.id or False,
                'date_invoice': fields.date.today(cr, uid, context=context),
            }
            inv_id = self.pool.get('account.invoice').create(cr, uid, inv)
            return inv_id

        sales_order_line_obj = self.pool.get('sale.order.line')
        sales_order_obj = self.pool.get('sale.order')
        wf_service = netsvc.LocalService('workflow')
        for line in sales_order_line_obj.browse(cr, uid, context.get('active_ids', []), context=context):
            if (not line.invoiced) and (line.state not in ('draft', 'cancel')):
                if not line.order_id.id in invoices:
                    invoices[line.order_id.id] = []
                line_id = sales_order_line_obj.invoice_line_create(cr, uid,
                        [line.id])
                for lid in line_id:
                    invoices[line.order_id.id].append((line, lid))
        for result in invoices.values():
            order = result[0][0].order_id
            il = map(lambda x: x[1], result)
            res = make_invoice(order, il)
            cr.execute('INSERT INTO sale_order_invoice_rel \
                    (order_id,invoice_id) values (%s,%s)', (order.id, res))

            flag = True
            data_sale = sales_order_obj.browse(cr, uid, line.order_id.id, context=context)
            for line in data_sale.order_line:
                if not line.invoiced:
                    flag = False
                    break
            if flag:
                wf_service.trg_validate(uid, 'sale.order', line.order_id.id, 'manual_invoice', cr)
                sales_order_obj.write(cr, uid, [line.order_id.id], {'state': 'progress'})

        if not invoices:
            raise osv.except_osv(_('Warning!'), _('Invoice cannot be created for this Sales Order Line due to one of the following reasons:\n1.The state of this sales order line is either "draft" or "cancel"!\n2.The Sales Order Line is Invoiced!'))
        if context.get('open_invoices', False):
            return self.open_invoices( cr, uid, ids, res, context=context)
        return {'type': 'ir.actions.act_window_close'}

    def open_invoices(self, cr, uid, ids, invoice_ids, context=None):
        """ open a view on one of the given invoice_ids """
        ir_model_data = self.pool.get('ir.model.data')
        form_res = ir_model_data.get_object_reference(cr, uid, 'account', 'invoice_form')
        form_id = form_res and form_res[1] or False
        tree_res = ir_model_data.get_object_reference(cr, uid, 'account', 'invoice_tree')
        tree_id = tree_res and tree_res[1] or False

        return {
            'name': _('Invoice'),
            'view_type': 'form',
            'view_mode': 'form,tree',
            'res_model': 'account.invoice',
            'res_id': invoice_ids,
            'view_id': False,
            'views': [(form_id, 'form'), (tree_id, 'tree')],
            'context': {'type': 'out_invoice'},
            'type': 'ir.actions.act_window',
        }

sale_order_line_make_invoice()

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<commit_msg>[FIX] sale: fixed wrong use of fields.date.today()<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
#    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 osv import osv, fields
from tools.translate import _
import netsvc

class sale_order_line_make_invoice(osv.osv_memory):
    _name = "sale.order.line.make.invoice"
    _description = "Sale OrderLine Make_invoice"
    def make_invoices(self, cr, uid, ids, context=None):
        """
             To make invoices.

             @param self: The object pointer.
             @param cr: A database cursor
             @param uid: ID of the user currently logged in
             @param ids: the ID or list of IDs
             @param context: A standard dictionary

             @return: A dictionary which of fields with values.

        """
        if context is None: context = {}
        res = False
        invoices = {}

    #TODO: merge with sale.py/make_invoice
        def make_invoice(order, lines):
            """
                 To make invoices.

                 @param order:
                 @param lines:

                 @return:

            """
            a = order.partner_id.property_account_receivable.id
            if order.partner_id and order.partner_id.property_payment_term.id:
                pay_term = order.partner_id.property_payment_term.id
            else:
                pay_term = False
            inv = {
                'name': order.name,
                'origin': order.name,
                'type': 'out_invoice',
                'reference': "P%dSO%d" % (order.partner_id.id, order.id),
                'account_id': a,
                'partner_id': order.partner_invoice_id.id,
                'invoice_line': [(6, 0, lines)],
                'currency_id' : order.pricelist_id.currency_id.id,
                'comment': order.note,
                'payment_term': pay_term,
                'fiscal_position': order.fiscal_position.id or order.partner_id.property_account_position.id,
                'user_id': order.user_id and order.user_id.id or False,
                'company_id': order.company_id and order.company_id.id or False,
                'date_invoice': fields.date.today(),
            }
            inv_id = self.pool.get('account.invoice').create(cr, uid, inv)
            return inv_id

        sales_order_line_obj = self.pool.get('sale.order.line')
        sales_order_obj = self.pool.get('sale.order')
        wf_service = netsvc.LocalService('workflow')
        for line in sales_order_line_obj.browse(cr, uid, context.get('active_ids', []), context=context):
            if (not line.invoiced) and (line.state not in ('draft', 'cancel')):
                if not line.order_id.id in invoices:
                    invoices[line.order_id.id] = []
                line_id = sales_order_line_obj.invoice_line_create(cr, uid,
                        [line.id])
                for lid in line_id:
                    invoices[line.order_id.id].append((line, lid))
        for result in invoices.values():
            order = result[0][0].order_id
            il = map(lambda x: x[1], result)
            res = make_invoice(order, il)
            cr.execute('INSERT INTO sale_order_invoice_rel \
                    (order_id,invoice_id) values (%s,%s)', (order.id, res))

            flag = True
            data_sale = sales_order_obj.browse(cr, uid, line.order_id.id, context=context)
            for line in data_sale.order_line:
                if not line.invoiced:
                    flag = False
                    break
            if flag:
                wf_service.trg_validate(uid, 'sale.order', line.order_id.id, 'manual_invoice', cr)
                sales_order_obj.write(cr, uid, [line.order_id.id], {'state': 'progress'})

        if not invoices:
            raise osv.except_osv(_('Warning!'), _('Invoice cannot be created for this Sales Order Line due to one of the following reasons:\n1.The state of this sales order line is either "draft" or "cancel"!\n2.The Sales Order Line is Invoiced!'))
        if context.get('open_invoices', False):
            return self.open_invoices( cr, uid, ids, res, context=context)
        return {'type': 'ir.actions.act_window_close'}

    def open_invoices(self, cr, uid, ids, invoice_ids, context=None):
        """ open a view on one of the given invoice_ids """
        ir_model_data = self.pool.get('ir.model.data')
        form_res = ir_model_data.get_object_reference(cr, uid, 'account', 'invoice_form')
        form_id = form_res and form_res[1] or False
        tree_res = ir_model_data.get_object_reference(cr, uid, 'account', 'invoice_tree')
        tree_id = tree_res and tree_res[1] or False

        return {
            'name': _('Invoice'),
            'view_type': 'form',
            'view_mode': 'form,tree',
            'res_model': 'account.invoice',
            'res_id': invoice_ids,
            'view_id': False,
            'views': [(form_id, 'form'), (tree_id, 'tree')],
            'context': {'type': 'out_invoice'},
            'type': 'ir.actions.act_window',
        }

sale_order_line_make_invoice()

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo.exceptions import UserError
from odoo import api, fields, models, _

class AccountAnalyticLine(models.Model):
    _inherit = 'account.analytic.line'

    timesheet_invoice_type = fields.Selection([
        ('billable_time', 'Billable Time'),
        ('billable_fixed', 'Billable Fixed'),
        ('non_billable', 'Non Billable')], string="Billable Type", readonly=True, copy=False)
    timesheet_invoice_id = fields.Many2one('account.invoice', string="Invoice", readonly=True, copy=False, help="Invoice created from the timesheet")
    timesheet_revenue = fields.Monetary("Revenue", default=0.0, readonly=True, currency_field='company_currency_id', copy=False)

    @api.model
    def create(self, values):
        if values.get('task_id'):
            task = self.env['project.task'].browse(values['task_id'])
            values['so_line'] = task.sale_line_id.id or values.get('so_line', False)
        values.update(self._get_timesheet_values(values))
        values.update(self._get_timesheet_billing_values(values))
        return super(AccountAnalyticLine, self).create(values)

    @api.multi
    def write(self, values):
        # prevent to update invoiced timesheets
        #if self.filtered(lambda timesheet: timesheet.timesheet_invoice_id):
        #    if any([field_name in values for field_name in ['unit_amount', 'employee_id', 'task_id', 'timesheet_revenue', 'so_line', 'amount', 'date']]):
        #        raise UserError(_('You can not modify already invoiced timesheets.'))

        so_lines = self.mapped('so_line')
        if values.get('task_id'):
            task = self.env['project.task'].browse(values['task_id'])
            values['so_line'] = task.sale_line_id.id or values.get('so_line', False)
        for line in self:
            values.update(line._get_timesheet_values(values))
            values.update(line._get_timesheet_billing_values(values))
            super(AccountAnalyticLine, line).write(values)

        # Update delivered quantity on SO lines which are not linked to the analytic lines anymore
        so_lines -= self.mapped('so_line')
        if so_lines:
            so_lines.with_context(force_so_lines=so_lines).sudo()._compute_analytic()
        return True

    def _get_timesheet_values(self, values):
        result = {}
        values = values if values is not None else {}
        if values.get('project_id') or self.project_id:
            if values.get('amount'):
                return {}
            unit_amount = values.get('unit_amount', 0.0) or self.unit_amount

            # find the employee
            employee_id = values.get('employee_id') or self.employee_id.id or (self.env.user.employee_ids and self.env.user.employee_ids[0].id or False)
            employee = self.env['hr.employee'].browse(employee_id) if employee_id else self.env['hr.employee']
            if not employee:
                user_id = values.get('user_id') or self.user_id.id or self._default_user()
                employee = self.env['hr.employee'].search([('user_id', '=', user_id)], limit=1)

            # find the analytic account
            account_id = values.get('account_id') or self.account_id.id
            if not account_id and values.get('project_id'):
                project = self.env['project.project'].browse(values['project_id'])
                account_id = project.analytic_account_id.id
            analytic_account = self.env['account.analytic.account'].browse(account_id) if account_id else self.env['account.analytic.account']

            # convert employee cost into timesheet (analytic account) currency
            uom = employee.company_id.project_time_mode_id
            cost = employee.timesheet_cost or 0.0
            amount = -unit_amount * cost
            amount_converted = employee.currency_id.compute(amount, analytic_account.currency_id)

            result.update({
                'amount': amount_converted,
                'product_uom_id': uom.id,
                'account_id': account_id,
            })
        return result

    def _get_timesheet_billing_values(self, values):
        """
            If invoice on delivered quantity:
                timesheet hours * (SO Line Price) * (1- discount),
            elif invoice on ordered quantities & create task:
                min (
                    timesheet hours * (SO Line unit price) * (1- discount),
                    TOTAL SO - TOTAL INVOICED - sum(timesheet revenues with invoice_id=False)
                )
            else:
                0
        """
        result = {}
        if self.env.context.get('create'):  # avoid bad loop
            return result

        # find the timesheet UoM
        timesheet_uom = self.product_uom_id
        if values.get('product_uom_id'):
            timesheet_uom = self.env['product.uom'].browse(values['product_uom_id'])
        if not timesheet_uom:  # fallback on default company timesheet UoM
            timesheet_uom = self.env.user.company_id.project_time_mode_id

        unit_amount = values.get('unit_amount', 0.0) or self.unit_amount
        billable_type = 'non_billable'
        revenue = 0.0

        # set the revenue and billable type according to the product and the SO line
        so_line_id = values.get('so_line') or self.so_line.id
        so_line = self.env['sale.order.line'].browse(so_line_id).sudo() if so_line_id else self.env['sale.order.line'].browse().sudo()
        if so_line.product_id.type == 'service':
            # find the analytic account to convert revenue into its currency
            account_id = values.get('account_id') or self.account_id.id
            analytic_account = self.env['account.analytic.account'].browse(account_id)
            # convert the unit of mesure into hours
            sale_price_hour = so_line.product_uom._compute_price(so_line.price_unit, timesheet_uom)
            sale_price = so_line.currency_id.compute(sale_price_hour, analytic_account.currency_id)  # amount from SO should be convert into analytic account currency
            # calculate the revenue on the timesheet
            if so_line.product_id.invoice_policy == 'delivery':
                revenue = analytic_account.currency_id.round(unit_amount * sale_price * (1-(so_line.discount/100)))
                billable_type = 'billable_time'
            elif so_line.product_id.invoice_policy == 'order' and so_line.product_id.track_service == 'task':
                quantity_hour = so_line.product_uom._compute_quantity(so_line.product_uom_qty, timesheet_uom)
                # compute the total revenue the SO since we are in fixed price
                total_revenue_so = analytic_account.currency_id.round(quantity_hour * sale_price * (1-(so_line.discount/100)))
                # compute the total revenue already existing (without the current timesheet line)
                domain = [('so_line', '=', so_line.id)]
                if self.ids:
                    domain += [('id', 'not in', self.ids)]
                analytic_lines = self.sudo().search(domain)
                total_revenue_invoiced = sum(analytic_lines.mapped('timesheet_revenue'))
                # compute (new) revenue of current timesheet line
                revenue = min(
                    analytic_account.currency_id.round(unit_amount * so_line.currency_id.compute(so_line.price_unit, analytic_account.currency_id) * (1-so_line.discount)),
                    total_revenue_so - total_revenue_invoiced
                )
                billable_type = 'billable_fixed'
        result['timesheet_revenue'] = revenue
        result['timesheet_invoice_type'] = billable_type
        return result

    def _get_sale_order_line(self, vals=None):
        result = dict(vals or {})
        if self.project_id:
            if result.get('so_line'):
                sol = self.env['sale.order.line'].browse([result['so_line']])
            else:
                sol = self.so_line
            if not sol:
                sol = self.env['sale.order.line'].search([
                    ('order_id.project_id', '=', self.account_id.id),
                    ('state', 'in', ('sale', 'done')),
                    ('product_id.track_service', '=', 'timesheet'),
                    ('product_id.type', '=', 'service')],
                    limit=1)
            if sol:
                result.update({
                    'so_line': sol.id,
                    'product_id': sol.product_id.id,
                })
                result.update(self._get_timesheet_values(result))

        return super(AccountAnalyticLine, self)._get_sale_order_line(vals=result)
<commit_msg>[FIX] sale_timesheet: uncomment forgotten code when testing previous fix<commit_after># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo.exceptions import UserError
from odoo import api, fields, models, _

class AccountAnalyticLine(models.Model):
    _inherit = 'account.analytic.line'

    timesheet_invoice_type = fields.Selection([
        ('billable_time', 'Billable Time'),
        ('billable_fixed', 'Billable Fixed'),
        ('non_billable', 'Non Billable')], string="Billable Type", readonly=True, copy=False)
    timesheet_invoice_id = fields.Many2one('account.invoice', string="Invoice", readonly=True, copy=False, help="Invoice created from the timesheet")
    timesheet_revenue = fields.Monetary("Revenue", default=0.0, readonly=True, currency_field='company_currency_id', copy=False)

    @api.model
    def create(self, values):
        if values.get('task_id'):
            task = self.env['project.task'].browse(values['task_id'])
            values['so_line'] = task.sale_line_id.id or values.get('so_line', False)
        values.update(self._get_timesheet_values(values))
        values.update(self._get_timesheet_billing_values(values))
        return super(AccountAnalyticLine, self).create(values)

    @api.multi
    def write(self, values):
        # prevent to update invoiced timesheets
        if self.filtered(lambda timesheet: timesheet.timesheet_invoice_id):
            if any([field_name in values for field_name in ['unit_amount', 'employee_id', 'task_id', 'timesheet_revenue', 'so_line', 'amount', 'date']]):
                raise UserError(_('You can not modify already invoiced timesheets.'))

        so_lines = self.mapped('so_line')
        if values.get('task_id'):
            task = self.env['project.task'].browse(values['task_id'])
            values['so_line'] = task.sale_line_id.id or values.get('so_line', False)
        for line in self:
            values.update(line._get_timesheet_values(values))
            values.update(line._get_timesheet_billing_values(values))
            super(AccountAnalyticLine, line).write(values)

        # Update delivered quantity on SO lines which are not linked to the analytic lines anymore
        so_lines -= self.mapped('so_line')
        if so_lines:
            so_lines.with_context(force_so_lines=so_lines).sudo()._compute_analytic()
        return True

    def _get_timesheet_values(self, values):
        result = {}
        values = values if values is not None else {}
        if values.get('project_id') or self.project_id:
            if values.get('amount'):
                return {}
            unit_amount = values.get('unit_amount', 0.0) or self.unit_amount

            # find the employee
            employee_id = values.get('employee_id') or self.employee_id.id or (self.env.user.employee_ids and self.env.user.employee_ids[0].id or False)
            employee = self.env['hr.employee'].browse(employee_id) if employee_id else self.env['hr.employee']
            if not employee:
                user_id = values.get('user_id') or self.user_id.id or self._default_user()
                employee = self.env['hr.employee'].search([('user_id', '=', user_id)], limit=1)

            # find the analytic account
            account_id = values.get('account_id') or self.account_id.id
            if not account_id and values.get('project_id'):
                project = self.env['project.project'].browse(values['project_id'])
                account_id = project.analytic_account_id.id
            analytic_account = self.env['account.analytic.account'].browse(account_id) if account_id else self.env['account.analytic.account']

            # convert employee cost into timesheet (analytic account) currency
            uom = employee.company_id.project_time_mode_id
            cost = employee.timesheet_cost or 0.0
            amount = -unit_amount * cost
            amount_converted = employee.currency_id.compute(amount, analytic_account.currency_id)

            result.update({
                'amount': amount_converted,
                'product_uom_id': uom.id,
                'account_id': account_id,
            })
        return result

    def _get_timesheet_billing_values(self, values):
        """
            If invoice on delivered quantity:
                timesheet hours * (SO Line Price) * (1- discount),
            elif invoice on ordered quantities & create task:
                min (
                    timesheet hours * (SO Line unit price) * (1- discount),
                    TOTAL SO - TOTAL INVOICED - sum(timesheet revenues with invoice_id=False)
                )
            else:
                0
        """
        result = {}
        if self.env.context.get('create'):  # avoid bad loop
            return result

        # find the timesheet UoM
        timesheet_uom = self.product_uom_id
        if values.get('product_uom_id'):
            timesheet_uom = self.env['product.uom'].browse(values['product_uom_id'])
        if not timesheet_uom:  # fallback on default company timesheet UoM
            timesheet_uom = self.env.user.company_id.project_time_mode_id

        unit_amount = values.get('unit_amount', 0.0) or self.unit_amount
        billable_type = 'non_billable'
        revenue = 0.0

        # set the revenue and billable type according to the product and the SO line
        so_line_id = values.get('so_line') or self.so_line.id
        so_line = self.env['sale.order.line'].browse(so_line_id).sudo() if so_line_id else self.env['sale.order.line'].browse().sudo()
        if so_line.product_id.type == 'service':
            # find the analytic account to convert revenue into its currency
            account_id = values.get('account_id') or self.account_id.id
            analytic_account = self.env['account.analytic.account'].browse(account_id)
            # convert the unit of mesure into hours
            sale_price_hour = so_line.product_uom._compute_price(so_line.price_unit, timesheet_uom)
            sale_price = so_line.currency_id.compute(sale_price_hour, analytic_account.currency_id)  # amount from SO should be convert into analytic account currency
            # calculate the revenue on the timesheet
            if so_line.product_id.invoice_policy == 'delivery':
                revenue = analytic_account.currency_id.round(unit_amount * sale_price * (1-(so_line.discount/100)))
                billable_type = 'billable_time'
            elif so_line.product_id.invoice_policy == 'order' and so_line.product_id.track_service == 'task':
                quantity_hour = so_line.product_uom._compute_quantity(so_line.product_uom_qty, timesheet_uom)
                # compute the total revenue the SO since we are in fixed price
                total_revenue_so = analytic_account.currency_id.round(quantity_hour * sale_price * (1-(so_line.discount/100)))
                # compute the total revenue already existing (without the current timesheet line)
                domain = [('so_line', '=', so_line.id)]
                if self.ids:
                    domain += [('id', 'not in', self.ids)]
                analytic_lines = self.sudo().search(domain)
                total_revenue_invoiced = sum(analytic_lines.mapped('timesheet_revenue'))
                # compute (new) revenue of current timesheet line
                revenue = min(
                    analytic_account.currency_id.round(unit_amount * so_line.currency_id.compute(so_line.price_unit, analytic_account.currency_id) * (1-so_line.discount)),
                    total_revenue_so - total_revenue_invoiced
                )
                billable_type = 'billable_fixed'
        result['timesheet_revenue'] = revenue
        result['timesheet_invoice_type'] = billable_type
        return result

    def _get_sale_order_line(self, vals=None):
        result = dict(vals or {})
        if self.project_id:
            if result.get('so_line'):
                sol = self.env['sale.order.line'].browse([result['so_line']])
            else:
                sol = self.so_line
            if not sol:
                sol = self.env['sale.order.line'].search([
                    ('order_id.project_id', '=', self.account_id.id),
                    ('state', 'in', ('sale', 'done')),
                    ('product_id.track_service', '=', 'timesheet'),
                    ('product_id.type', '=', 'service')],
                    limit=1)
            if sol:
                result.update({
                    'so_line': sol.id,
                    'product_id': sol.product_id.id,
                })
                result.update(self._get_timesheet_values(result))

        return super(AccountAnalyticLine, self)._get_sale_order_line(vals=result)
<|endoftext|>


<commit_before><commit_msg>fix bug in keyword mapping<commit_after><|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo.exceptions import UserError, ValidationError

from odoo import api, fields, models, _
from odoo.osv import expression

class AccountAnalyticLine(models.Model):
    _inherit = 'account.analytic.line'

    def _default_sale_line_domain(self):
        domain = super(AccountAnalyticLine, self)._default_sale_line_domain()
        return expression.OR([domain, [('qty_delivered_method', '=', 'timesheet')]])

    timesheet_invoice_type = fields.Selection([
        ('billable_time', 'Billable Time'),
        ('billable_fixed', 'Billable Fixed'),
        ('non_billable', 'Non Billable'),
        ('non_billable_project', 'No task found')], string="Billable Type", compute='_compute_timesheet_invoice_type', compute_sudo=True, store=True, readonly=True)
    timesheet_invoice_id = fields.Many2one('account.invoice', string="Invoice", readonly=True, copy=False, help="Invoice created from the timesheet")

    @api.multi
    @api.depends('so_line.product_id', 'project_id', 'task_id')
    def _compute_timesheet_invoice_type(self):
        for timesheet in self:
            if timesheet.project_id:  # AAL will be set to False
                invoice_type = 'non_billable_project' if not timesheet.task_id else 'non_billable'
                if timesheet.task_id and timesheet.so_line.product_id.type == 'service':
                    if timesheet.so_line.product_id.invoice_policy == 'delivery':
                        if timesheet.so_line.product_id.service_type == 'timesheet':
                            invoice_type = 'billable_time'
                        else:
                            invoice_type = 'billable_fixed'
                    elif timesheet.so_line.product_id.invoice_policy == 'order':
                        invoice_type = 'billable_fixed'
                timesheet.timesheet_invoice_type = invoice_type

    @api.onchange('employee_id')
    def _onchange_task_id_employee_id(self):
        if self.project_id:  # timesheet only
            if self.task_id.billable_type == 'task_rate':
                self.so_line = self.task_id.sale_line_id
            elif self.task_id.billable_type == 'employee_rate':
                self.so_line = self._timesheet_determine_sale_line(self.task_id, self.employee_id)
            else:
                self.so_line = False

    @api.constrains('so_line', 'project_id')
    def _check_sale_line_in_project_map(self):
        for timesheet in self:
            if timesheet.project_id and timesheet.so_line:  # billed timesheet
                if timesheet.so_line not in timesheet.project_id.mapped('sale_line_employee_ids.sale_line_id') | timesheet.task_id.sale_line_id | timesheet.project_id.sale_line_id:
                    raise ValidationError(_("This timesheet line cannot be billed: there is no Sale Order Item defined on the task, nor on the project. Please define one to save your timesheet line."))

    @api.multi
    def write(self, values):
        # prevent to update invoiced timesheets if one line is of type delivery
        if self.sudo().filtered(lambda aal: aal.so_line.product_id.invoice_policy == "delivery") and self.filtered(lambda timesheet: timesheet.timesheet_invoice_id):
            if any([field_name in values for field_name in ['unit_amount', 'employee_id', 'project_id', 'task_id', 'so_line', 'amount', 'date']]):
                raise UserError(_('You can not modify already invoiced timesheets (linked to a Sales order items invoiced on Time and material).'))
        result = super(AccountAnalyticLine, self).write(values)
        return result

    @api.model
    def _timesheet_preprocess(self, values):
        values = super(AccountAnalyticLine, self)._timesheet_preprocess(values)
        # task implies so line (at create)
        if 'task_id' in values and not values.get('so_line') and values.get('employee_id'):
            task = self.env['project.task'].sudo().browse(values['task_id'])
            employee = self.env['hr.employee'].sudo().browse(values['employee_id'])
            values['so_line'] = self._timesheet_determine_sale_line(task, employee).id
        return values

    @api.multi
    def _timesheet_postprocess_values(self, values):
        result = super(AccountAnalyticLine, self)._timesheet_postprocess_values(values)
        # (re)compute the sale line
        if any([field_name in values for field_name in ['task_id', 'employee_id']]):
            for timesheet in self:
                result[timesheet.id].update({
                    'so_line': timesheet._timesheet_determine_sale_line(timesheet.task_id, timesheet.employee_id).id,
                })
        return result

    @api.model
    def _timesheet_determine_sale_line(self, task, employee):
        """ Deduce the SO line associated to the timesheet line:
            1/ timesheet on task rate: the so line will be the one from the task
            2/ timesheet on employee rate task: find the SO line in the map of the project (even for subtask), or fallback on the SO line of the task, or fallback
                on the one on the project
            NOTE: this have to be consistent with `_compute_billable_type` on project.task.
        """
        if task.billable_type != 'no':
            if task.billable_type == 'employee_rate':
                map_entry = self.env['project.sale.line.employee.map'].search([('project_id', '=', task.project_id.id), ('employee_id', '=', employee.id)])
                if map_entry:
                    return map_entry.sale_line_id
                if task.sale_line_id:
                    return task.sale_line_id
                return task.project_id.sale_line_id
            elif task.billable_type == 'task_rate':
                return task.sale_line_id
        return self.env['sale.order.line']
<commit_msg>[FIX] sale_timesheet: extract the check on write in a function<commit_after># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo.exceptions import UserError, ValidationError

from odoo import api, fields, models, _
from odoo.osv import expression

class AccountAnalyticLine(models.Model):
    _inherit = 'account.analytic.line'

    def _default_sale_line_domain(self):
        domain = super(AccountAnalyticLine, self)._default_sale_line_domain()
        return expression.OR([domain, [('qty_delivered_method', '=', 'timesheet')]])

    timesheet_invoice_type = fields.Selection([
        ('billable_time', 'Billable Time'),
        ('billable_fixed', 'Billable Fixed'),
        ('non_billable', 'Non Billable'),
        ('non_billable_project', 'No task found')], string="Billable Type", compute='_compute_timesheet_invoice_type', compute_sudo=True, store=True, readonly=True)
    timesheet_invoice_id = fields.Many2one('account.invoice', string="Invoice", readonly=True, copy=False, help="Invoice created from the timesheet")

    @api.multi
    @api.depends('so_line.product_id', 'project_id', 'task_id')
    def _compute_timesheet_invoice_type(self):
        for timesheet in self:
            if timesheet.project_id:  # AAL will be set to False
                invoice_type = 'non_billable_project' if not timesheet.task_id else 'non_billable'
                if timesheet.task_id and timesheet.so_line.product_id.type == 'service':
                    if timesheet.so_line.product_id.invoice_policy == 'delivery':
                        if timesheet.so_line.product_id.service_type == 'timesheet':
                            invoice_type = 'billable_time'
                        else:
                            invoice_type = 'billable_fixed'
                    elif timesheet.so_line.product_id.invoice_policy == 'order':
                        invoice_type = 'billable_fixed'
                timesheet.timesheet_invoice_type = invoice_type

    @api.onchange('employee_id')
    def _onchange_task_id_employee_id(self):
        if self.project_id:  # timesheet only
            if self.task_id.billable_type == 'task_rate':
                self.so_line = self.task_id.sale_line_id
            elif self.task_id.billable_type == 'employee_rate':
                self.so_line = self._timesheet_determine_sale_line(self.task_id, self.employee_id)
            else:
                self.so_line = False

    @api.constrains('so_line', 'project_id')
    def _check_sale_line_in_project_map(self):
        for timesheet in self:
            if timesheet.project_id and timesheet.so_line:  # billed timesheet
                if timesheet.so_line not in timesheet.project_id.mapped('sale_line_employee_ids.sale_line_id') | timesheet.task_id.sale_line_id | timesheet.project_id.sale_line_id:
                    raise ValidationError(_("This timesheet line cannot be billed: there is no Sale Order Item defined on the task, nor on the project. Please define one to save your timesheet line."))

    @api.multi
    def write(self, values):
        # prevent to update invoiced timesheets if one line is of type delivery
        self._check_can_write(values)
        result = super(AccountAnalyticLine, self).write(values)
        return result

    @api.multi
    def _check_can_write(self, values):
        if self.sudo().filtered(lambda aal: aal.so_line.product_id.invoice_policy == "delivery") and self.filtered(lambda timesheet: timesheet.timesheet_invoice_id):
            if any([field_name in values for field_name in ['unit_amount', 'employee_id', 'project_id', 'task_id', 'so_line', 'amount', 'date']]):
                raise UserError(_('You can not modify already invoiced timesheets (linked to a Sales order items invoiced on Time and material).'))

    @api.model
    def _timesheet_preprocess(self, values):
        values = super(AccountAnalyticLine, self)._timesheet_preprocess(values)
        # task implies so line (at create)
        if 'task_id' in values and not values.get('so_line') and values.get('employee_id'):
            task = self.env['project.task'].sudo().browse(values['task_id'])
            employee = self.env['hr.employee'].sudo().browse(values['employee_id'])
            values['so_line'] = self._timesheet_determine_sale_line(task, employee).id
        return values

    @api.multi
    def _timesheet_postprocess_values(self, values):
        result = super(AccountAnalyticLine, self)._timesheet_postprocess_values(values)
        # (re)compute the sale line
        if any([field_name in values for field_name in ['task_id', 'employee_id']]):
            for timesheet in self:
                result[timesheet.id].update({
                    'so_line': timesheet._timesheet_determine_sale_line(timesheet.task_id, timesheet.employee_id).id,
                })
        return result

    @api.model
    def _timesheet_determine_sale_line(self, task, employee):
        """ Deduce the SO line associated to the timesheet line:
            1/ timesheet on task rate: the so line will be the one from the task
            2/ timesheet on employee rate task: find the SO line in the map of the project (even for subtask), or fallback on the SO line of the task, or fallback
                on the one on the project
            NOTE: this have to be consistent with `_compute_billable_type` on project.task.
        """
        if task.billable_type != 'no':
            if task.billable_type == 'employee_rate':
                map_entry = self.env['project.sale.line.employee.map'].search([('project_id', '=', task.project_id.id), ('employee_id', '=', employee.id)])
                if map_entry:
                    return map_entry.sale_line_id
                if task.sale_line_id:
                    return task.sale_line_id
                return task.project_id.sale_line_id
            elif task.billable_type == 'task_rate':
                return task.sale_line_id
        return self.env['sale.order.line']
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import api, fields, models, _
from odoo.exceptions import ValidationError

class ProductTemplate(models.Model):
    _inherit = 'product.template'

    service_policy = fields.Selection([
        ('ordered_timesheet', 'Ordered quantities'),
        ('delivered_timesheet', 'Timesheets on tasks'),
        ('delivered_manual', 'Milestones (manually set quantities on order)')
    ], string="Service Invoicing Policy", compute='_compute_service_policy', inverse='_inverse_service_policy')
    service_type = fields.Selection(selection_add=[
        ('timesheet', 'Timesheets on project (one fare per SO/Project)'),
    ])
    service_tracking = fields.Selection([
        ('no', 'Don\'t create task'),
        ('task_global_project', 'Create a task in an existing project'),
        ('task_new_project', 'Create a task in a new project'),
        ('project_only', 'Create a new project but no task'),
    ], string="Service Tracking", default="no",
       help="On Sales order confirmation, this product can generate a project and/or task. From those, you can track the service you are selling.")
    project_id = fields.Many2one(
        'project.project', 'Project', company_dependent=True, domain=[('billable_type', '=', 'no')],
        help='Select a non billable project on which tasks can be created. This setting must be set for each company.')
    project_template_id = fields.Many2one(
        'project.project', 'Project Template', company_dependent=True, domain=[('billable_type', '=', 'no')], copy=True,
        help='Select a non billable project to be the skeleton of the new created project when selling the current product. Its stages and tasks will be duplicated.')

    @api.depends('invoice_policy', 'service_type')
    def _compute_service_policy(self):
        for product in self:
            policy = None
            if product.invoice_policy == 'delivery':
                policy = 'delivered_manual' if product.service_type == 'manual' else 'delivered_timesheet'
            elif product.invoice_policy == 'order' and product.service_type == 'timesheet':
                policy = 'ordered_timesheet'
            product.service_policy = policy

    def _inverse_service_policy(self):
        for product in self:
            policy = product.service_policy
            if not policy and not product.invoice_policy =='delivery':
                product.invoice_policy = 'order'
                product.service_type = 'manual'
            elif policy == 'ordered_timesheet':
                product.invoice_policy = 'order'
                product.service_type = 'timesheet'
            else:
                product.invoice_policy = 'delivery'
                product.service_type = 'manual' if policy == 'delivered_manual' else 'timesheet'

    @api.constrains('project_id', 'project_template_id')
    def _check_project_and_template(self):
        """ NOTE 'service_tracking' should be in decorator parameters but since ORM check constraints twice (one after setting
            stored fields, one after setting non stored field), the error is raised when company-dependent fields are not set.
            So, this constraints does cover all cases and inconsistent can still be recorded until the ORM change its behavior.
        """
        for product in self:
            if product.service_tracking == 'no' and (product.project_id or product.project_template_id):
                raise ValidationError(_('The product %s should not have a project nor a project template since it will not generate project.') % (product.name,))
            elif product.service_tracking == 'task_global_project' and product.project_template_id:
                raise ValidationError(_('The product %s should not have a project template since it will generate a task in a global project.') % (product.name,))
            elif product.service_tracking in ['task_new_project', 'project_only'] and product.project_id:
                raise ValidationError(_('The product %s should not have a global project since it will generate a project.') % (product.name,))

    @api.onchange('service_tracking')
    def _onchange_service_tracking(self):
        if self.service_tracking == 'no':
            self.project_id = False
            self.project_template_id = False
        elif self.service_tracking == 'task_global_project':
            self.project_template_id = False
        elif self.service_tracking in ['task_new_project', 'project_only']:
            self.project_id = False

    @api.onchange('type')
    def _onchange_type(self):
        super(ProductTemplate, self)._onchange_type()
        if self.type == 'service':
            self.invoice_policy = 'order'
            self.service_type = 'timesheet'
        elif self.type == 'consu' and self.service_policy == 'ordered_timesheet':
            self.invoice_policy = 'order'
<commit_msg>[FIX] sale_timesheet: missing onchange<commit_after># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import api, fields, models, _
from odoo.exceptions import ValidationError

class ProductTemplate(models.Model):
    _inherit = 'product.template'

    service_policy = fields.Selection([
        ('ordered_timesheet', 'Ordered quantities'),
        ('delivered_timesheet', 'Timesheets on tasks'),
        ('delivered_manual', 'Milestones (manually set quantities on order)')
    ], string="Service Invoicing Policy", compute='_compute_service_policy', inverse='_inverse_service_policy')
    service_type = fields.Selection(selection_add=[
        ('timesheet', 'Timesheets on project (one fare per SO/Project)'),
    ])
    service_tracking = fields.Selection([
        ('no', 'Don\'t create task'),
        ('task_global_project', 'Create a task in an existing project'),
        ('task_new_project', 'Create a task in a new project'),
        ('project_only', 'Create a new project but no task'),
    ], string="Service Tracking", default="no",
       help="On Sales order confirmation, this product can generate a project and/or task. From those, you can track the service you are selling.")
    project_id = fields.Many2one(
        'project.project', 'Project', company_dependent=True, domain=[('billable_type', '=', 'no')],
        help='Select a non billable project on which tasks can be created. This setting must be set for each company.')
    project_template_id = fields.Many2one(
        'project.project', 'Project Template', company_dependent=True, domain=[('billable_type', '=', 'no')], copy=True,
        help='Select a non billable project to be the skeleton of the new created project when selling the current product. Its stages and tasks will be duplicated.')

    @api.depends('invoice_policy', 'service_type')
    def _compute_service_policy(self):
        for product in self:
            policy = None
            if product.invoice_policy == 'delivery':
                policy = 'delivered_manual' if product.service_type == 'manual' else 'delivered_timesheet'
            elif product.invoice_policy == 'order' and product.service_type == 'timesheet':
                policy = 'ordered_timesheet'
            product.service_policy = policy

    def _inverse_service_policy(self):
        for product in self:
            policy = product.service_policy
            if not policy and not product.invoice_policy =='delivery':
                product.invoice_policy = 'order'
                product.service_type = 'manual'
            elif policy == 'ordered_timesheet':
                product.invoice_policy = 'order'
                product.service_type = 'timesheet'
            else:
                product.invoice_policy = 'delivery'
                product.service_type = 'manual' if policy == 'delivered_manual' else 'timesheet'

    @api.constrains('project_id', 'project_template_id')
    def _check_project_and_template(self):
        """ NOTE 'service_tracking' should be in decorator parameters but since ORM check constraints twice (one after setting
            stored fields, one after setting non stored field), the error is raised when company-dependent fields are not set.
            So, this constraints does cover all cases and inconsistent can still be recorded until the ORM change its behavior.
        """
        for product in self:
            if product.service_tracking == 'no' and (product.project_id or product.project_template_id):
                raise ValidationError(_('The product %s should not have a project nor a project template since it will not generate project.') % (product.name,))
            elif product.service_tracking == 'task_global_project' and product.project_template_id:
                raise ValidationError(_('The product %s should not have a project template since it will generate a task in a global project.') % (product.name,))
            elif product.service_tracking in ['task_new_project', 'project_only'] and product.project_id:
                raise ValidationError(_('The product %s should not have a global project since it will generate a project.') % (product.name,))

    @api.onchange('service_tracking')
    def _onchange_service_tracking(self):
        if self.service_tracking == 'no':
            self.project_id = False
            self.project_template_id = False
        elif self.service_tracking == 'task_global_project':
            self.project_template_id = False
        elif self.service_tracking in ['task_new_project', 'project_only']:
            self.project_id = False

    @api.onchange('type')
    def _onchange_type(self):
        super(ProductTemplate, self)._onchange_type()
        if self.type == 'service':
            self.invoice_policy = 'order'
            self.service_type = 'timesheet'
        elif self.type == 'consu' and self.service_policy == 'ordered_timesheet':
            self.invoice_policy = 'order'

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

    @api.onchange('service_tracking')
    def _onchange_service_tracking(self):
        if self.service_tracking == 'no':
            self.project_id = False
            self.project_template_id = False
        elif self.service_tracking == 'task_global_project':
            self.project_template_id = False
        elif self.service_tracking in ['task_new_project', 'project_only']:
            self.project_id = False
<|endoftext|>


<commit_before>## Copyright 2017 Knossos authors, see NOTICE file
##
## 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.

from __future__ import absolute_import, print_function

import sys
import os
import logging
import ctypes
import shlex
import six

from . import center, qt, launcher

class Integration(object):

    def shutdown(self):
        pass

    def show_progress(self, value):
        pass

    def set_progress(self, value):
        pass

    def hide_progress(self):
        pass

    def annoy_user(self, activate=True):
        pass

    def install_scheme_handler(self):
        pass

class LinuxIntegration(Integration):

    def install_scheme_handler(self):
        my_cmd = launcher.get_cmd()

        tpl_desktop = r"""[Desktop Entry]
Name=Knossos
Exec={PATH} %U
Icon={ICON_PATH}
Type=Application
Terminal=false
MimeType=x-scheme-handler/fso;
"""

        tpl_mime_type = 'x-scheme-handler/fso=Knossos.desktop;'

        applications_path = os.path.expanduser('~/.local/share/applications/')
        desktop_file = applications_path + 'knossos.desktop'
        mime_types_file = applications_path + 'mimeapps.list'
        my_path = ' '.join([shlex.quote(p) for p in my_cmd])

        if os.path.isfile(desktop_file) or os.path.isfile('/usr/share/applications/knossos.desktop'):
            return True

        tpl_desktop = tpl_desktop.replace('{PATH}', my_path)
        tpl_desktop = tpl_desktop.replace('{ICON_PATH}', launcher.get_file_path('hlp.png'))

        if not os.path.isdir(applications_path):
            os.makedirs(applications_path)

        with open(desktop_file, 'w') as output_file:
            output_file.write(tpl_desktop)

        found = False
        if os.path.isfile(mime_types_file):
            with open(mime_types_file, 'r') as lines:
                for line in lines:
                    if tpl_mime_type in line:
                        found = True
                        break

        if not found:
            with open(mime_types_file, 'a') as output_file:
                output_file.write(tpl_mime_type)

        return True

class UnityIntegration(LinuxIntegration):
    launcher = None

    def __init__(self, Unity):
        self.launcher = Unity.LauncherEntry.get_for_desktop_id('knossos.desktop')

    def show_progress(self, value):
        self.launcher.set_property('progress_visible', True)
        self.set_progress(value)

    def set_progress(self, value):
        self.launcher.set_property('progress', value)

    def hide_progress(self):
        self.launcher.set_property('progress_visible', False)

    def annoy_user(self, activate=True):
        self.launcher.set_property('urgent', activate)

class WindowsIntegration(Integration):
    TBPF_NOPROGRESS = 0x0
    TBPF_INDETERMINATE = 0x1
    TBPF_NORMAL = 0x2
    TBPF_ERROR = 0x4
    TBPF_PAUSED = 0x8

    taskbar = None
    _hwnd = None
    _win = None

    def __init__(self, taskbar):
        self.taskbar = taskbar
        taskbar.HrInit()

    def wid(self):
        win = center.main_win.win
        if win != self._win:
            self._hwnd = win.winId()
            self._win = win

        return self._hwnd

    def show_progress(self, value):
        self.taskbar.SetProgressState(self.wid(), self.TBPF_NORMAL)
        self.set_progress(value)

    def set_progress(self, value):
        self.taskbar.SetProgressValue(self.wid(), int(value * 100), 100)

    def hide_progress(self):
        self.taskbar.SetProgressState(self.wid(), self.TBPF_NOPROGRESS)

    def annoy_user(self, activate=True):
        pass

    def install_scheme_handler(self):
        my_cmd = launcher.get_cmd()

        settings = qt.QtCore.QSettings('HKEY_CLASSES_ROOT\\fso', qt.QtCore.QSettings.NativeFormat)
        settings.setFallbacksEnabled(False)

        settings.setValue('Default', 'URL:Knossos protocol')
        settings.setValue('URL Protocol', '')
        settings.setValue('DefaultIcon/Default', '"' + launcher.get_file_path('hlp.ico') + ',1"')

        my_cmd.append('%1')
        my_path = ' '.join(['"' + p + '"' for p in my_cmd])

        settings.setValue('shell/open/command/Default', my_path)

        # Check
        # FIXME: Is there any better way to detect whether this worked or not?

        settings.sync()
        settings = qt.QtCore.QSettings('HKEY_CLASSES_ROOT\\fso', qt.QtCore.QSettings.NativeFormat)
        settings.setFallbacksEnabled(False)

        return settings.value('shell/open/command/Default') == my_path

current = None

def init():
    global current

    if sys.platform.startswith('win'):
        try:
            import comtypes.client as cc

            tbl = cc.GetModule('taskbar.tlb')
            taskbar = cc.CreateObject('{56FDF344-FD6D-11d0-958A-006097C9A090}', interface=tbl.ITaskbarList3)
        except:
            logging.exception('Failed to load ITaskbarList3! Disabling Windows integration.')
        else:
            logging.info('Activating Windows integration...')
            current = WindowsIntegration(taskbar)
            return
    elif sys.platform.startswith('linux'):
        try:
            from gi.repository import Unity
        except ImportError:
            # Can't find Unity.
            pass
        else:
            logging.info('Activating Unity integration...')
            current = UnityIntegration(Unity)
            return

        logging.info('Activating generic Linux integration...')
        current = LinuxIntegration()
        return

    logging.warning('No desktop integration active.')
    current = Integration()
<commit_msg>Make sure the UnityIntegration can't cause uncaught exceptions.<commit_after>## Copyright 2017 Knossos authors, see NOTICE file
##
## 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.

from __future__ import absolute_import, print_function

import sys
import os
import logging
import shlex

from . import center, qt, launcher

class Integration(object):

    def shutdown(self):
        pass

    def show_progress(self, value):
        pass

    def set_progress(self, value):
        pass

    def hide_progress(self):
        pass

    def annoy_user(self, activate=True):
        pass

    def install_scheme_handler(self):
        pass

class LinuxIntegration(Integration):

    def install_scheme_handler(self):
        my_cmd = launcher.get_cmd()

        tpl_desktop = r"""[Desktop Entry]
Name=Knossos
Exec={PATH} %U
Icon={ICON_PATH}
Type=Application
Terminal=false
MimeType=x-scheme-handler/fso;
"""

        tpl_mime_type = 'x-scheme-handler/fso=Knossos.desktop;'

        applications_path = os.path.expanduser('~/.local/share/applications/')
        desktop_file = applications_path + 'knossos.desktop'
        mime_types_file = applications_path + 'mimeapps.list'
        my_path = ' '.join([shlex.quote(p) for p in my_cmd])

        if os.path.isfile(desktop_file) or os.path.isfile('/usr/share/applications/knossos.desktop'):
            return True

        tpl_desktop = tpl_desktop.replace('{PATH}', my_path)
        tpl_desktop = tpl_desktop.replace('{ICON_PATH}', launcher.get_file_path('hlp.png'))

        if not os.path.isdir(applications_path):
            os.makedirs(applications_path)

        with open(desktop_file, 'w') as output_file:
            output_file.write(tpl_desktop)

        found = False
        if os.path.isfile(mime_types_file):
            with open(mime_types_file, 'r') as lines:
                for line in lines:
                    if tpl_mime_type in line:
                        found = True
                        break

        if not found:
            with open(mime_types_file, 'a') as output_file:
                output_file.write(tpl_mime_type)

        return True

class UnityIntegration(LinuxIntegration):
    launcher = None

    def __init__(self, Unity):
        try:
            self.launcher = Unity.LauncherEntry.get_for_desktop_id('knossos.desktop')
        except:
            self.launcher = None
            logging.exception('Failed to initialize LauncherEntry for Unity.')

    def show_progress(self, value):
        if self.launcher:
            try:
                self.launcher.set_property('progress_visible', True)
                self.set_progress(value)
            except:
                logging.exception('Setting progress_visible for Unity failed!')

    def set_progress(self, value):
        if self.launcher:
            try:
                self.launcher.set_property('progress', value)
            except:
                logging.exception('Setting progress for Unity failed!')

    def hide_progress(self):
        if self.launcher:
            try:
                self.launcher.set_property('progress_visible', False)
            except:
                logging.exception('Setting progress_visible for Unity failed!')

    def annoy_user(self, activate=True):
        if self.launcher:
            try:
                self.launcher.set_property('urgent', activate)
            except:
                logging.exception('Setting urgent for Unity failed!')

class WindowsIntegration(Integration):
    TBPF_NOPROGRESS = 0x0
    TBPF_INDETERMINATE = 0x1
    TBPF_NORMAL = 0x2
    TBPF_ERROR = 0x4
    TBPF_PAUSED = 0x8

    taskbar = None
    _hwnd = None
    _win = None

    def __init__(self, taskbar):
        self.taskbar = taskbar
        taskbar.HrInit()

    def wid(self):
        win = center.main_win.win
        if win != self._win:
            self._hwnd = win.winId()
            self._win = win

        return self._hwnd

    def show_progress(self, value):
        self.taskbar.SetProgressState(self.wid(), self.TBPF_NORMAL)
        self.set_progress(value)

    def set_progress(self, value):
        self.taskbar.SetProgressValue(self.wid(), int(value * 100), 100)

    def hide_progress(self):
        self.taskbar.SetProgressState(self.wid(), self.TBPF_NOPROGRESS)

    def annoy_user(self, activate=True):
        pass

    def install_scheme_handler(self):
        my_cmd = launcher.get_cmd()

        settings = qt.QtCore.QSettings('HKEY_CLASSES_ROOT\\fso', qt.QtCore.QSettings.NativeFormat)
        settings.setFallbacksEnabled(False)

        settings.setValue('Default', 'URL:Knossos protocol')
        settings.setValue('URL Protocol', '')
        settings.setValue('DefaultIcon/Default', '"' + launcher.get_file_path('hlp.ico') + ',1"')

        my_cmd.append('%1')
        my_path = ' '.join(['"' + p + '"' for p in my_cmd])

        settings.setValue('shell/open/command/Default', my_path)

        # Check
        # FIXME: Is there any better way to detect whether this worked or not?

        settings.sync()
        settings = qt.QtCore.QSettings('HKEY_CLASSES_ROOT\\fso', qt.QtCore.QSettings.NativeFormat)
        settings.setFallbacksEnabled(False)

        return settings.value('shell/open/command/Default') == my_path

current = None

def init():
    global current

    if sys.platform.startswith('win'):
        try:
            import comtypes.client as cc

            tbl = cc.GetModule('taskbar.tlb')
            taskbar = cc.CreateObject('{56FDF344-FD6D-11d0-958A-006097C9A090}', interface=tbl.ITaskbarList3)
        except:
            logging.exception('Failed to load ITaskbarList3! Disabling Windows integration.')
        else:
            logging.info('Activating Windows integration...')
            current = WindowsIntegration(taskbar)
            return
    elif sys.platform.startswith('linux'):
        try:
            import gi
            try:
                gi.require_version('Unity', '6.0')
            except:
                logging.exception('Failed to specify Unity version.')

            from gi.repository import Unity
        except ImportError:
            # Can't find Unity.
            pass
        else:
            logging.info('Activating Unity integration...')
            current = UnityIntegration(Unity)
            return

        logging.info('Activating generic Linux integration...')
        current = LinuxIntegration()
        return

    logging.warning('No desktop integration active.')
    current = Integration()
<|endoftext|>


<commit_before>__author__ = 'George Oblapenko, Viktor Evstratov'
__license__ = "GPLv3"
"""
Various pre-rolled functions to ease common operations - extracting data from csv files or files in a folder,
sync/dump/copy datasets
"""
from csv import reader
from os.path import join, isfile
import numpy as np
from os import walk
from krakenlib.dataset import DataSet
from krakenlib.misc import element_length
from krakenlib.errors import KrakenousException
from json import dumps

def csv_tentacle(path_to_file, id_column_number, missing_element=-1, custom_mapping: list=None):
    # more complex rules with dealing with missing_elements in the future? need user input for that
    """
    custom_mapping maps header strings into new header strings, list of tuples
    """
    pass

def folder_tentacle(path_to_folder, column_name: str, exclude_files_list: tuple=(), filename_transform=None,
                    keep_original_filename: bool=True, original_filename_column_name: str='filename', **kwargs):
    for (dirpath, dirnames, filenames) in walk(path_to_folder):
        for f_name in filenames:
            if filename_transform is None:
                if f_name not in exclude_files_list:
                    yield {column_name: f_name}
            else:
                if f_name not in exclude_files_list:
                    if keep_original_filename is True:
                        yield {original_filename_column_name: f_name, column_name: filename_transform(f_name, **kwargs)}
                    else:
                        yield {column_name: filename_transform(f_name, **kwargs)}

def add_labels(dataset: DataSet, id_field_name: str, labels, labels_name: str='label', overwrite_existing: bool=False):
    """
    labels - iterable of iterables - ((some_id, label), ...)
    return difference between added and not_added?
    """
    if overwrite_existing is False and dataset.feature_exists_global(labels_name) is True:
        raise KrakenousException(labels_name)
    inserts = 0
    for data_record in dataset.yield_data_records(('id', id_field_name)):
        for single_label in labels:
            if data_record['id_field_name'] in single_label[0]:
                dataset.insert_single(data_record['id'], labels_name, single_label[1], True)
                inserts += 1
    return dataset.total_records - inserts

def dump_dataset(dataset: DataSet, db_data: dict, dump_backend: str, column_names: tuple=(), copy_meta: bool=True):
    """
    allow copying only of specified column_names
    """
    if dump_backend not in ('sqlite', 'pickle', 'csv'):
        raise KrakenousException('Unknown backend' + dump_backend)
    else:
        new_dataset = DataSet(dump_backend, db_data)
        if copy_meta is True:
            new_dataset.metadata = dataset.metadata
        for data_record in dataset.yield_data_records(column_names):
            new_dataset.append_data_record(data_record)
        return None

def copy_to_dataset(dataset1: DataSet, dataset2: DataSet, overwrite: bool=False):
    pass

def sync_datasets(dataset1, dataset2, abort_if_collision: bool=True):
    """
    Check if data in fields with same name is the same everywhere!!! If not, either rename or abort (specified
    by abort_if_collision) ds1[myfield] != ds2[myfield] -> ds1[myfield1], ds2[myfield2], copy around
    use dataset.rename_field for that
    return either none or a list of tuples of renamed fields: [(myfield1, myfield2)]
    """
    pass

def convert_single_feature_numpy(dataset: DataSet, feature_name: str, start_id: int=1, end_id: int=-1):
    # always returns a 2d array
    if dataset.total_records == 0:
        raise KrakenousException('The dataset is empty!')
    if end_id == -1:
        end_id = dataset.total_records
    else:
        if end_id > dataset.total_records:
            raise KrakenousException('Incorrect range, end_id=' + str(end_id), ', while total_records='
                                     + str(dataset.total_records))
    if start_id < 0 or start_id > end_id:
        raise KrakenousException('start_id cannot be less than 0 or bigger than end_id')

    starting = dataset.single_data_record(start_id, (feature_name,))

    el_length = element_length(starting[feature_name])
    if el_length[1] == 'string':
        raise KrakenousException('Cannot convert column ' + feature_name + ' to numpy array')
    result = np.zeros((end_id - start_id + 1, el_length[0]))
    if el_length[1] == 'number' or el_length[1] == 'tuple' or el_length[1] == 'list':
        for data_record in enumerate(dataset.yield_data_records((feature_name,), start_id, end_id)):
            result[data_record[0], :] = data_record[1][feature_name]
        # for data_record in enumerate(dataset.yield_data_records((feature_name,), start_id, end_id)):
        #     result[data_record[0], :] = data_record[1][feature_name]
    elif el_length[1] == 'ndarray':
        for data_record in enumerate(dataset.yield_data_records((feature_name,), start_id, end_id)):
            result[data_record[0], :] = data_record[1][feature_name].flatten()
    return result

def convert_multiple_features_numpy(dataset: DataSet, feature_names: tuple, start_id: int=1, end_id: int=-1):

    if dataset.total_records == 0:
        raise KrakenousException('The dataset is empty!')
    if end_id == -1:
        end_id = dataset.total_records
    else:
        if end_id > dataset.total_records:
            raise KrakenousException('Incorrect range, end_id=' + str(end_id), ', while total_records='
                                     + str(dataset.total_records))
    if start_id < 0 or start_id > end_id:
        raise KrakenousException('start_id cannot be less than 0 or bigger than end_id')

    total_length = 0

    starting = dataset.single_data_record(start_id, feature_names)

    lengths = []
    for feature_name in feature_names:
        feature_len = element_length(starting[feature_name])
        if feature_len[1] == 'string' or feature_len[0] <= 0:
            raise KrakenousException('Cannot convert column ' + feature_name + ' to numpy array')
        else:
            total_length += feature_len[0]
            lengths.append(feature_len)
    if total_length > 0:
        result = np.zeros((dataset.total_records + 1 - start_id, total_length))
        for data_record in enumerate(dataset.yield_data_records(feature_names, start_id, end_id)):
            curr_len = 0
            for name_number_pair in enumerate(feature_names):
                el_type = lengths[name_number_pair[0]][1]
                el_len = lengths[name_number_pair[0]][0]
                if el_type == 'number' or el_type == 'tuple' or el_type == 'list':
                    result[data_record[0],
                           curr_len:curr_len + el_len] = data_record[1][name_number_pair[1]]
                    curr_len += el_len
                elif el_type == 'ndarray':
                    result[data_record[0],
                           curr_len:curr_len + el_len] = data_record[1][name_number_pair[1]].flatten()
                    curr_len += el_len
        return result
    else:
        raise KrakenousException('No features that can be fit into a numpy array found in the passed tuple')

def numpy_array_serializer(array: np.ndarray) -> str:
    return dumps(array.tolist())<commit_msg>draft of syncing of datasets written<commit_after>__author__ = 'George Oblapenko, Viktor Evstratov'
__license__ = "GPLv3"
"""
Various pre-rolled functions to ease common operations - extracting data from csv files or files in a folder,
sync/dump/copy datasets
"""
from csv import reader
from os.path import join, isfile
import numpy as np
from os import walk
from krakenlib.dataset import DataSet
from krakenlib.misc import element_length
from krakenlib.errors import KrakenousException
from json import dumps

def csv_tentacle(path_to_file, id_column_number, missing_element=-1, custom_mapping: list=None):
    # more complex rules with dealing with missing_elements in the future? need user input for that
    """
    custom_mapping maps header strings into new header strings, list of tuples
    """
    pass

def folder_tentacle(path_to_folder, column_name: str, exclude_files_list: tuple=(), filename_transform=None,
                    keep_original_filename: bool=True, original_filename_column_name: str='filename', **kwargs):
    for (dirpath, dirnames, filenames) in walk(path_to_folder):
        for f_name in filenames:
            if filename_transform is None:
                if f_name not in exclude_files_list:
                    yield {column_name: f_name}
            else:
                if f_name not in exclude_files_list:
                    if keep_original_filename is True:
                        yield {original_filename_column_name: f_name, column_name: filename_transform(f_name, **kwargs)}
                    else:
                        yield {column_name: filename_transform(f_name, **kwargs)}

def add_labels(dataset: DataSet, id_field_name: str, labels, labels_name: str='label', overwrite_existing: bool=False):
    """
    labels - iterable of iterables - ((some_id, label), ...)
    return difference between added and not_added?
    """
    if overwrite_existing is False and dataset.feature_exists_global(labels_name) is True:
        raise KrakenousException(labels_name)
    inserts = 0
    for data_record in dataset.yield_data_records(('id', id_field_name)):
        for single_label in labels:
            if data_record['id_field_name'] in single_label[0]:
                dataset.insert_single(data_record['id'], labels_name, single_label[1], True)
                inserts += 1
    return dataset.total_records - inserts

def dump_dataset(dataset: DataSet, db_data: dict, dump_backend: str, column_names: tuple=(), copy_meta: bool=True):
    """
    allow copying only of specified column_names
    """
    if dump_backend not in ('sqlite', 'pickle', 'csv'):
        raise KrakenousException('Unknown backend' + dump_backend)
    else:
        new_dataset = DataSet(dump_backend, db_data)
        if copy_meta is True:
            new_dataset.metadata = dataset.metadata
        for data_record in dataset.yield_data_records(column_names):
            new_dataset.append_data_record(data_record)
        return None

def sync_datasets(dataset1: DataSet, dataset2: DataSet):
    #TODO what if key doesn't exist in case of the shelve backend?

    if dataset1.total_records != dataset2.total_records:
        raise KrakenousException('Different numbers of records in datasets')
    data_names1 = dataset1.feature_names()
    data_names2 = dataset2.feature_names()
    from_first_to_second = ['id']
    from_second_to_first = ['id']
    for data_name in data_names1:
        if data_name not in data_names2:
            from_first_to_second.append(data_name)
    for data_name in data_names2:
        if data_name not in data_names1:
            from_second_to_first.append(data_name)
    for record in dataset1.yield_data_records(from_first_to_second):
        for data_name in from_first_to_second:
            dataset2.insert_single(record['id'], data_name, record[data_name])
    for record in dataset2.yield_data_records(from_second_to_first):
        for data_name in from_second_to_first:
            dataset1.insert_single(record['id'], data_name, record[data_name])

def convert_single_feature_numpy(dataset: DataSet, feature_name: str, start_id: int=1, end_id: int=-1):
    # always returns a 2d array
    if dataset.total_records == 0:
        raise KrakenousException('The dataset is empty')
    if end_id == -1:
        end_id = dataset.total_records
    else:
        if end_id > dataset.total_records:
            raise KrakenousException('Incorrect range, end_id=' + str(end_id), ', while total_records='
                                     + str(dataset.total_records))
    if start_id < 0 or start_id > end_id:
        raise KrakenousException('start_id cannot be less than 0 or bigger than end_id')

    starting = dataset.single_data_record(start_id, (feature_name,))

    el_length = element_length(starting[feature_name])
    if el_length[1] == 'string':
        raise KrakenousException('Cannot convert column ' + feature_name + ' to numpy array')
    result = np.zeros((end_id - start_id + 1, el_length[0]))
    if el_length[1] == 'number' or el_length[1] == 'tuple' or el_length[1] == 'list':
        for data_record in enumerate(dataset.yield_data_records((feature_name,), start_id, end_id)):
            result[data_record[0], :] = data_record[1][feature_name]
        # for data_record in enumerate(dataset.yield_data_records((feature_name,), start_id, end_id)):
        #     result[data_record[0], :] = data_record[1][feature_name]
    elif el_length[1] == 'ndarray':
        for data_record in enumerate(dataset.yield_data_records((feature_name,), start_id, end_id)):
            result[data_record[0], :] = data_record[1][feature_name].flatten()
    return result

def convert_multiple_features_numpy(dataset: DataSet, feature_names: tuple, start_id: int=1, end_id: int=-1):

    if dataset.total_records == 0:
        raise KrakenousException('The dataset is empty!')
    if end_id == -1:
        end_id = dataset.total_records
    else:
        if end_id > dataset.total_records:
            raise KrakenousException('Incorrect range, end_id=' + str(end_id), ', while total_records='
                                     + str(dataset.total_records))
    if start_id < 0 or start_id > end_id:
        raise KrakenousException('start_id cannot be less than 0 or bigger than end_id')

    total_length = 0

    starting = dataset.single_data_record(start_id, feature_names)

    lengths = []
    for feature_name in feature_names:
        feature_len = element_length(starting[feature_name])
        if feature_len[1] == 'string' or feature_len[0] <= 0:
            raise KrakenousException('Cannot convert column ' + feature_name + ' to numpy array')
        else:
            total_length += feature_len[0]
            lengths.append(feature_len)
    if total_length > 0:
        result = np.zeros((dataset.total_records + 1 - start_id, total_length))
        for data_record in enumerate(dataset.yield_data_records(feature_names, start_id, end_id)):
            curr_len = 0
            for name_number_pair in enumerate(feature_names):
                el_type = lengths[name_number_pair[0]][1]
                el_len = lengths[name_number_pair[0]][0]
                if el_type == 'number' or el_type == 'tuple' or el_type == 'list':
                    result[data_record[0],
                           curr_len:curr_len + el_len] = data_record[1][name_number_pair[1]]
                    curr_len += el_len
                elif el_type == 'ndarray':
                    result[data_record[0],
                           curr_len:curr_len + el_len] = data_record[1][name_number_pair[1]].flatten()
                    curr_len += el_len
        return result
    else:
        raise KrakenousException('No features that can be fit into a numpy array found in the passed tuple')

def numpy_array_serializer(array: np.ndarray) -> str:
    return dumps(array.tolist())<|endoftext|>