<commit_before># -*- coding: utf-8 -*-
{
    'name': 'Argentinian Localization',
    'version': '8.0.1.1.0',
    'category': 'Localization/Argentina',
    'sequence': 14,
    'author':  'ADHOC SA',
    'website': 'www.adhoc.com.ar',
    'license': 'AGPL-3',
    'summary': '',
    'description': """
Provides the configuration for whole business suite according to Argentinian Localization.
==========================================================================================
Algunas ideas en torno a esta localización:
    Se usan los reportes de Aeroo porque son facilmente customizables para cada Cliente
    El módulo l10n_ar_invoice tiene toda la lógica de impuestos y tipos de documentos de la afip, probablemente sea mejor renombrarloa l10n_ar_afip o l10n_ar_documents o l10n_ar_account
    Respecto a los impuestos y como identificamos si son IVA, iibb, drei, retencion, percepcion, etc. Si bien todavía no lo usamos, la idea es hacerlo por un ilike al nombre donde
        Si el nombre del padre tiene "IVA" es IVA
        Si el nombre del padre tiene "IIBB" es IIBB
        Si el nombre del padre tiene "DREI" es DREI
        Si el nombre del padre tiene "Ganancias" es Ganancias
        Si el nombre del padre tiene "RETENCION" es RETENCION
        Si el nombre del padre tiene "PERCEPCION" es PERCEPCION
    Todo el analisis de impuestos se debería hacer so bre account move lines consultando el tax.code (los tax no interesan)
    Si una retención o impuesto ya fue conciliado o no, lo vamos a saber agregando un m2o en account.move.line apuntando a nuestro "vat.ledger" o como se llame esa clase
    Por ahora, que no hay impuestos y percepeciones automáticas.
        Si yo tengo que cargar percepciones en una compra:
            Alternativa 1 (sin desarrollo)
                Creamos productos tipo "servicio" para cada percepción dentro de una categoría "Impuestos", asociadas a un impuesto de esa percepción, con código python "result = price_unit" e "impuestos incluidos en el precio". Son productos que solo se pueden comprar.
                Luego se agregan dichos productos en la factura de compras, completando el importe correspondiente.
            Atlernativa 2 (con modulo "account_invoice_manual_tax")
                Modificamos la vista de impuestos en facturas para que permita elegir código de impuestos.
                La ventaja de esto es que ya nos permite utilizar esto en percepciones de venta sin que hayamos que se carguen manualmente.
        Si yo tengo que cargar retenciones en un cobro:
            TODO
        Si yo tengo que aplicar percepciones en una venta
            TODO pero la idea sería usar algo de posiciones fiscales o similar y terminar
        Si yo tengo que aplicar retenciones en un pago:
            TODO

Features
+++++++++++++++
Product Features
--------------------
TODO

Warehouse Features
------------------------
TODO

Sales Features
--------------------
TODO

* TODO1
* TODO2
* TODO3

Purchase Features
-------------------------
TODO

* TODO1
* TODO2

Finance Features
------------------
TODO

Extra Tools
-------------
TODO

* TODO1
* TODO2
    """,
    'depends': [
        'base_setup'
    ],
    'external_dependencies': {
    },
    'data': [
        'l10n_ar_base_groups.xml',
        'res_config_view.xml',
    ],
    'demo': [
    ],
    'test': [
    ],
    'installable': True,
    'auto_install': True,
    'application': True,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<commit_msg>[REF] correct manifest odoo version number<commit_after># -*- coding: utf-8 -*-
{
    'name': 'Argentinian Localization',
    'version': '9.0.0.0.0',
    'category': 'Localization/Argentina',
    'sequence': 14,
    'author':  'ADHOC SA',
    'website': 'www.adhoc.com.ar',
    'license': 'AGPL-3',
    'summary': '',
    'description': """
Provides the configuration for whole business suite according to Argentinian Localization.
==========================================================================================
Algunas ideas en torno a esta localización:
    Se usan los reportes de Aeroo porque son facilmente customizables para cada Cliente
    El módulo l10n_ar_invoice tiene toda la lógica de impuestos y tipos de documentos de la afip, probablemente sea mejor renombrarloa l10n_ar_afip o l10n_ar_documents o l10n_ar_account
    Respecto a los impuestos y como identificamos si son IVA, iibb, drei, retencion, percepcion, etc. Si bien todavía no lo usamos, la idea es hacerlo por un ilike al nombre donde
        Si el nombre del padre tiene "IVA" es IVA
        Si el nombre del padre tiene "IIBB" es IIBB
        Si el nombre del padre tiene "DREI" es DREI
        Si el nombre del padre tiene "Ganancias" es Ganancias
        Si el nombre del padre tiene "RETENCION" es RETENCION
        Si el nombre del padre tiene "PERCEPCION" es PERCEPCION
    Todo el analisis de impuestos se debería hacer so bre account move lines consultando el tax.code (los tax no interesan)
    Si una retención o impuesto ya fue conciliado o no, lo vamos a saber agregando un m2o en account.move.line apuntando a nuestro "vat.ledger" o como se llame esa clase
    Por ahora, que no hay impuestos y percepeciones automáticas.
        Si yo tengo que cargar percepciones en una compra:
            Alternativa 1 (sin desarrollo)
                Creamos productos tipo "servicio" para cada percepción dentro de una categoría "Impuestos", asociadas a un impuesto de esa percepción, con código python "result = price_unit" e "impuestos incluidos en el precio". Son productos que solo se pueden comprar.
                Luego se agregan dichos productos en la factura de compras, completando el importe correspondiente.
            Atlernativa 2 (con modulo "account_invoice_manual_tax")
                Modificamos la vista de impuestos en facturas para que permita elegir código de impuestos.
                La ventaja de esto es que ya nos permite utilizar esto en percepciones de venta sin que hayamos que se carguen manualmente.
        Si yo tengo que cargar retenciones en un cobro:
            TODO
        Si yo tengo que aplicar percepciones en una venta
            TODO pero la idea sería usar algo de posiciones fiscales o similar y terminar
        Si yo tengo que aplicar retenciones en un pago:
            TODO

Features
+++++++++++++++
Product Features
--------------------
TODO

Warehouse Features
------------------------
TODO

Sales Features
--------------------
TODO

* TODO1
* TODO2
* TODO3

Purchase Features
-------------------------
TODO

* TODO1
* TODO2

Finance Features
------------------
TODO

Extra Tools
-------------
TODO

* TODO1
* TODO2
    """,
    'depends': [
        'base_setup'
    ],
    'external_dependencies': {
    },
    'data': [
        'l10n_ar_base_groups.xml',
        'res_config_view.xml',
    ],
    'demo': [
    ],
    'test': [
    ],
    'installable': True,
    'auto_install': True,
    'application': True,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<|endoftext|>


<commit_before># libavg - Media Playback Engine.
# Copyright (C) 2003-2008 Ulrich von Zadow
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Current versions can be found at www.libavg.de
#
# Original author of this file is Martin Heistermann <mh at sponc dot de>
#

import math

from libavg import avg, Point2D
from clusteredEventList import ClusteredEventList
from mathutil import solveEquationMatrix, EquationSingular, EquationNotSolvable
from mathutil import getAngle, getDistance, getScaledDim

NUM_SPEEDS = 5

g_player = avg.Player.get()

class Grabable:
    """Helper for multitouch object movement.
    Grabable will add the well-known multitouch gestures
    to a node, i.e. moving with one finger, rotating,
    resizing and moving with 2 fingers.
    It also works with many more cursors/fingers, clustering
    them.
    """
    def __init__(self,
            node,
            source = avg.TOUCH | avg.MOUSE,
            maxSize = None, minSize = None,
            onResize = lambda: None,
            onDrop = lambda: None,
            onStop = lambda: None,
            onAction = lambda: None,
            onMotion = lambda pos, size, angle, pivot: None,
            onDragStart = lambda: None,
            initialDown = None,
            inertia = 0.95,
            rotInertia = 0.95,
            moveNode = True):

        global g_player
        self.__inertia = inertia
        self.__rotInertia = rotInertia
        self.__node = node
        self.__minSize = minSize
        self.__maxSize = maxSize
        self.__moveNode = moveNode
        self.__callback = {
                'onResize': onResize,
                'onDrop': onDrop,
                'onStop': onStop,
                'onAction': onAction,
                'onMotion': onMotion,
                'onDragStart': onDragStart,
                }

        self.__stopInertia()
        #self.__oldAngle = 0.0
        self.__lastFixPoint = None
        self.__lastNumFingers = 0
        self.__onFrameHandler = g_player.setOnFrameHandler(self.__onFrame)

        self.__eventList = ClusteredEventList (self.__node,
                source = source,
                onMotion = self.__onMotion,
                onUp = self.__onUp,
                onDown = self.__onDown,
                resetMotion = self.__resetMotion
                )
        if initialDown:
            self.__eventList.handleInitialDown (initialDown)
        self.__lastPos = None
        self.__stopped = True

    def isDragging(self):
        return len(self.__eventList) > 0

    def getSpeed(self):
        return self.__speed

    def getAngle(self):
        return self.__angle

    def delete(self):
        global g_player
        g_player.clearInterval(self.__onFrameHandler)
        self.__eventList.delete()
        self.__node = None

    def __onFrame(self):
        global g_player
        if len (self.__eventList) == 0:
            # inertia
            if self.__speed.getNorm() < 1:
                if not self.__stopped:
                    self.__stopped = True
                    self.__callback['onStop']()
                    self.__stopInertia()
                    return
            if(self.__moveNode):
                self.__node.pos += self.__speed
                self.__node.angle += self.__rotSpeed
            self.__speed *= self.__inertia
            self.__rotSpeed *= self.__inertia
        else:
            # save current speed for inertia
            pos = self.__getAbsCenter()
            angle = self.__node.angle
            if self.__lastPos:
                speed = pos - self.__lastPos
                rotSpeed = angle - self.__lastAngle
                # use minimal angle to avoid extreme rotation:
                if rotSpeed < -math.pi/2:
                    rotSpeed += math.pi*2
                if rotSpeed > math.pi/2:
                    rotSpeed -= math.pi*2
                self.__speeds = (self.__speeds + [speed])[-NUM_SPEEDS:]
                self.__rotSpeeds = (self.__rotSpeeds + [rotSpeed])[-NUM_SPEEDS:]
            self.__lastPos = pos
            self.__lastAngle = angle

    def __stopInertia (self):
        self.__speed = Point2D(0,0)
        self.__rotSpeed = 0
        self.__speeds = [Point2D(0,0)]
        self.__rotSpeeds = [0.0]
        self.__lastPos = None

    def __onDown(self):
        def __gotoTopLayer ():
            parent = self.__node.getParent()
            numChildren = parent.getNumChildren()
            parent.reorderChild(self.__node, numChildren - 1)

        self.__stopped = False
        self.__stopInertia()
        self.__reshape()
        if len(self.__eventList) == 1: # first finger down
            __gotoTopLayer()
            self.__callback['onDragStart']()
        self.__callback['onAction']()

    def __onMotion(self):
        self.__reshape()
        self.__callback['onAction']()

    def __drop(self):
        self.__speed = sum(self.__speeds, Point2D(0,0)) / len(self.__speeds)
        self.__rotSpeed = sum(self.__rotSpeeds, 0.0) / len(self.__rotSpeeds)
        self.__callback['onDrop']()

    def __onUp(self):
        if len(self.__eventList) == 0:
            self.__drop()
        self.__callback['onAction']()

    def __reshape (self):
        def applyAffineTransformation (parameters, p):
            """apply transformation to point:
                         M:       v:
              P' = P * (m  -n) + (v0)
                       (n   m)   (v1) """
            m, n, v0, v1 = parameters
            nx = p[0] * m - p[1] * n + v0
            ny = p[0] * n + p[1] * m + v1
            return Point2D(nx, ny)

        clusters = self.__eventList.getCursors()

        if len(clusters) == 1:
            cursor = self.__eventList.getCursors()[0]

            pos = self.__oldpos + cursor.getDelta()
            size = self.__node.size
            angle = self.__node.angle
            pivot = self.__node.pivot

        elif len(clusters) == 2:
            # calculate an affine transformation which describes cluster movement
            # TODO: explain used maths
            cursor1, cursor2 = clusters
            equationMatrix = (
                    ((cursor1.getStartPos().x, -cursor1.getStartPos().y, 1, 0), cursor1.getPos().x),
                    ((cursor1.getStartPos().y,  cursor1.getStartPos().x, 0, 1), cursor1.getPos().y),
                    ((cursor2.getStartPos().x, -cursor2.getStartPos().y, 1, 0), cursor2.getPos().x),
                    ((cursor2.getStartPos().y,  cursor2.getStartPos().x, 0, 1), cursor2.getPos().y),
                    )
            try:
                param = solveEquationMatrix (equationMatrix)
            except (EquationSingular, EquationNotSolvable):
                print "WARNING: Grabable: cannot solve equation, skipping movement"
                return False

            absTouchCenter = cursor2.getPos() + (cursor1.getPos() - cursor2.getPos()) / 2

            n_tl = applyAffineTransformation (param, self.o_tl)
            n_bl = applyAffineTransformation (param, self.o_bl)
            n_tr = applyAffineTransformation (param, self.o_tr)

            pos = n_tl
            size = Point2D(getDistance (n_tl, n_tr), getDistance (n_tl, n_bl))
            angle = getAngle(n_tl, n_tr) # pivot for this rotation is 0,0 (rel. to node)

            def getRelPos(pos, nodePos, angle, pivot):
                return (pos - nodePos).getRotated(-angle, pivot)

            def getAbsPos(pos, nodePos, angle, pivot):
                return pos.getRotated(angle, pivot) + nodePos

            # get middle of touches relative to the node
            relTouchCenter = getRelPos(absTouchCenter, n_tl, angle, Point2D(0,0))

            def getOffsetForMovedPivot(oldPivot, newPivot, angle):
                oldPos = Point2D(0,0).getRotated(angle, oldPivot)
                newPos = Point2D(0,0).getRotated(angle, newPivot)
                return oldPos - newPos

            pos += getOffsetForMovedPivot(
                    oldPivot = Point2D(0,0),
                    newPivot = relTouchCenter,
                    angle = angle)
            pivot = relTouchCenter

            def scaleMinMax(pos, size, angle, pivot):
                # the absolute position of the pivot should change when
                # resizing, so we track and revert absolute pivot movement
                oldAbsPivot = getAbsPos(pivot, pos, angle, pivot)

                newSize = getScaledDim (size,
                        max = self.__maxSize,
                        min = self.__minSize)

                ratio = newSize.x / size.x
                newPivot = pivot * ratio

                pos += getOffsetForMovedPivot(
                        oldPivot = pivot,
                        newPivot = newPivot,
                        angle = angle)
                pivot = newPivot

                size = newSize

                newAbsPivot = getAbsPos(pivot, pos, angle, pivot)

                # move node to revert absolute pivot position
                pos -= (newAbsPivot - oldAbsPivot)

                return (pos, size, angle, pivot)

            (pos, size, angle, pivot) = scaleMinMax(pos, size, angle, pivot)

        else: # more than 2 clusters
            assert False

        if self.__moveNode:
            self.__node.angle = angle
            self.__node.size = size
            self.__node.pos = pos
            self.__node.pivot = pivot
            self.__callback['onResize']()

        self.__callback['onMotion'](pos, size, angle, pivot)

    def __getAbsCenter(self):
        return self.__node.getAbsPos (self.__node.size/2)

    def __resetMotion (self):
        """ sets a new movement start point """
        # store absolute position at the beginning of the movement
        # for 2-finger-movements:
        self.o_tl = self.__node.getAbsPos ((0, 0))
        self.o_bl = self.__node.getAbsPos ((0, self.__node.height))
        self.o_tr = self.__node.getAbsPos ((self.__node.width, 0))

        # for 1-finger-movements:
        self.__oldpos = self.__node.pos

        self.__lastFixPoint = None

<commit_msg>grabable.py: renamed rotIneratia to toque, use it instead of __inertia (bugfix)<commit_after># libavg - Media Playback Engine.
# Copyright (C) 2003-2008 Ulrich von Zadow
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Current versions can be found at www.libavg.de
#
# Original author of this file is Martin Heistermann <mh at sponc dot de>
#

import math

from libavg import avg, Point2D
from clusteredEventList import ClusteredEventList
from mathutil import solveEquationMatrix, EquationSingular, EquationNotSolvable
from mathutil import getAngle, getDistance, getScaledDim

NUM_SPEEDS = 5

g_player = avg.Player.get()

class Grabable:
    """Helper for multitouch object movement.
    Grabable will add the well-known multitouch gestures
    to a node, i.e. moving with one finger, rotating,
    resizing and moving with 2 fingers.
    It also works with many more cursors/fingers, clustering
    them.
    """
    def __init__(self,
            node,
            source = avg.TOUCH | avg.MOUSE,
            maxSize = None, minSize = None,
            onResize = lambda: None,
            onDrop = lambda: None,
            onStop = lambda: None,
            onAction = lambda: None,
            onMotion = lambda pos, size, angle, pivot: None,
            onDragStart = lambda: None,
            initialDown = None,
            inertia = 0.95,
            torque = 0.95,
            moveNode = True):

        global g_player
        self.__inertia = inertia
        self.__torque = torque
        self.__node = node
        self.__minSize = minSize
        self.__maxSize = maxSize
        self.__moveNode = moveNode
        self.__callback = {
                'onResize': onResize,
                'onDrop': onDrop,
                'onStop': onStop,
                'onAction': onAction,
                'onMotion': onMotion,
                'onDragStart': onDragStart,
                }

        self.__stopInertia()
        #self.__oldAngle = 0.0
        self.__lastFixPoint = None
        self.__lastNumFingers = 0
        self.__onFrameHandler = g_player.setOnFrameHandler(self.__onFrame)

        self.__eventList = ClusteredEventList (self.__node,
                source = source,
                onMotion = self.__onMotion,
                onUp = self.__onUp,
                onDown = self.__onDown,
                resetMotion = self.__resetMotion
                )
        if initialDown:
            self.__eventList.handleInitialDown (initialDown)
        self.__lastPos = None
        self.__stopped = True

    def isDragging(self):
        return len(self.__eventList) > 0

    def getSpeed(self):
        return self.__speed

    def getAngle(self):
        return self.__angle

    def delete(self):
        global g_player
        g_player.clearInterval(self.__onFrameHandler)
        self.__eventList.delete()
        self.__node = None

    def __onFrame(self):
        global g_player
        if len (self.__eventList) == 0:
            # inertia
            if self.__speed.getNorm() < 1:
                if not self.__stopped:
                    self.__stopped = True
                    self.__callback['onStop']()
                    self.__stopInertia()
                    return
            if self.__moveNode:
                self.__node.pos += self.__speed
                self.__node.angle += self.__rotSpeed
            self.__speed *= self.__inertia
            self.__rotSpeed *= self.__torque
        else:
            # save current speed for inertia
            pos = self.__getAbsCenter()
            angle = self.__node.angle
            if self.__lastPos:
                speed = pos - self.__lastPos
                rotSpeed = angle - self.__lastAngle
                # use minimal angle to avoid extreme rotation:
                if rotSpeed < -math.pi/2:
                    rotSpeed += math.pi*2
                if rotSpeed > math.pi/2:
                    rotSpeed -= math.pi*2
                self.__speeds = (self.__speeds + [speed])[-NUM_SPEEDS:]
                self.__rotSpeeds = (self.__rotSpeeds + [rotSpeed])[-NUM_SPEEDS:]
            self.__lastPos = pos
            self.__lastAngle = angle

    def __stopInertia (self):
        self.__speed = Point2D(0,0)
        self.__rotSpeed = 0
        self.__speeds = [Point2D(0,0)]
        self.__rotSpeeds = [0.0]
        self.__lastPos = None

    def __onDown(self):
        def __gotoTopLayer ():
            parent = self.__node.getParent()
            numChildren = parent.getNumChildren()
            parent.reorderChild(self.__node, numChildren - 1)

        self.__stopped = False
        self.__stopInertia()
        self.__reshape()
        if len(self.__eventList) == 1: # first finger down
            __gotoTopLayer()
            self.__callback['onDragStart']()
        self.__callback['onAction']()

    def __onMotion(self):
        self.__reshape()
        self.__callback['onAction']()

    def __drop(self):
        self.__speed = sum(self.__speeds, Point2D(0,0)) / len(self.__speeds)
        self.__rotSpeed = sum(self.__rotSpeeds, 0.0) / len(self.__rotSpeeds)
        self.__callback['onDrop']()

    def __onUp(self):
        if len(self.__eventList) == 0:
            self.__drop()
        self.__callback['onAction']()

    def __reshape (self):
        def applyAffineTransformation (parameters, p):
            """apply transformation to point:
                         M:       v:
              P' = P * (m  -n) + (v0)
                       (n   m)   (v1) """
            m, n, v0, v1 = parameters
            nx = p[0] * m - p[1] * n + v0
            ny = p[0] * n + p[1] * m + v1
            return Point2D(nx, ny)

        clusters = self.__eventList.getCursors()

        if len(clusters) == 1:
            cursor = self.__eventList.getCursors()[0]

            pos = self.__oldpos + cursor.getDelta()
            size = self.__node.size
            angle = self.__node.angle
            pivot = self.__node.pivot

        elif len(clusters) == 2:
            # calculate an affine transformation which describes cluster movement
            # TODO: explain used maths
            cursor1, cursor2 = clusters
            equationMatrix = (
                    ((cursor1.getStartPos().x, -cursor1.getStartPos().y, 1, 0), cursor1.getPos().x),
                    ((cursor1.getStartPos().y,  cursor1.getStartPos().x, 0, 1), cursor1.getPos().y),
                    ((cursor2.getStartPos().x, -cursor2.getStartPos().y, 1, 0), cursor2.getPos().x),
                    ((cursor2.getStartPos().y,  cursor2.getStartPos().x, 0, 1), cursor2.getPos().y),
                    )
            try:
                param = solveEquationMatrix (equationMatrix)
            except (EquationSingular, EquationNotSolvable):
                print "WARNING: Grabable: cannot solve equation, skipping movement"
                return False

            absTouchCenter = cursor2.getPos() + (cursor1.getPos() - cursor2.getPos()) / 2

            n_tl = applyAffineTransformation (param, self.o_tl)
            n_bl = applyAffineTransformation (param, self.o_bl)
            n_tr = applyAffineTransformation (param, self.o_tr)

            pos = n_tl
            size = Point2D(getDistance (n_tl, n_tr), getDistance (n_tl, n_bl))
            angle = getAngle(n_tl, n_tr) # pivot for this rotation is 0,0 (rel. to node)

            def getRelPos(pos, nodePos, angle, pivot):
                return (pos - nodePos).getRotated(-angle, pivot)

            def getAbsPos(pos, nodePos, angle, pivot):
                return pos.getRotated(angle, pivot) + nodePos

            # get middle of touches relative to the node
            relTouchCenter = getRelPos(absTouchCenter, n_tl, angle, Point2D(0,0))

            def getOffsetForMovedPivot(oldPivot, newPivot, angle):
                oldPos = Point2D(0,0).getRotated(angle, oldPivot)
                newPos = Point2D(0,0).getRotated(angle, newPivot)
                return oldPos - newPos

            pos += getOffsetForMovedPivot(
                    oldPivot = Point2D(0,0),
                    newPivot = relTouchCenter,
                    angle = angle)
            pivot = relTouchCenter

            def scaleMinMax(pos, size, angle, pivot):
                # the absolute position of the pivot should change when
                # resizing, so we track and revert absolute pivot movement
                oldAbsPivot = getAbsPos(pivot, pos, angle, pivot)

                newSize = getScaledDim (size,
                        max = self.__maxSize,
                        min = self.__minSize)

                ratio = newSize.x / size.x
                newPivot = pivot * ratio

                pos += getOffsetForMovedPivot(
                        oldPivot = pivot,
                        newPivot = newPivot,
                        angle = angle)
                pivot = newPivot

                size = newSize

                newAbsPivot = getAbsPos(pivot, pos, angle, pivot)

                # move node to revert absolute pivot position
                pos -= (newAbsPivot - oldAbsPivot)

                return (pos, size, angle, pivot)

            (pos, size, angle, pivot) = scaleMinMax(pos, size, angle, pivot)

        else: # more than 2 clusters
            assert False

        if self.__moveNode:
            self.__node.angle = angle
            self.__node.size = size
            self.__node.pos = pos
            self.__node.pivot = pivot
            self.__callback['onResize']()

        self.__callback['onMotion'](pos, size, angle, pivot)

    def __getAbsCenter(self):
        return self.__node.getAbsPos (self.__node.size/2)

    def __resetMotion (self):
        """ sets a new movement start point """
        # store absolute position at the beginning of the movement
        # for 2-finger-movements:
        self.o_tl = self.__node.getAbsPos ((0, 0))
        self.o_bl = self.__node.getAbsPos ((0, self.__node.height))
        self.o_tr = self.__node.getAbsPos ((self.__node.width, 0))

        # for 1-finger-movements:
        self.__oldpos = self.__node.pos

        self.__lastFixPoint = None

<|endoftext|>


<commit_before># -*- encoding: utf-8 -*-
###############################################################################
#                                                                             #
# Copyright (C) 2009  Renato Lima - Akretion                                  #
#                                                                             #
#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/>.        #
###############################################################################

import l10n_br_account
import sped
import res_company
import res_partner
import account
import account_invoice
import product
import account_fiscal_position_rule
import account_product_fiscal_classification
import wizard
<commit_msg>Atualizado arquivo l10n_br_account/__init__.py<commit_after># -*- encoding: utf-8 -*-
###############################################################################
#                                                                             #
# Copyright (C) 2009  Renato Lima - Akretion                                  #
#                                                                             #
#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/>.        #
###############################################################################

import l10n_br_account
import sped
import res_company
import res_partner
import account
import account_invoice
import product
import account_fiscal_position_rule
<|endoftext|>


<commit_before># libavg - Media Playback Engine.
# Copyright (C) 2003-2008 Ulrich von Zadow
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Current versions can be found at www.libavg.de
#
# Original author of this file is Martin Heistermann <mh at sponc dot de>
#

import math
from libavg import Point2D

def getAngle(p1, p2):
    vec = p2 - p1
    res = math.atan2(vec.y, vec.x)
    if res < 0:
        res += math.pi * 2
    return res

def getDistance (p, q):
    return math.sqrt((p.x-q.x)**2 + (p.y-q.y)**2)

def getDistSquared (p, q):
    return (p.x-q.x)**2 + (p.y-q.y)**2

def getScaledDim (size, max, min):
    width, height = size

    if max:
        max = Point2D(max)
        if width > max.x:
            height = height * (max.x / width)
            width = max.x
        if height > max.y:
            width = width * (max.y / height)
            height = max.y

    if min:
        min = Point2D(min)
        if width < min.x:
            height = height * (min.x / width)
            width = min.x
        if height < min.y:
            width = width * (min.y / height)
            height = min.y

    return Point2D(width, height)

class EquationNotSolvable (Exception):
    pass
class EquationSingular (Exception):
    pass

def gauss_jordan(m, eps = 1.0/(10**10)):
    """Puts given matrix (2D array) into the Reduced Row Echelon Form.
         Returns True if successful, False if 'm' is singular.
         NOTE: make sure all the matrix items support fractions! Int matrix will NOT work!
         Written by Jarno Elonen in April 2005, released into Public Domain
         http://elonen.iki.fi/code/misc-notes/affine-fit/index.html"""
    (h, w) = (len(m), len(m[0]))
    for y in range(0,h):
        maxrow = y
        for y2 in range(y+1, h):        # Find max pivot
            if abs(m[y2][y]) > abs(m[maxrow][y]):
                maxrow = y2
        (m[y], m[maxrow]) = (m[maxrow], m[y])
        if abs(m[y][y]) <= eps:         # Singular?
            raise EquationSingular
        for y2 in range(y+1, h):        # Eliminate column y
            c = m[y2][y] / m[y][y]
            for x in range(y, w):
                m[y2][x] -= m[y][x] * c
    for y in range(h-1, 0-1, -1): # Backsubstitute
        c    = m[y][y]
        for y2 in range(0,y):
            for x in range(w-1, y-1, -1):
                m[y2][x] -=    m[y][x] * m[y2][y] / c
        m[y][y] /= c
        for x in range(h, w):             # Normalize row y
            m[y][x] /= c
    return m

def solveEquationMatrix(_matrix, eps = 1.0/(10**10)):
    matrix=[]
    for coefficients, res in _matrix:
        newrow = map(float, coefficients + (res,))
        matrix.append(newrow)
    matrix = gauss_jordan (matrix)
    res=[]
    for col in xrange(len(matrix[0])-1):
        rows = filter(lambda row: row[col] >= eps, matrix)
        if len(rows)!=1:
            raise EquationNotSolvable
        res.append (rows[0][-1])

    return res

<commit_msg>mathutil.py: getScaledDim max/min arguments now both optional<commit_after># libavg - Media Playback Engine.
# Copyright (C) 2003-2008 Ulrich von Zadow
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Current versions can be found at www.libavg.de
#
# Original author of this file is Martin Heistermann <mh at sponc dot de>
#

import math
from libavg import Point2D

def getAngle(p1, p2):
    vec = p2 - p1
    res = math.atan2(vec.y, vec.x)
    if res < 0:
        res += math.pi * 2
    return res

def getDistance (p, q):
    return math.sqrt((p.x-q.x)**2 + (p.y-q.y)**2)

def getDistSquared (p, q):
    return (p.x-q.x)**2 + (p.y-q.y)**2

def getScaledDim (size, max = None, min = None):
    width, height = size

    if max:
        max = Point2D(max)
        if width > max.x:
            height = height * (max.x / width)
            width = max.x
        if height > max.y:
            width = width * (max.y / height)
            height = max.y

    if min:
        min = Point2D(min)
        if width < min.x:
            height = height * (min.x / width)
            width = min.x
        if height < min.y:
            width = width * (min.y / height)
            height = min.y

    return Point2D(width, height)

class EquationNotSolvable (Exception):
    pass
class EquationSingular (Exception):
    pass

def gauss_jordan(m, eps = 1.0/(10**10)):
    """Puts given matrix (2D array) into the Reduced Row Echelon Form.
         Returns True if successful, False if 'm' is singular.
         NOTE: make sure all the matrix items support fractions! Int matrix will NOT work!
         Written by Jarno Elonen in April 2005, released into Public Domain
         http://elonen.iki.fi/code/misc-notes/affine-fit/index.html"""
    (h, w) = (len(m), len(m[0]))
    for y in range(0,h):
        maxrow = y
        for y2 in range(y+1, h):        # Find max pivot
            if abs(m[y2][y]) > abs(m[maxrow][y]):
                maxrow = y2
        (m[y], m[maxrow]) = (m[maxrow], m[y])
        if abs(m[y][y]) <= eps:         # Singular?
            raise EquationSingular
        for y2 in range(y+1, h):        # Eliminate column y
            c = m[y2][y] / m[y][y]
            for x in range(y, w):
                m[y2][x] -= m[y][x] * c
    for y in range(h-1, 0-1, -1): # Backsubstitute
        c    = m[y][y]
        for y2 in range(0,y):
            for x in range(w-1, y-1, -1):
                m[y2][x] -=    m[y][x] * m[y2][y] / c
        m[y][y] /= c
        for x in range(h, w):             # Normalize row y
            m[y][x] /= c
    return m

def solveEquationMatrix(_matrix, eps = 1.0/(10**10)):
    matrix=[]
    for coefficients, res in _matrix:
        newrow = map(float, coefficients + (res,))
        matrix.append(newrow)
    matrix = gauss_jordan (matrix)
    res=[]
    for col in xrange(len(matrix[0])-1):
        rows = filter(lambda row: row[col] >= eps, matrix)
        if len(rows)!=1:
            raise EquationNotSolvable
        res.append (rows[0][-1])

    return res

<|endoftext|>


<commit_before># Copyright (C) 2009  Renato Lima - Akretion
# Copyright (C) 2012  Raphaël Valyi - Akretion
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

from odoo import _, api, fields, models
from odoo.addons import decimal_precision as dp
from odoo.exceptions import UserError
from odoo.tools import float_is_zero

class SaleOrder(models.Model):
    _name = 'sale.order'
    _inherit = [_name, 'l10n_br_fiscal.document.mixin']

    @api.depends('order_line.price_total')
    def _amount_all(self):
        """Compute the total amounts of the SO."""
        for order in self:
            order.amount_gross = sum(
                line.price_gross for line in order.order_line)

            order.amount_discount = sum(
                line.discount_value for line in order.order_line)

            order.amount_untaxed = sum(
                line.price_subtotal for line in order.order_line)

            order.amount_tax = sum(
                line.price_tax for line in order.order_line)

            order.amount_total = sum(
                line.price_total for line in order.order_line)

            order.amount_freight = sum(
                line.freight_value for line in order.order_line)

            order.amount_costs = sum(
                line.other_costs_value for line in order.order_line)

            order.amount_insurance = sum(
                line.insurance_value for line in order.order_line)

    @api.model
    def _default_fiscal_operation(self):
        return self.env.user.company_id.sale_fiscal_operation_id

    @api.model
    def _fiscal_operation_domain(self):
        domain = [('state', '=', 'approved')]
        return domain

    @api.model
    def _default_copy_note(self):
        return self.env.user.company_id.copy_note

    fiscal_operation_id = fields.Many2one(
        comodel_name='l10n_br_fiscal.operation',
        readonly=True,
        states={'draft': [('readonly', False)]},
        default=_default_fiscal_operation,
        domain=lambda self: self._fiscal_operation_domain())

    ind_pres = fields.Selection(
        readonly=True,
        states={'draft': [('readonly', False)]})

    copy_note = fields.Boolean(
        string='Copiar Observação no documentos fiscal',
        default=_default_copy_note)

    cnpj_cpf = fields.Char(
        string='CNPJ/CPF',
        related='partner_id.cnpj_cpf')

    legal_name = fields.Char(
        string='Legal Name',
        related='partner_id.legal_name')

    ie = fields.Char(
        string='State Tax Number/RG',
        related='partner_id.inscr_est')

    discount_rate = fields.Float(
        string='Discount',
        readonly=True,
        states={'draft': [('readonly', False)]})

    amount_gross = fields.Monetary(
        compute='_amount_all',
        string="Amount Gross",
        store=True,
        readonly=True,
        help="Amount without discount.")

    amount_discount = fields.Monetary(
        compute='_amount_all',
        store=True,
        string='Discount (-)',
        readonly=True,
        help="The discount amount.")

    amount_freight = fields.Float(
        compute='_amount_all',
        store=True,
        string='Freight',
        readonly=True,
        default=0.00,
        digits=dp.get_precision("Account"),
        states={"draft": [("readonly", False)]})

    amount_insurance = fields.Float(
        compute='_amount_all',
        store=True,
        string='Insurance',
        readonly=True,
        default=0.00,
        digits=dp.get_precision('Account'))

    amount_costs = fields.Float(
        compute='_amount_all',
        store=True,
        string="Other Costs",
        readonly=True,
        default=0.00,
        digits=dp.get_precision('Account'))

    fiscal_document_count = fields.Integer(
        related='invoice_count',
        readonly=True)

    @api.onchange('discount_rate')
    def onchange_discount_rate(self):
        for order in self:
            for line in order.order_line:
                line.discount = order.discount_rate
                line._onchange_discount()

    @api.onchange('fiscal_operation_id')
    def _onchange_fiscal_operation_id(self):
        self.fiscal_position_id = self.fiscal_operation_id.fiscal_position_id

    # TODO FIscal Comment
    # @api.model
    # def _fiscal_comment(self, order):
    #     fp_comment = []
    #     fp_ids = []
    #
    #     for line in order.order_line:
    #         if line.fiscal_operation_line_id and \
    #                 line.fiscal_operation_line_id.inv_copy_note and \
    #                 line.fiscal_operation_line_id.note:
    #             if line.fiscal_operation_line_id.id not in fp_ids:
    #                 fp_comment.append(line.fiscal_operation_line_id.note)
    #                 fp_ids.append(line.fiscal_operation_line_id.id)
    #
    #      return fp_comment

    @api.multi
    def action_view_document(self):
        invoices = self.mapped('invoice_ids')
        action = self.env.ref('l10n_br_fiscal.document_out_action').read()[0]
        if len(invoices) > 1:
            action['domain'] = \
                [('id', 'in', invoices.mapped('fiscal_document_id').ids)]
        elif len(invoices) == 1:
            form_view = \
                [(self.env.ref('l10n_br_fiscal.document_form').id, 'form')]
            if 'views' in action:
                action['views'] = form_view + [(state, view) for state, view
                                               in action['views'] if
                                               view != 'form']
            else:
                action['views'] = form_view
            action['res_id'] = invoices.fiscal_document_id.id
        else:
            action = {'type': 'ir.actions.act_window_close'}
        return action

    @api.multi
    def _prepare_invoice(self):
        self.ensure_one()
        result = super(SaleOrder, self)._prepare_invoice()

        comment = []
        if self.note and self.copy_note:
            comment.append(self.note)

        # TODO FISCAL Commnet
        # result['fiscal_comment'] = " - ".join(fiscal_comment)
        # fiscal_comment = self._fiscal_comment(self)
        result['comment'] = " - ".join(comment)

        result.update(self._prepare_br_fiscal_dict())

        if self.fiscal_operation_id:
            # TODO Defini document_type_id in other method in line
            if self._context.get('document_type_id'):
                result['document_type_id'] = \
                    self._context.get('document_type_id')
            # TODO
            result['document_serie_id'] = 1

            if self.fiscal_operation_id.journal_id:
                result['journal_id'] = self.fiscal_operation_id.journal_id.id

        return result

    @api.multi
    def action_invoice_create(self, grouped=False, final=False):

        inv_ids = super().action_invoice_create(grouped=grouped, final=final)

        # In brazilian localization we need to overwrite this method
        # because when there are a sale order line with different Document
        # Fiscal Type the method should be create invoices separated.

        document_type_list = []

        for invoice_id in inv_ids:
            invoice_created_by_super = self.env[
                'account.invoice'].browse(invoice_id)

            # Identify how many Document Types exist
            for inv_line in invoice_created_by_super.invoice_line_ids:

                fiscal_document_type = \
                    inv_line.fiscal_operation_line_id.get_document_type(
                        inv_line.invoice_id.company_id)

                if fiscal_document_type.id not in document_type_list:
                    document_type_list.append(fiscal_document_type.id)

            # Check if there more than one Document Type
            if len(document_type_list) > 1:

                # Remove the First Document Type,
                # already has Invoice created
                invoice_created_by_super.document_type_id =\
                    document_type_list.pop(0)

                for document_type in document_type_list:
                    document_type = self.env[
                        'l10n_br_fiscal.document.type'].browse(document_type)

                    inv_obj = self.env['account.invoice']
                    invoices = {}
                    references = {}
                    invoices_origin = {}
                    invoices_name = {}

                    for order in self:
                        group_key = order.id if grouped else (
                            order.partner_invoice_id.id, order.currency_id.id)

                        if group_key not in invoices:
                            inv_data = order.with_context(
                                document_type_id=document_type.id
                            )._prepare_invoice()
                            invoice = inv_obj.create(inv_data)
                            references[invoice] = order
                            invoices[group_key] = invoice
                            invoices_origin[group_key] = [invoice.origin]
                            invoices_name[group_key] = [invoice.name]
                            inv_ids.append(invoice.id)
                        elif group_key in invoices:
                            if order.name not in invoices_origin[group_key]:
                                invoices_origin[group_key].append(order.name)
                            if (order.client_order_ref and
                                order.client_order_ref not in
                                invoices_name[group_key]):
                                invoices_name[group_key].append(
                                    order.client_order_ref)

                    # Update Invoice Line
                    for inv_line in invoice_created_by_super.invoice_line_ids:
                        fiscal_document_type = \
                            inv_line.fiscal_operation_line_id.get_document_type(
                                inv_line.invoice_id.company_id)
                        if fiscal_document_type.id == document_type.id:
                            inv_line.invoice_id = invoice.id

        return inv_ids
<commit_msg>[12.0][MIG][FIX] PEP8.<commit_after># Copyright (C) 2009  Renato Lima - Akretion
# Copyright (C) 2012  Raphaël Valyi - Akretion
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

from odoo import api, fields, models
from odoo.addons import decimal_precision as dp

class SaleOrder(models.Model):
    _name = 'sale.order'
    _inherit = [_name, 'l10n_br_fiscal.document.mixin']

    @api.depends('order_line.price_total')
    def _amount_all(self):
        """Compute the total amounts of the SO."""
        for order in self:
            order.amount_gross = sum(
                line.price_gross for line in order.order_line)

            order.amount_discount = sum(
                line.discount_value for line in order.order_line)

            order.amount_untaxed = sum(
                line.price_subtotal for line in order.order_line)

            order.amount_tax = sum(
                line.price_tax for line in order.order_line)

            order.amount_total = sum(
                line.price_total for line in order.order_line)

            order.amount_freight = sum(
                line.freight_value for line in order.order_line)

            order.amount_costs = sum(
                line.other_costs_value for line in order.order_line)

            order.amount_insurance = sum(
                line.insurance_value for line in order.order_line)

    @api.model
    def _default_fiscal_operation(self):
        return self.env.user.company_id.sale_fiscal_operation_id

    @api.model
    def _fiscal_operation_domain(self):
        domain = [('state', '=', 'approved')]
        return domain

    @api.model
    def _default_copy_note(self):
        return self.env.user.company_id.copy_note

    fiscal_operation_id = fields.Many2one(
        comodel_name='l10n_br_fiscal.operation',
        readonly=True,
        states={'draft': [('readonly', False)]},
        default=_default_fiscal_operation,
        domain=lambda self: self._fiscal_operation_domain())

    ind_pres = fields.Selection(
        readonly=True,
        states={'draft': [('readonly', False)]})

    copy_note = fields.Boolean(
        string='Copiar Observação no documentos fiscal',
        default=_default_copy_note)

    cnpj_cpf = fields.Char(
        string='CNPJ/CPF',
        related='partner_id.cnpj_cpf')

    legal_name = fields.Char(
        string='Legal Name',
        related='partner_id.legal_name')

    ie = fields.Char(
        string='State Tax Number/RG',
        related='partner_id.inscr_est')

    discount_rate = fields.Float(
        string='Discount',
        readonly=True,
        states={'draft': [('readonly', False)]})

    amount_gross = fields.Monetary(
        compute='_amount_all',
        string="Amount Gross",
        store=True,
        readonly=True,
        help="Amount without discount.")

    amount_discount = fields.Monetary(
        compute='_amount_all',
        store=True,
        string='Discount (-)',
        readonly=True,
        help="The discount amount.")

    amount_freight = fields.Float(
        compute='_amount_all',
        store=True,
        string='Freight',
        readonly=True,
        default=0.00,
        digits=dp.get_precision("Account"),
        states={"draft": [("readonly", False)]})

    amount_insurance = fields.Float(
        compute='_amount_all',
        store=True,
        string='Insurance',
        readonly=True,
        default=0.00,
        digits=dp.get_precision('Account'))

    amount_costs = fields.Float(
        compute='_amount_all',
        store=True,
        string="Other Costs",
        readonly=True,
        default=0.00,
        digits=dp.get_precision('Account'))

    fiscal_document_count = fields.Integer(
        related='invoice_count',
        readonly=True)

    @api.onchange('discount_rate')
    def onchange_discount_rate(self):
        for order in self:
            for line in order.order_line:
                line.discount = order.discount_rate
                line._onchange_discount()

    @api.onchange('fiscal_operation_id')
    def _onchange_fiscal_operation_id(self):
        self.fiscal_position_id = self.fiscal_operation_id.fiscal_position_id

    # TODO FIscal Comment
    # @api.model
    # def _fiscal_comment(self, order):
    #     fp_comment = []
    #     fp_ids = []
    #
    #     for line in order.order_line:
    #         if line.fiscal_operation_line_id and \
    #                 line.fiscal_operation_line_id.inv_copy_note and \
    #                 line.fiscal_operation_line_id.note:
    #             if line.fiscal_operation_line_id.id not in fp_ids:
    #                 fp_comment.append(line.fiscal_operation_line_id.note)
    #                 fp_ids.append(line.fiscal_operation_line_id.id)
    #
    #      return fp_comment

    @api.multi
    def action_view_document(self):
        invoices = self.mapped('invoice_ids')
        action = self.env.ref('l10n_br_fiscal.document_out_action').read()[0]
        if len(invoices) > 1:
            action['domain'] = \
                [('id', 'in', invoices.mapped('fiscal_document_id').ids)]
        elif len(invoices) == 1:
            form_view = \
                [(self.env.ref('l10n_br_fiscal.document_form').id, 'form')]
            if 'views' in action:
                action['views'] = form_view + [(state, view) for state, view
                                               in action['views'] if
                                               view != 'form']
            else:
                action['views'] = form_view
            action['res_id'] = invoices.fiscal_document_id.id
        else:
            action = {'type': 'ir.actions.act_window_close'}
        return action

    @api.multi
    def _prepare_invoice(self):
        self.ensure_one()
        result = super(SaleOrder, self)._prepare_invoice()

        comment = []
        if self.note and self.copy_note:
            comment.append(self.note)

        # TODO FISCAL Commnet
        # result['fiscal_comment'] = " - ".join(fiscal_comment)
        # fiscal_comment = self._fiscal_comment(self)
        result['comment'] = " - ".join(comment)

        result.update(self._prepare_br_fiscal_dict())

        if self.fiscal_operation_id:
            # TODO Defini document_type_id in other method in line
            if self._context.get('document_type_id'):
                result['document_type_id'] = \
                    self._context.get('document_type_id')
            # TODO
            result['document_serie_id'] = 1

            if self.fiscal_operation_id.journal_id:
                result['journal_id'] = self.fiscal_operation_id.journal_id.id

        return result

    @api.multi
    def action_invoice_create(self, grouped=False, final=False):

        inv_ids = super().action_invoice_create(grouped=grouped, final=final)

        # In brazilian localization we need to overwrite this method
        # because when there are a sale order line with different Document
        # Fiscal Type the method should be create invoices separated.

        document_type_list = []

        for invoice_id in inv_ids:
            invoice_created_by_super = self.env[
                'account.invoice'].browse(invoice_id)

            # Identify how many Document Types exist
            for inv_line in invoice_created_by_super.invoice_line_ids:

                fiscal_document_type = \
                    inv_line.fiscal_operation_line_id.get_document_type(
                        inv_line.invoice_id.company_id)

                if fiscal_document_type.id not in document_type_list:
                    document_type_list.append(fiscal_document_type.id)

            # Check if there more than one Document Type
            if len(document_type_list) > 1:

                # Remove the First Document Type,
                # already has Invoice created
                invoice_created_by_super.document_type_id =\
                    document_type_list.pop(0)

                for document_type in document_type_list:
                    document_type = self.env[
                        'l10n_br_fiscal.document.type'].browse(document_type)

                    inv_obj = self.env['account.invoice']
                    invoices = {}
                    references = {}
                    invoices_origin = {}
                    invoices_name = {}

                    for order in self:
                        group_key = order.id if grouped else (
                            order.partner_invoice_id.id, order.currency_id.id)

                        if group_key not in invoices:
                            inv_data = order.with_context(
                                document_type_id=document_type.id
                            )._prepare_invoice()
                            invoice = inv_obj.create(inv_data)
                            references[invoice] = order
                            invoices[group_key] = invoice
                            invoices_origin[group_key] = [invoice.origin]
                            invoices_name[group_key] = [invoice.name]
                            inv_ids.append(invoice.id)
                        elif group_key in invoices:
                            if order.name not in invoices_origin[group_key]:
                                invoices_origin[group_key].append(order.name)
                            if (order.client_order_ref and
                               order.client_order_ref not in
                               invoices_name[group_key]):
                                invoices_name[group_key].append(
                                    order.client_order_ref)

                    # Update Invoice Line
                    for inv_line in invoice_created_by_super.invoice_line_ids:
                        fiscal_document_type = \
                            inv_line.fiscal_operation_line_id.get_document_type(
                                inv_line.invoice_id.company_id)
                        if fiscal_document_type.id == document_type.id:
                            inv_line.invoice_id = invoice.id

        return inv_ids
<|endoftext|>


<commit_before># Copyright (C) 2021 Open Source Integrators (<http://www.opensourceintegrators.com>)
# Copyright (C) 2014 Sossia, Lda. (<http://www.sossia.pt>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
    "name": "Portugal - IVA",
    "version": "14.0.0.1.0",
    "license": "AGPL-3",
    "depends": ["account", "l10n_pt"],
    "author": "Open Source Integrators, Sossia, Odoo Community Association (OCA)",
    "summary": "Portuguese VAT requirements extensions",
    "website": "https://github.com/OCA/l10n-portugal",
    "category": "Localisation/Portugal",
    "data": [
        "security/ir.model.access.csv",
        "data/account.l10n_pt.vat.exempt.reason.csv",
        "data/account_tax.xml",
        "data/vat_adjustment_norm.xml",
        "views/account_journal_view.xml",
        "views/account_move_view.xml",
        "views/account_tax_view.xml",
        "views/l10n_pt_vat_exempt_reason_view.xml",
        "views/vat_adjustment_norm_view.xml",
    ],
    "installable": True,
    "auto_install": True,
}
<commit_msg>l10n_pt_vat 14.0.0.2.0<commit_after># Copyright (C) 2021 Open Source Integrators (<http://www.opensourceintegrators.com>)
# Copyright (C) 2014 Sossia, Lda. (<http://www.sossia.pt>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
    "name": "Portugal - IVA",
    "version": "14.0.0.2.0",
    "license": "AGPL-3",
    "depends": ["account", "l10n_pt"],
    "author": "Open Source Integrators, Sossia, Odoo Community Association (OCA)",
    "summary": "Portuguese VAT requirements extensions",
    "website": "https://github.com/OCA/l10n-portugal",
    "category": "Localisation/Portugal",
    "data": [
        "security/ir.model.access.csv",
        "data/account.l10n_pt.vat.exempt.reason.csv",
        "data/account_tax.xml",
        "data/vat_adjustment_norm.xml",
        "views/account_journal_view.xml",
        "views/account_move_view.xml",
        "views/account_tax_view.xml",
        "views/l10n_pt_vat_exempt_reason_view.xml",
        "views/vat_adjustment_norm_view.xml",
    ],
    "installable": True,
    "auto_install": True,
}
<|endoftext|>


<commit_before>import warnings
from functools import wraps

def make_return_array_immutable(func):
    @wraps(func)
    def _wrapped(self, *args, **kwds):
        array = func(self, *args, **kwds)
        immutable_array = array.view()
        immutable_array.flags.writeable = False
        return immutable_array
    return _wrapped

def deprecated(func):
    """Mark a function as deprecated
    """
    @wraps(func)
    def _wrapped(*args, **kwargs):
        warnings.warn("Call to deprecated function {}.".format(func.__name__),
                      category=DeprecationWarning)
        return func(*args, **kwargs)
    _wrapped.__dict__.update(func.__dict__)

    return _wrapped
<commit_msg>Added docstrings to functions.<commit_after>"""General decorators for the landlab library."""

import warnings
from functools import wraps

def make_return_array_immutable(func):
    """Decorate a function so that its return array is read-only.

    Parameters
    ----------
    func : function
        A function that returns a numpy array.

    Returns
    -------
    func
        A wrapped function that returns a read-only view of an array.
    """
    @wraps(func)
    def _wrapped(self, *args, **kwds):
        array = func(self, *args, **kwds)
        immutable_array = array.view()
        immutable_array.flags.writeable = False
        return immutable_array
    return _wrapped

def deprecated(func):
    """Mark a function as deprecated.

    Parameters
    ----------
    func : function
        A function.

    Returns
    -------
    func
        A wrapped function that issues a deprecation warning.
    """
    @wraps(func)
    def _wrapped(*args, **kwargs):
        warnings.warn("Call to deprecated function {}.".format(func.__name__),
                      category=DeprecationWarning)
        return func(*args, **kwargs)
    _wrapped.__dict__.update(func.__dict__)

    return _wrapped
<|endoftext|>


<commit_before>import json

from flask import request, session, render_template, Blueprint

from lexos.managers.utility import load_file_manager
from lexos.models.content_analysis_model import ContentAnalysisModel
from lexos.interfaces.base_interface import detect_active_docs

# this is a flask blue print
# it helps us to manage groups of views
# see here for more detail:
# http://exploreflask.com/en/latest/blueprints.html
# http://flask.pocoo.org/docs/0.12/blueprints/
content_analysis_view = Blueprint('content_analysis', __name__)
analysis = None

# Tells Flask to load this function when someone is at '/contentanalysis'
@content_analysis_view.route("/contentanalysis", methods=["GET", "POST"])
def content_analysis():
    """Handles the functionality on the contentanalysis page.

    :return: a response object (often a render_template call) to flask and
    eventually to the browser.
    """
    global analysis
    if analysis is None or 'content_analysis' not in session:
        analysis = ContentAnalysisModel()
        session['content_analysis'] = True
    elif len(analysis.corpus) == 0:
        file_manager = load_file_manager()
        files = file_manager.get_active_files()
        for file in files:
            analysis.add_corpus(file_name=file.name,
                                label=file.label,
                                content=file.load_contents())

    if request.method == 'GET':
        dictionary_labels = []
        active_dictionaries = []
        session['toggle_all'] = False
        if len(analysis.dictionaries):
            session['toggle_all'] = True
            for dictionary in analysis.dictionaries:
                dictionary_labels.append(dictionary.label)
                active_dictionaries.append(dictionary.active)
                if not dictionary.active:
                    session['toggle_all'] = False
        return render_template('contentanalysis.html',
                               dictionary_labels=dictionary_labels,
                               active_dictionaries=active_dictionaries,
                               toggle_all=session['toggle_all'])
    else:
        formula = request.json['calc_input']
        if len(formula) == 0:
            session['formula'] = "0"
        else:
            formula = formula.replace("√", "sqrt").replace("^", "**")
            session['formula'] = formula
            error_msg = "Formula errors:
"
            if formula.count("(") != formula.count(")"):
                error_msg += "Mismatched parenthesis
"
            if "sin()" in formula:
                error_msg += "sin takes exactly one argument (0 given)
"
            if "cos()" in formula:
                error_msg += "cos takes exactly one argument (0 given)
"
            if "tan()" in formula:
                error_msg += "tan takes exactly one argument (0 given)
"
            if "log()" in formula:
                error_msg += "log takes exactly one argument (0 given)
"
            return error(error_msg)

        num_active_docs = detect_active_docs()
        num_active_dicts = analysis.detect_active_dicts()
        if num_active_docs == 0 and num_active_dicts == 0:
            data = {"error": "At least 1 active document and 1 active "
                             "dictionary are required to perform a "
                             "content analysis."}
            data = json.dumps(data)
            return data
        elif num_active_docs == 0:
            return error("At least 1 active document is required to perform "
                         "a content analysis.")
        elif num_active_dicts == 0:
            return error("At least 1 active dictionary is required to perform "
                         "a content analysis.")
        analysis.count_words()
        if analysis.is_secure(session['formula']):
            data = {"result_table": "",
                    "dictionary_labels": [],
                    "active_dictionaries": [],
                    "error": False}
            analysis.generate_scores(session['formula'])
            analysis.generate_averages()
            data['result_table'] = analysis.to_html()
            for dictionary in analysis.dictionaries:
                data['dictionary_labels'].append(dictionary.label)
                data['active_dictionaries'].append(dictionary.active)
            data = json.dumps(data)
            return data
        return error("Formula error: Invalid input")

# Tells Flask to load this function when someone is at '/getdictlabels'
@content_analysis_view.route("/uploaddictionaries", methods=["GET", "POST"])
def upload_dictionaries():
    """Uploads dictionaries to the content analysis object.

    :return: a json object.
    """
    global analysis
    analysis = ContentAnalysisModel()
    session['formula'] = ""
    session['toggle_all'] = True
    data = {'dictionary_labels': [],
            'active_dictionaries': [],
            'formula': "",
            'toggle_all': True,
            'error': False}
    if detect_active_docs() == 0:
        data['error'] = True
    for upload_file in request.files.getlist('lemfileselect[]'):
        file_name = upload_file.filename
        content = upload_file.read()
        analysis.add_dictionary(file_name=file_name, content=content)
        data['dictionary_labels'].append(analysis.dictionaries[-1].label)
        data['active_dictionaries'].append(True)
    data = json.dumps(data)
    return data

# Tells Flask to load this function when someone is at '/saveformula'
@content_analysis_view.route("/saveformula", methods=["GET", "POST"])
def save_formula():
    """Saves the formula.

    :return: a string indicating if it succeeded
    """
    formula = request.json['calc_input']
    print(formula)
    if len(formula) == 0:
        session['formula'] = "0"
    else:
        formula = formula.replace("√", "sqrt").replace("^", "**")
        session['formula'] = formula
        if formula.count("(") != formula.count(")") or \
                formula.count("[") != formula.count("]"):
            return "error"
    return "success"

# Tells Flask to load this function when someone is at '/toggledictionary'
@content_analysis_view.route("/toggledictionary", methods=["GET", "POST"])
def toggle_dictionary():
    """Handles the functionality of the checkboxes.

    :return: a json object.
    """
    global analysis
    data = {'dictionary_labels': [],
            'active_dictionaries': [],
            'toggle_all': session['toggle_all']}
    if request.json['toggle_all']:
        session['toggle_all'] = not session['toggle_all']
        for dictionary in analysis.dictionaries:
            dictionary.active = session['toggle_all']
            data['dictionary_labels'].append(dictionary.label)
            data['active_dictionaries'].append(session['toggle_all'])
    else:
        dictionary = request.json['dict_name']
        analysis.toggle_dictionary(dictionary)
        session['toggle_all'] = True
        for dictionary in analysis.dictionaries:
            data['dictionary_labels'].append(dictionary.label)
            data['active_dictionaries'].append(dictionary.active)
            if not dictionary.active:
                session['toggle_all'] = False
    data['toggle_all'] = session['toggle_all']
    data = json.dumps(data)
    return data

# Tells Flask to load this function when someone is at '/deletedictionary'
@content_analysis_view.route("/deletedictionary", methods=["GET", "POST"])
def delete_dictionary():
    """Handles the functionality of the delete buttons.

    :return: a json object.
    """
    global analysis
    data = {'dictionary_labels': [],
            'active_dictionaries': []}
    dict_label = request.json['dict_label']
    analysis.delete_dictionary(dict_label)
    for dictionary in analysis.dictionaries:
        data['dictionary_labels'].append(dictionary.label)
        data['active_dictionaries'].append(dictionary.active)
    data = json.dumps(data)
    return data

def error(msg: str):
    data = {"error": msg}
    data = json.dumps(data)
    return data
<commit_msg>small fix<commit_after>import json

from flask import request, session, render_template, Blueprint

from lexos.managers.utility import load_file_manager
from lexos.models.content_analysis_model import ContentAnalysisModel
from lexos.interfaces.base_interface import detect_active_docs

# this is a flask blue print
# it helps us to manage groups of views
# see here for more detail:
# http://exploreflask.com/en/latest/blueprints.html
# http://flask.pocoo.org/docs/0.12/blueprints/
content_analysis_view = Blueprint('content_analysis', __name__)
analysis = None

# Tells Flask to load this function when someone is at '/contentanalysis'
@content_analysis_view.route("/contentanalysis", methods=["GET", "POST"])
def content_analysis():
    """Handles the functionality on the contentanalysis page.

    :return: a response object (often a render_template call) to flask and
    eventually to the browser.
    """
    global analysis
    if analysis is None or 'content_analysis' not in session:
        analysis = ContentAnalysisModel()
        session['content_analysis'] = True
    elif len(analysis.corpus) == 0:
        file_manager = load_file_manager()
        files = file_manager.get_active_files()
        for file in files:
            analysis.add_corpus(file_name=file.name,
                                label=file.label,
                                content=file.load_contents())

    if request.method == 'GET':
        dictionary_labels = []
        active_dictionaries = []
        session['toggle_all'] = False
        if len(analysis.dictionaries):
            session['toggle_all'] = True
            for dictionary in analysis.dictionaries:
                dictionary_labels.append(dictionary.label)
                active_dictionaries.append(dictionary.active)
                if not dictionary.active:
                    session['toggle_all'] = False
        return render_template('contentanalysis.html',
                               dictionary_labels=dictionary_labels,
                               active_dictionaries=active_dictionaries,
                               toggle_all=session['toggle_all'])
    else:
        formula = request.json['calc_input']
        if len(formula) == 0:
            session['formula'] = "0"
        else:
            formula = formula.replace("√", "sqrt").replace("^", "**")
            session['formula'] = formula
            error_msg = "Formula errors:
"
            is_error = False
            if formula.count("(") != formula.count(")"):
                error_msg += "Mismatched parenthesis
"
                is_error = True
            if "sin()" in formula:
                error_msg += "sin takes exactly one argument (0 given)
"
                is_error = True
            if "cos()" in formula:
                error_msg += "cos takes exactly one argument (0 given)
"
                is_error = True
            if "tan()" in formula:
                error_msg += "tan takes exactly one argument (0 given)
"
                is_error = True
            if "log()" in formula:
                error_msg += "log takes exactly one argument (0 given)
"
                is_error = True
            if is_error:
                return error(error_msg)

        num_active_docs = detect_active_docs()
        num_active_dicts = analysis.detect_active_dicts()
        if num_active_docs == 0 and num_active_dicts == 0:
            data = {"error": "At least 1 active document and 1 active "
                             "dictionary are required to perform a "
                             "content analysis."}
            data = json.dumps(data)
            return data
        elif num_active_docs == 0:
            return error("At least 1 active document is required to perform "
                         "a content analysis.")
        elif num_active_dicts == 0:
            return error("At least 1 active dictionary is required to perform "
                         "a content analysis.")
        analysis.count_words()
        if analysis.is_secure(session['formula']):
            data = {"result_table": "",
                    "dictionary_labels": [],
                    "active_dictionaries": [],
                    "error": False}
            analysis.generate_scores(session['formula'])
            analysis.generate_averages()
            data['result_table'] = analysis.to_html()
            for dictionary in analysis.dictionaries:
                data['dictionary_labels'].append(dictionary.label)
                data['active_dictionaries'].append(dictionary.active)
            data = json.dumps(data)
            return data
        return error("Formula error: Invalid input")

# Tells Flask to load this function when someone is at '/getdictlabels'
@content_analysis_view.route("/uploaddictionaries", methods=["GET", "POST"])
def upload_dictionaries():
    """Uploads dictionaries to the content analysis object.

    :return: a json object.
    """
    global analysis
    analysis = ContentAnalysisModel()
    session['formula'] = ""
    session['toggle_all'] = True
    data = {'dictionary_labels': [],
            'active_dictionaries': [],
            'formula': "",
            'toggle_all': True,
            'error': False}
    if detect_active_docs() == 0:
        data['error'] = True
    for upload_file in request.files.getlist('lemfileselect[]'):
        file_name = upload_file.filename
        content = upload_file.read()
        analysis.add_dictionary(file_name=file_name, content=content)
        data['dictionary_labels'].append(analysis.dictionaries[-1].label)
        data['active_dictionaries'].append(True)
    data = json.dumps(data)
    return data

# Tells Flask to load this function when someone is at '/saveformula'
@content_analysis_view.route("/saveformula", methods=["GET", "POST"])
def save_formula():
    """Saves the formula.

    :return: a string indicating if it succeeded
    """
    formula = request.json['calc_input']
    if len(formula) == 0:
        session['formula'] = "0"
    else:
        formula = formula.replace("√", "sqrt").replace("^", "**")
        session['formula'] = formula
        if formula.count("(") != formula.count(")") or \
                formula.count("[") != formula.count("]"):
            return "error"
    return "success"

# Tells Flask to load this function when someone is at '/toggledictionary'
@content_analysis_view.route("/toggledictionary", methods=["GET", "POST"])
def toggle_dictionary():
    """Handles the functionality of the checkboxes.

    :return: a json object.
    """
    global analysis
    data = {'dictionary_labels': [],
            'active_dictionaries': [],
            'toggle_all': session['toggle_all']}
    if request.json['toggle_all']:
        session['toggle_all'] = not session['toggle_all']
        for dictionary in analysis.dictionaries:
            dictionary.active = session['toggle_all']
            data['dictionary_labels'].append(dictionary.label)
            data['active_dictionaries'].append(session['toggle_all'])
    else:
        dictionary = request.json['dict_name']
        analysis.toggle_dictionary(dictionary)
        session['toggle_all'] = True
        for dictionary in analysis.dictionaries:
            data['dictionary_labels'].append(dictionary.label)
            data['active_dictionaries'].append(dictionary.active)
            if not dictionary.active:
                session['toggle_all'] = False
    data['toggle_all'] = session['toggle_all']
    data = json.dumps(data)
    return data

# Tells Flask to load this function when someone is at '/deletedictionary'
@content_analysis_view.route("/deletedictionary", methods=["GET", "POST"])
def delete_dictionary():
    """Handles the functionality of the delete buttons.

    :return: a json object.
    """
    global analysis
    data = {'dictionary_labels': [],
            'active_dictionaries': []}
    dict_label = request.json['dict_label']
    analysis.delete_dictionary(dict_label)
    for dictionary in analysis.dictionaries:
        data['dictionary_labels'].append(dictionary.label)
        data['active_dictionaries'].append(dictionary.active)
    data = json.dumps(data)
    return data

def error(msg: str):
    data = {"error": msg}
    data = json.dumps(data)
    return data
<|endoftext|>