<commit_before># SPDX-License-Identifier: Apache-2.0
#
# Copyright (C) 2017, ARM Limited and contributors.
#
# 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 collections import OrderedDict, namedtuple
import json
import os

from lisa.wlgen.rta import RTA, Periodic, Ramp, Step, RunAndSync

from .utils import StorageTestCase, create_local_target, ASSET_DIR

# Disable DeprecationWarning since PerfAnalysis is deprecated
from lisa.analysis.rta import PerfAnalysis
import warnings
warnings.filterwarnings('ignore', category=DeprecationWarning)

class RTABase(StorageTestCase):
    """
    Common functionality for testing RTA

    Doesn't have "Test" in the name so that nosetests doesn't try to run it
    directly
    """

    tools = ['rt-app']

    def get_expected_command(self, rta_wload):
        """Return the rt-app command we should execute when `run` is called"""
        rta_path = self.target.which('rt-app')
        json_path = os.path.join(rta_wload.run_dir, rta_wload.json)
        return '{} {} 2>&1'.format(rta_path, json_path)

    def setUp(self):
        super().setUp()
        self.target = create_local_target()

    def assert_output_file_exists(self, path):
        """Assert that a file was created"""
        path = os.path.join(self.res_dir, path)
        self.assertTrue(os.path.isfile(path),
                        'No output file {} from rt-app'.format(path))

    def assert_can_read_logfile(self, exp_tasks):
        """Assert that the perf_analysis module understands the log output"""
        analysis = PerfAnalysis.from_dir(self.res_dir)
        self.assertSetEqual(set(exp_tasks), set(analysis.tasks))

class TestRTAProfile(RTABase):
    def _do_test(self, profile, exp_phases):
        rtapp = RTA.by_profile(
            self.target, name='test', profile=profile, res_dir=self.res_dir,
            calibration=None, log_stats=True)

        with open(rtapp.local_json) as f:
            conf = json.load(f, object_pairs_hook=OrderedDict)

        # Check that the configuration looks like we expect it to
        phases = list(conf['tasks']['test']['phases'].values())
        self.assertEqual(len(phases), len(exp_phases), 'Wrong number of phases')
        for phase, exp_phase in zip(phases, exp_phases):
            self.assertDictEqual(phase, exp_phase)

        # Try running the workload and check that it produces the expected log
        # files
        rtapp.run()

        # rtapp_cmds = [c for c in self.target.executed_commands if 'rt-app' in c]
        # self.assertListEqual(rtapp_cmds, [self.get_expected_command(rtapp)])

        self.assert_output_file_exists('output.log')
        self.assert_output_file_exists('test.json')
        self.assert_output_file_exists('rt-app-test-0.log')
        self.assert_can_read_logfile(exp_tasks=['test'])

    def test_profile_periodic_smoke(self):
        """
        Smoketest Periodic rt-app workload

        Creates a workload using Periodic, tests that the JSON has the expected
        content, then tests that it can be run.
        """

        profile = {
            "test" : Periodic(period_ms=100, duty_cycle_pct=20, duration_s=1)
        }

        exp_phases = [
            {
                'loop': 10,
                'run': 20000,
                'timer': {
                    'period': 100000,
                    'ref': 'test'
                }
            }
        ]

        self._do_test(profile, exp_phases)

    def test_profile_step_smoke(self):
        """
        Smoketest Step rt-app workload

        Creates a workload using Step, tests that the JSON has the expected
        content, then tests that it can be run.
        """

        profile = {"test" : Step(start_pct=100, end_pct=0, time_s=1)}

        exp_phases = [
            {
                'run': 1000000,
                'loop': 1
            },
            {
                'sleep': 1000000,
                'loop': 1
            },
        ]

        self._do_test(profile, exp_phases)

    def test_profile_run_and_sync_smoke(self):
        profile = {"test" : RunAndSync('my_barrier', time_s=1)}
        exp_phases = [
            OrderedDict([
                ('loop', 1),
                ('run', 1000000),
                ('barrier', 'my_barrier')
            ])
        ]

        self._do_test(profile, exp_phases)

    def test_composition(self):
        """
        Test RTA task composition with __add__

        Creates a composed workload by +-ing RTATask objects, tests that the
        JSON has the expected content, then tests running the workload
        """
        light = Periodic(duty_cycle_pct=10, duration_s=1.0, period_ms=10)

        start_pct = 10
        end_pct = 90
        delta_pct = 20
        ramp = Ramp(start_pct=start_pct, end_pct=end_pct, delta_pct=delta_pct,
                    time_s=1, period_ms=50)

        heavy = Periodic(duty_cycle_pct=90, duration_s=0.1, period_ms=100)

        profile = {"test" : light + ramp + heavy}

        exp_phases = [
            # Light phase:
            {
                "loop": 100,
                "run": 1000,
                "timer": {
                    "period": 10000,
                    "ref": "test"
                }
            },
            # Ramp phases:
            {
                "loop": 20,
                "run": 5000,
                "timer": {
                    "period": 50000,
                    "ref": "test"
                }
            },
            {
                "loop": 20,
                "run": 15000,
                "timer": {
                    "period": 50000,
                    "ref": "test"
                }
            },
            {
                "loop": 20,
                "run": 25000,
                "timer": {
                    "period": 50000,
                    "ref": "test"
                }
            },
            {
                "loop": 20,
                "run": 35000,
                "timer": {
                    "period": 50000,
                    "ref": "test"
                }
            },
            {
                "loop": 20,
                "run": 45000,
                "timer": {
                    "period": 50000,
                    "ref": "test"
                }
            },
            # Heavy phase:
            {
                "loop": 1,
                "run": 90000,
                "timer": {
                    "period": 100000,
                    "ref": "test"
                }
            }]

        self._do_test(profile, exp_phases)

    def test_invalid_composition(self):
        """Test that you can't compose tasks with a delay in the second task"""
        t1 = Periodic()
        t2 = Periodic(delay_s=1)

        # Should work fine if delayed task is the first one
        try:
            t3 = t2 + t1
        except Exception as e:
            raise AssertionError("Couldn't compose tasks: {}".format(e))

        # But not the other way around
        with self.assertRaises(ValueError):
            t3 = t1 + t2

class TestRTACustom(RTABase):
    def _test_custom_smoke(self, calibration):
        """
        Test RTA custom workload

        Creates an rt-app workload using 'custom' and checks that the json
        roughly matches the file we provided. If we have root, attempts to run
        the workload.
        """

        json_path = os.path.join(ASSET_DIR, 'mp3-short.json')

        with open(json_path, 'r') as fh:
            str_conf = fh.read()

        rtapp = RTA.by_str(
            self.target, name='test', str_conf=str_conf, res_dir=self.res_dir,
            max_duration_s=5, calibration=calibration)

        with open(rtapp.local_json, 'r') as fh:
            conf = json.load(fh)

        self.assertSetEqual(
            set(conf['tasks'].keys()),
            set(['AudioTick', 'AudioOut', 'AudioTrack',
                 'mp3.decoder', 'OMXCall']))

        # Would like to try running the workload but mp3-short.json has nonzero
        # 'priority' fields, and we probably don't have permission for that
        # unless we're root.
        if self.target.is_rooted:
            rtapp.run(as_root=True)

            # rtapp_cmds = [c for c in self.target.executed_commands
            #               if 'rt-app' in c]
            # self.assertListEqual(rtapp_cmds, [self.get_expected_command(rtapp)])

            self.assert_output_file_exists('output.log')
            self.assert_output_file_exists('test.json')

    def test_custom_smoke_calib(self):
        """Test RTA custom workload (providing calibration)"""
        calibration = min(self.target.plat_info['rtapp']['calib'].values())
        self._test_custom_smoke(calibration)

    def test_custom_smoke_no_calib(self):
        """Test RTA custom workload (providing no calibration)"""
        self._test_custom_smoke(None)

class TestRTACalibrationConf(RTABase):
    """Test setting the "calibration" field of rt-app config"""
    def _get_calib_conf(self, calibration):
        profile = {"test" : Periodic()}
        rtapp = RTA.by_profile(
            self.target, name='test', res_dir=self.res_dir, profile=profile,
            calibration=calibration)

        with open(rtapp.local_json) as fh:
            return json.load(fh)['global']['calibration']

    def test_calibration_conf_pload_nodata(self):
        """Test that the smallest pload value is used"""
        conf = self._get_calib_conf(None)
        self.assertEqual(conf, 100, 'Calibration not set to minimum pload value')

    def test_calibration_conf_pload_int(self):
        """Test that the calibration value is returned as expected"""
        conf = self._get_calib_conf(666)
        self.assertEqual(conf, 666, 'Calibration value modified')

    def test_calibration_conf_pload_str(self):
        """Test that the calibration value is returned as expected"""
        conf = self._get_calib_conf('CPU0')
        self.assertEqual(conf, 'CPU0', 'Calibration value modified')

# vim :set tabstop=4 shiftwidth=4 textwidth=80 expandtab
<commit_msg>tests: Fix PerfAnalysis test<commit_after># SPDX-License-Identifier: Apache-2.0
#
# Copyright (C) 2017, ARM Limited and contributors.
#
# 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 collections import OrderedDict, namedtuple
import json
import os
import re

from lisa.wlgen.rta import RTA, Periodic, Ramp, Step, RunAndSync

from .utils import StorageTestCase, create_local_target, ASSET_DIR

# Disable DeprecationWarning since PerfAnalysis is deprecated
from lisa.analysis.rta import PerfAnalysis
import warnings
warnings.filterwarnings('ignore', category=DeprecationWarning)

class RTABase(StorageTestCase):
    """
    Common functionality for testing RTA

    Doesn't have "Test" in the name so that nosetests doesn't try to run it
    directly
    """

    tools = ['rt-app']

    def get_expected_command(self, rta_wload):
        """Return the rt-app command we should execute when `run` is called"""
        rta_path = self.target.which('rt-app')
        json_path = os.path.join(rta_wload.run_dir, rta_wload.json)
        return '{} {} 2>&1'.format(rta_path, json_path)

    def setUp(self):
        super().setUp()
        self.target = create_local_target()

    def assert_output_file_exists(self, path):
        """Assert that a file was created"""
        path = os.path.join(self.res_dir, path)
        self.assertTrue(os.path.isfile(path),
                        'No output file {} from rt-app'.format(path))

    def assert_can_read_logfile(self, exp_tasks):
        """Assert that the perf_analysis module understands the log output"""
        analysis = PerfAnalysis.from_dir(self.res_dir)
        exp_tasks = [re.sub(r'-[0-9]+', '', task) for task in exp_tasks]
        self.assertSetEqual(set(exp_tasks), set(analysis.tasks))

class TestRTAProfile(RTABase):
    def _do_test(self, profile, exp_phases):
        rtapp = RTA.by_profile(
            self.target, name='test', profile=profile, res_dir=self.res_dir,
            calibration=None, log_stats=True)

        with open(rtapp.local_json) as f:
            conf = json.load(f, object_pairs_hook=OrderedDict)

        # Check that the configuration looks like we expect it to
        phases = list(conf['tasks']['test']['phases'].values())
        self.assertEqual(len(phases), len(exp_phases), 'Wrong number of phases')
        for phase, exp_phase in zip(phases, exp_phases):
            self.assertDictEqual(phase, exp_phase)

        # Try running the workload and check that it produces the expected log
        # files
        rtapp.run()

        # rtapp_cmds = [c for c in self.target.executed_commands if 'rt-app' in c]
        # self.assertListEqual(rtapp_cmds, [self.get_expected_command(rtapp)])

        self.assert_output_file_exists('output.log')
        self.assert_output_file_exists('test.json')
        self.assert_output_file_exists('rt-app-test-0.log')
        self.assert_can_read_logfile(exp_tasks=['test-0'])

    def test_profile_periodic_smoke(self):
        """
        Smoketest Periodic rt-app workload

        Creates a workload using Periodic, tests that the JSON has the expected
        content, then tests that it can be run.
        """

        profile = {
            "test" : Periodic(period_ms=100, duty_cycle_pct=20, duration_s=1)
        }

        exp_phases = [
            {
                'loop': 10,
                'run': 20000,
                'timer': {
                    'period': 100000,
                    'ref': 'test'
                }
            }
        ]

        self._do_test(profile, exp_phases)

    def test_profile_step_smoke(self):
        """
        Smoketest Step rt-app workload

        Creates a workload using Step, tests that the JSON has the expected
        content, then tests that it can be run.
        """

        profile = {"test" : Step(start_pct=100, end_pct=0, time_s=1)}

        exp_phases = [
            {
                'run': 1000000,
                'loop': 1
            },
            {
                'sleep': 1000000,
                'loop': 1
            },
        ]

        self._do_test(profile, exp_phases)

    def test_profile_run_and_sync_smoke(self):
        profile = {"test" : RunAndSync('my_barrier', time_s=1)}
        exp_phases = [
            OrderedDict([
                ('loop', 1),
                ('run', 1000000),
                ('barrier', 'my_barrier')
            ])
        ]

        self._do_test(profile, exp_phases)

    def test_composition(self):
        """
        Test RTA task composition with __add__

        Creates a composed workload by +-ing RTATask objects, tests that the
        JSON has the expected content, then tests running the workload
        """
        light = Periodic(duty_cycle_pct=10, duration_s=1.0, period_ms=10)

        start_pct = 10
        end_pct = 90
        delta_pct = 20
        ramp = Ramp(start_pct=start_pct, end_pct=end_pct, delta_pct=delta_pct,
                    time_s=1, period_ms=50)

        heavy = Periodic(duty_cycle_pct=90, duration_s=0.1, period_ms=100)

        profile = {"test" : light + ramp + heavy}

        exp_phases = [
            # Light phase:
            {
                "loop": 100,
                "run": 1000,
                "timer": {
                    "period": 10000,
                    "ref": "test"
                }
            },
            # Ramp phases:
            {
                "loop": 20,
                "run": 5000,
                "timer": {
                    "period": 50000,
                    "ref": "test"
                }
            },
            {
                "loop": 20,
                "run": 15000,
                "timer": {
                    "period": 50000,
                    "ref": "test"
                }
            },
            {
                "loop": 20,
                "run": 25000,
                "timer": {
                    "period": 50000,
                    "ref": "test"
                }
            },
            {
                "loop": 20,
                "run": 35000,
                "timer": {
                    "period": 50000,
                    "ref": "test"
                }
            },
            {
                "loop": 20,
                "run": 45000,
                "timer": {
                    "period": 50000,
                    "ref": "test"
                }
            },
            # Heavy phase:
            {
                "loop": 1,
                "run": 90000,
                "timer": {
                    "period": 100000,
                    "ref": "test"
                }
            }]

        self._do_test(profile, exp_phases)

    def test_invalid_composition(self):
        """Test that you can't compose tasks with a delay in the second task"""
        t1 = Periodic()
        t2 = Periodic(delay_s=1)

        # Should work fine if delayed task is the first one
        try:
            t3 = t2 + t1
        except Exception as e:
            raise AssertionError("Couldn't compose tasks: {}".format(e))

        # But not the other way around
        with self.assertRaises(ValueError):
            t3 = t1 + t2

class TestRTACustom(RTABase):
    def _test_custom_smoke(self, calibration):
        """
        Test RTA custom workload

        Creates an rt-app workload using 'custom' and checks that the json
        roughly matches the file we provided. If we have root, attempts to run
        the workload.
        """

        json_path = os.path.join(ASSET_DIR, 'mp3-short.json')

        with open(json_path, 'r') as fh:
            str_conf = fh.read()

        rtapp = RTA.by_str(
            self.target, name='test', str_conf=str_conf, res_dir=self.res_dir,
            max_duration_s=5, calibration=calibration)

        with open(rtapp.local_json, 'r') as fh:
            conf = json.load(fh)

        self.assertSetEqual(
            set(conf['tasks'].keys()),
            set(['AudioTick', 'AudioOut', 'AudioTrack',
                 'mp3.decoder', 'OMXCall']))

        # Would like to try running the workload but mp3-short.json has nonzero
        # 'priority' fields, and we probably don't have permission for that
        # unless we're root.
        if self.target.is_rooted:
            rtapp.run(as_root=True)

            # rtapp_cmds = [c for c in self.target.executed_commands
            #               if 'rt-app' in c]
            # self.assertListEqual(rtapp_cmds, [self.get_expected_command(rtapp)])

            self.assert_output_file_exists('output.log')
            self.assert_output_file_exists('test.json')

    def test_custom_smoke_calib(self):
        """Test RTA custom workload (providing calibration)"""
        calibration = min(self.target.plat_info['rtapp']['calib'].values())
        self._test_custom_smoke(calibration)

    def test_custom_smoke_no_calib(self):
        """Test RTA custom workload (providing no calibration)"""
        self._test_custom_smoke(None)

class TestRTACalibrationConf(RTABase):
    """Test setting the "calibration" field of rt-app config"""
    def _get_calib_conf(self, calibration):
        profile = {"test" : Periodic()}
        rtapp = RTA.by_profile(
            self.target, name='test', res_dir=self.res_dir, profile=profile,
            calibration=calibration)

        with open(rtapp.local_json) as fh:
            return json.load(fh)['global']['calibration']

    def test_calibration_conf_pload_nodata(self):
        """Test that the smallest pload value is used"""
        conf = self._get_calib_conf(None)
        self.assertEqual(conf, 100, 'Calibration not set to minimum pload value')

    def test_calibration_conf_pload_int(self):
        """Test that the calibration value is returned as expected"""
        conf = self._get_calib_conf(666)
        self.assertEqual(conf, 666, 'Calibration value modified')

    def test_calibration_conf_pload_str(self):
        """Test that the calibration value is returned as expected"""
        conf = self._get_calib_conf('CPU0')
        self.assertEqual(conf, 'CPU0', 'Calibration value modified')

# vim :set tabstop=4 shiftwidth=4 textwidth=80 expandtab
<|endoftext|>


<commit_before>import os
import unittest
from facturapdf import InvoiceGenerator
from tests.helper import get_output_folder, get_initios_logo_path
from os.path import isdir, isfile, splitext
from facturapdf.dtos import Customer, Metadata

class TestCase(unittest.TestCase):
    def assertIsFolder(self, folder):
        self.assertTrue(isdir(folder))

    def assertIsFile(self, file):
        self.assertTrue(isfile(file))

    def assertExtension(self, file, ext):
        self.assertTrue(splitext(file)[1] == '.pdf')

class CreateInvoiceTest(TestCase):
    def setUp(self):
        self.file = os.path.join(get_output_folder(), "output.pdf")
        self.initios_logo = get_initios_logo_path()
        self.invoice_generator = InvoiceGenerator()

    def test_can_create_a_invoice(self):
        customer = Customer(
            code='CUS1', name='Example Customer Name', vat='123456789X',
            address='Long address from our customer', city='Vigo',
            postal_code='309182', province='Pontevedra', country='España',
            contact_name='Customer Name', contact_phone='9876542817', contact_email='mymail@python.com'
        )
        rows = [['Producto de ejemplo %i' % i, i * 10, i * 100, i * 1000] for i in range(0, 27)]
        metadata = Metadata(
            doc_type='FACTURA', code='FRA SER 14-2014', serie='SER', date='01/12/2014'
        )
        header_text = 'Calle de la empresa 2, bajo - oficina 3'

        self.invoice_generator.generate(self.file, self.initios_logo, rows, customer, metadata, header_text)
        self.assertIsFile(self.file)
        self.assertExtension(self.file, 'pdf')<commit_msg>Fixed typo<commit_after>import os
import unittest
from facturapdf import InvoiceGenerator
from tests.helper import get_output_folder, get_initios_logo_path
from os.path import isdir, isfile, splitext
from facturapdf.dtos import Customer, Metadata

class TestCase(unittest.TestCase):
    def assertIsFolder(self, folder):
        self.assertTrue(isdir(folder))

    def assertIsFile(self, file):
        self.assertTrue(isfile(file))

    def assertExtension(self, file, ext):
        self.assertTrue(splitext(file)[1] == '.pdf')

class CreateInvoiceTest(TestCase):
    def setUp(self):
        self.file = os.path.join(get_output_folder(), "output.pdf")
        self.initios_logo = get_initios_logo_path()
        self.invoice_generator = InvoiceGenerator()

    def test_can_create_an_invoice(self):
        customer = Customer(
            code='CUS1', name='Example Customer Name', vat='123456789X',
            address='Long address from our customer', city='Vigo',
            postal_code='309182', province='Pontevedra', country='España',
            contact_name='Customer Name', contact_phone='9876542817', contact_email='mymail@python.com'
        )
        rows = [['Producto de ejemplo %i' % i, i * 10, i * 100, i * 1000] for i in range(0, 27)]
        metadata = Metadata(
            doc_type='FACTURA', code='FRA SER 14-2014', serie='SER', date='01/12/2014'
        )
        header_text = 'Calle de la empresa 2, bajo - oficina 3'

        self.invoice_generator.generate(self.file, self.initios_logo, rows, customer, metadata, header_text)
        self.assertIsFile(self.file)
        self.assertExtension(self.file, 'pdf')<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.urls import reverse
from django.test import TestCase

from .models import Restaurant, Type, Cuisine, Food

class RestaurantModelTests(TestCase):

    def test_restaurant_object_creation(self):
        """
        Restaurant object created must return true for isinstance() and
        __str__() must be equal to restaurant's name
        """
        restaurant = create_restaurant("Test Restaurant")
        self.assertIs(isinstance(restaurant, Restaurant), True)
        self.assertEqual(restaurant.__str__(), restaurant.name)

class TypeModelTests(TestCase):

    def test_type_object_creation(self):
        """
        Type object created must return true for isinstance() and
        __str__() must be equal to restaurant's type
        """
        restaurant_type = Type.objects.create(name="Test Restaurant Type")
        self.assertIs(isinstance(restaurant_type, Type), True)
        self.assertEqual(restaurant_type.__str__(), restaurant_type.name)

class CuisineModelTests(TestCase):

    def test_cuisine_object_creation(self):
        """
        Cuisine object created must return true for isinstance() and
        __str__() must be equal to cuisine name
        """
        cuisine = Cuisine.objects.create(name="Test Cuisine")
        self.assertIs(isinstance(cuisine, Cuisine), True)
        self.assertEqual(cuisine.__str__(), cuisine.name)

class FoodModelTests(TestCase):

    def test_food_object_creation(self):
        """
        Food object created must return true for isinstance() and
        __str__() must be equal to food name
        """
        cuisine = Cuisine.objects.create(name="Test Cuisine")
        food = Food.objects.create(name="Test Food", cuisine_id=cuisine.id)
        self.assertIs(isinstance(food, Food), True)
        self.assertEqual(food.__str__(), food.name)

class IndexViewTests(TestCase):

    def test_no_restaurants(self):
        """ If no Restaurant exists appropriate message should be displayed
        """
        response = self.client.get(reverse('webapp:index'))
        self.assertContains(response, "No restaurant added")
        self.assertQuerysetEqual(response.context['restaurant_list'], [])

    def test_one_restaurant(self):
        """ If one Restaurant exists it should be displayed in the index page
        """
        create_restaurant("Test Restaurant")
        response = self.client.get(reverse('webapp:index'))
        self.assertQuerysetEqual(response.context['restaurant_list'], [
                                 '<Restaurant: Test Restaurant>'])

    def test_two_restaurants(self):
        """ If two Restaurant exists both should be displayed in the index page
        """
        create_restaurant("Test Restaurant 1")
        create_restaurant("Test Restaurant 2")
        response = self.client.get(reverse('webapp:index'))
        self.assertQuerysetEqual(response.context['restaurant_list'],
                                 ['<Restaurant: Test Restaurant 2>',
                                     '<Restaurant: Test Restaurant 1>']
                                 )

class DetailViewTests(TestCase):

    def test_no_restaurant(self):
        """ If restaurant with given id is not found 404 error should be raise
        """
        response = self.client.get(reverse('webapp:detail', args=(1,)))
        self.assertEqual(response.status_code, 404)

    def test_with_restaurant(self):
        """ If restaurant exists restaurant details must shown in detail page
        """
        restaurant = create_restaurant("Test Restaurant")
        response = self.client.get(
            reverse('webapp:detail', args=(restaurant.id,)))
        self.assertEqual(
            response.context['restaurant'].name, 'Test Restaurant')

class SearchViewTests(TestCase):

    def test_no_matching_content(self):
        """ If search content doesnot match the restaurant name or type
        or restaurant doesnot exists, appropriate message should be shown
        """
        search_text = "test"
        response = self.client.post(reverse('webapp:search'), {
                                    'search_field': search_text})
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(response.context['search_list'], [])

    def test_name_matching_with_search_text(self):
        """ If search content match with the restaurant name
        that restaurant should be shown in the list
        """
        create_restaurant("Test Restaurant")
        search_text = "test"
        response = self.client.post(reverse('webapp:search'), {
                                    'search_field': search_text})
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(response.context['search_list'], [
                                 '<Restaurant: Test Restaurant>'])

    def test_type_matching_with_search_text(self):
        """ If search content match with the restaurant type
        that restaurant should be shown in the list
        """
        restaurant = create_restaurant("Test Restaurant")
        restaurant.types.create(name="Diner")
        search_text = "diner"
        response = self.client.post(reverse('webapp:search'), {
                                    'search_field': search_text})
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(response.context['search_list'], [
                                 '<Restaurant: Test Restaurant>'])

    def test_name_and_type_matching_with_search_text(self):
        """ If search content matches the restaurant name and type
        only one result of the matching restaurant should be shown
        """
        restaurant = create_restaurant("Diner Restaurant")
        restaurant.types.create(name="Diner")
        search_text = "diner"
        response = self.client.post(reverse('webapp:search'), {
                                    'search_field': search_text})
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(response.context['search_list'], [
                                 '<Restaurant: Diner Restaurant>'])

class RestaurantCreateViewTests(TestCase):

    def test_view_loads(self):
        """ View should be loaded for GET request
        """
        response = self.client.get(reverse('webapp:restaurant_create'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'webapp/restaurant_form.html')

    def test_view_fails_blank(self):
        """ Validation error should be shown if posted with blank data
        """
        response = self.client.post(reverse('webapp:restaurant_create'), {})
        self.assertFormError(response, 'form', 'name', 'This field is required.')

    def test_view_fails_invalid(self):
        """ Validation error should be shown if invalid data is posted
        """
        self.credentials = {
            'name': 'test',
            'description': 'test',
            'state': 'test',
            'city': 'test',
            'street': 'test',
            'longitude': 'error',
            'latitude': 0.000111,
            'telephone': '1234567890',
            'website': 'http://test.com'
        }
        response = self.client.post(reverse('webapp:restaurant_create'), self.credentials)
        self.assertFormError(response, 'form', 'longitude', 'Enter a number.')

    def test_view_valid_post(self):
        """ If there is no validation error then it should redirect to restaurant's detail page
        """
        self.credentials = {
            'name': 'test',
            'description': 'test',
            'state': 'test',
            'city': 'test',
            'street': 'test',
            'longitude': 0.000111,
            'latitude': 0.000111,
            'telephone': '1234567890',
            'website': 'http://test.com'
        }
        response = self.client.post(reverse('webapp:restaurant_create'), self.credentials)
        self.assertRedirects(response, reverse('webapp:detail', args=(1,)))

# Helper functions
def create_restaurant(restaurant_name):
    return Restaurant.objects.create(name=restaurant_name,
                                     description="test restaurant",
                                     state="test",
                                     city="test",
                                     street="test",
                                     longitude=0.0,
                                     latitude=0.0,
                                     telephone="test",
                                     website="test.com")
<commit_msg>Added tests for restaurant updating and deletion views<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.urls import reverse
from django.test import TestCase

import copy

from .models import Restaurant, Type, Cuisine, Food

CREDENTIIALS = {
            'name': 'test',
            'description': 'test',
            'state': 'test',
            'city': 'test',
            'street': 'test',
            'longitude': 0.000111,
            'latitude': 0.000111,
            'telephone': '1234567890',
            'website': 'http://test.com'
        }

class RestaurantModelTests(TestCase):

    def test_restaurant_object_creation(self):
        """
        Restaurant object created must return true for isinstance() and
        __str__() must be equal to restaurant's name
        """
        restaurant = create_restaurant("Test Restaurant")
        self.assertIs(isinstance(restaurant, Restaurant), True)
        self.assertEqual(restaurant.__str__(), restaurant.name)

class TypeModelTests(TestCase):

    def test_type_object_creation(self):
        """
        Type object created must return true for isinstance() and
        __str__() must be equal to restaurant's type
        """
        restaurant_type = Type.objects.create(name="Test Restaurant Type")
        self.assertIs(isinstance(restaurant_type, Type), True)
        self.assertEqual(restaurant_type.__str__(), restaurant_type.name)

class CuisineModelTests(TestCase):

    def test_cuisine_object_creation(self):
        """
        Cuisine object created must return true for isinstance() and
        __str__() must be equal to cuisine name
        """
        cuisine = Cuisine.objects.create(name="Test Cuisine")
        self.assertIs(isinstance(cuisine, Cuisine), True)
        self.assertEqual(cuisine.__str__(), cuisine.name)

class FoodModelTests(TestCase):

    def test_food_object_creation(self):
        """
        Food object created must return true for isinstance() and
        __str__() must be equal to food name
        """
        cuisine = Cuisine.objects.create(name="Test Cuisine")
        food = Food.objects.create(name="Test Food", cuisine_id=cuisine.id)
        self.assertIs(isinstance(food, Food), True)
        self.assertEqual(food.__str__(), food.name)

class IndexViewTests(TestCase):

    def test_no_restaurants(self):
        """ If no Restaurant exists appropriate message should be displayed
        """
        response = self.client.get(reverse('webapp:index'))
        self.assertContains(response, "No restaurant added")
        self.assertQuerysetEqual(response.context['restaurant_list'], [])

    def test_one_restaurant(self):
        """ If one Restaurant exists it should be displayed in the index page
        """
        create_restaurant("Test Restaurant")
        response = self.client.get(reverse('webapp:index'))
        self.assertQuerysetEqual(response.context['restaurant_list'], [
                                 '<Restaurant: Test Restaurant>'])

    def test_two_restaurants(self):
        """ If two Restaurant exists both should be displayed in the index page
        """
        create_restaurant("Test Restaurant 1")
        create_restaurant("Test Restaurant 2")
        response = self.client.get(reverse('webapp:index'))
        self.assertQuerysetEqual(response.context['restaurant_list'],
                                 ['<Restaurant: Test Restaurant 2>',
                                     '<Restaurant: Test Restaurant 1>']
                                 )

class DetailViewTests(TestCase):

    def test_no_restaurant(self):
        """ If restaurant with given id is not found 404 error should be raise
        """
        response = self.client.get(reverse('webapp:detail', args=(1,)))
        self.assertEqual(response.status_code, 404)

    def test_with_restaurant(self):
        """ If restaurant exists restaurant details must shown in detail page
        """
        restaurant = create_restaurant("Test Restaurant")
        response = self.client.get(
            reverse('webapp:detail', args=(restaurant.id,)))
        self.assertEqual(
            response.context['restaurant'].name, 'Test Restaurant')

class SearchViewTests(TestCase):

    def test_no_matching_content(self):
        """ If search content doesnot match the restaurant name or type
        or restaurant doesnot exists, appropriate message should be shown
        """
        search_text = "test"
        response = self.client.post(reverse('webapp:search'), {
                                    'search_field': search_text})
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(response.context['search_list'], [])

    def test_name_matching_with_search_text(self):
        """ If search content match with the restaurant name
        that restaurant should be shown in the list
        """
        create_restaurant("Test Restaurant")
        search_text = "test"
        response = self.client.post(reverse('webapp:search'), {
                                    'search_field': search_text})
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(response.context['search_list'], [
                                 '<Restaurant: Test Restaurant>'])

    def test_type_matching_with_search_text(self):
        """ If search content match with the restaurant type
        that restaurant should be shown in the list
        """
        restaurant = create_restaurant("Test Restaurant")
        restaurant.types.create(name="Diner")
        search_text = "diner"
        response = self.client.post(reverse('webapp:search'), {
                                    'search_field': search_text})
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(response.context['search_list'], [
                                 '<Restaurant: Test Restaurant>'])

    def test_name_and_type_matching_with_search_text(self):
        """ If search content matches the restaurant name and type
        only one result of the matching restaurant should be shown
        """
        restaurant = create_restaurant("Diner Restaurant")
        restaurant.types.create(name="Diner")
        search_text = "diner"
        response = self.client.post(reverse('webapp:search'), {
                                    'search_field': search_text})
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(response.context['search_list'], [
                                 '<Restaurant: Diner Restaurant>'])

class RestaurantCreateViewTests(TestCase):

    def test_view_loads(self):
        """ View should be loaded for GET request
        """
        response = self.client.get(reverse('webapp:restaurant_create'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'webapp/restaurant_form.html')

    def test_view_fails_blank(self):
        """ Validation error should be shown if posted with blank data
        """
        response = self.client.post(reverse('webapp:restaurant_create'), {})
        self.assertFormError(response, 'form', 'name', 'This field is required.')

    def test_view_fails_invalid(self):
        """ Validation error should be shown if invalid data is posted
        """
        self.credentials = CREDENTIIALS.copy()
        self.credentials['longitude'] = 'error'
        response = self.client.post(reverse('webapp:restaurant_create'), self.credentials)
        self.assertFormError(response, 'form', 'longitude', 'Enter a number.')

    def test_view_valid_post(self):
        """ If there is no validation error then it should redirect to restaurant's detail page
        """
        response = self.client.post(reverse('webapp:restaurant_create'), CREDENTIIALS)
        self.assertRedirects(response, reverse('webapp:detail', args=(1,)))

class RestaurantUpdateViewTests(TestCase):

    def test_no_restaurant(self):
        """ If restaurant with given id is not found 404 error should be raise
        """
        response = self.client.post(reverse('webapp:restaurant_update', args=(1,)))
        self.assertEqual(response.status_code, 404)

    def test_view_loads(self):
        """ View loaded with data related to restaurant should be loaded for GET request
        """
        restaurant = create_restaurant("Test Restaurant")
        response = self.client.get(reverse('webapp:restaurant_update', args=(restaurant.id,)))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'webapp/restaurant_form.html')

    def test_view_fails_invalid(self):
        """ Validation error in updating should be shown if invalid data is posted
        """
        restaurant = create_restaurant("Test Restaurant")
        self.credentials = CREDENTIIALS.copy()
        self.credentials['longitude'] = 'error'
        response = self.client.post(reverse('webapp:restaurant_update', args=(restaurant.id,)), self.credentials)
        self.assertFormError(response, 'form', 'longitude', 'Enter a number.')

    def test_view_valid_post(self):
        """ If there is no validation error then it should redirect to restaurant's detail page
        """
        restaurant = create_restaurant("Test Restaurant")
        response = self.client.post(reverse('webapp:restaurant_update', args=(restaurant.id,)), CREDENTIIALS)
        self.assertRedirects(response, reverse('webapp:detail', args=(1,)))

    def test_view_delete_restaurant(self):
        """ If there is delete_btn in POST request submission the restaurant object
        should be deleted and page must be redirected to index page"
        """
        restaurant = create_restaurant("Test Restaurant")
        response = self.client.post(reverse('webapp:restaurant_update', args=(restaurant.id,)), {'delete_btn':'delete_btn'})
        self.assertRedirects(response, reverse('webapp:index'))

# Helper functions
def create_restaurant(restaurant_name):
    return Restaurant.objects.create(name=restaurant_name,
                                     description="test restaurant",
                                     state="test",
                                     city="test",
                                     street="test",
                                     longitude=0.0,
                                     latitude=0.0,
                                     telephone="test",
                                     website="test.com")
<|endoftext|>


<commit_before>#!/usr/bin/env python2

INVLIST_URL = 'http://dev.tsadm.local:8000/asb/inv/lst/'

import sys
import os.path

from urllib2 import urlopen

run_mode = ''
if sys.argv[0].endswith('test.py'):
    run_mode = 'test'
elif sys.argv[0].endswith('dev.py'):
    run_mode = 'dev'
print(run_mode)

if len(sys.argv) >= 2 and sys.argv[1] == '--list':
    try:
        print(urlopen(INVLIST_URL, timeout=15).read())
    except Exception as e:
        print(INVLIST_URL, str(e))
else:
    print('{}')

sys.exit(0)
<commit_msg>remove old code<commit_after>#!/usr/bin/env python2

INVLIST_URL = 'http://dev.tsadm.local:8000/asb/inv/lst/'

import sys
import os.path

from urllib2 import urlopen

if len(sys.argv) >= 2 and sys.argv[1] == '--list':
    try:
        print(urlopen(INVLIST_URL, timeout=15).read())
    except Exception as e:
        print(INVLIST_URL, str(e))
else:
    print('{}')

sys.exit(0)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2012 OpenERP - Team de Localización Argentina.
# https://launchpad.net/~openerp-l10n-ar-localization
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import fields, osv
from openerp.tools.translate import _
import re
import logging

_logger = logging.getLogger(__name__)

# Label filter to recover invoice number
re_label = re.compile(r'%\([^\)]+\)s')

# Functions to list parents names.
def _get_parents(child, parents=[]):
    if child:
        return parents + [ child.name ] + _get_parents(child.parent_id)
    else:
        return parents

class invoice(osv.osv):
    _inherit = "account.invoice"
    _columns = {
        'afip_result': fields.selection([
            ('', 'No CAE'),
            ('A', 'Accepted'),
            ('R', 'Rejected'),
        ], 'Status', help='This state is asigned by the AFIP. If * No CAE * state mean you have no generate this invoice by '),
        'afip_batch_number': fields.integer('Batch Number', readonly=True),
        'afip_cae': fields.char('CAE number', size=24),
        'afip_cae_due': fields.date('CAE due'),
        'afip_error_id': fields.many2one('afip.wsfe_error', 'AFIP Status', readonly=True),
    }

    _defaults = {
        'afip_result': '',
    }

    def valid_batch(self, cr, uid, ids, *args):
        """
        Increment batch number groupping by afip connection server.
        """
        seq_obj = self.pool.get('ir.sequence')

        conns = []
        invoices = {}
        for inv in self.browse(cr, uid, ids):
            conn = inv.journal_id.afip_connection_id
            if not conn: continue
            if inv.journal_id.afip_items_generated + 1 != inv.journal_id.sequence_id.number_next:
                raise osv.except_osv(_(u'Syncronization Error'),
                                     _(u'La AFIP espera que el próximo número de secuencia sea %i, pero el sistema indica que será %i. Hable inmediatamente con su administrador del sistema para resolver este problema.') %
                                     (inv.journal_id.afip_items_generated + 1, inv.journal_id.sequence_id.number_next))
            conns.append(conn)
            invoices[conn.id] = invoices.get(conn.id, []) + [inv.id]

        for conn in conns:
            prefix = conn.batch_sequence_id.prefix or ''
            suffix = conn.batch_sequence_id.suffix or ''
            sid_re = re.compile('%s(\d*)%s' % (prefix, suffix))
            sid = seq_obj.next_by_id(cr, uid, conn.batch_sequence_id.id)
            self.write(cr, uid, invoices[conn.id], {
                'afip_batch_number': int(sid_re.search(sid).group(1)),
            })

        return True

    def get_related_invoices(self, cr, uid, ids, *args):
        """
        List related invoice information to fill CbtesAsoc
        """
        r = {}
        _ids = [ids] if isinstance(ids, int) else ids

        for inv in self.browse(cr, uid, _ids):
            r[inv.id] = []
            rel_inv_ids = self.search(cr, uid, [('number','=',inv.origin),
                                                ('state','not in',['draft','proforma','proforma2','cancel'])])
            for rel_inv in self.browse(cr, uid, rel_inv_ids):
                journal = rel_inv.journal_id
                r[inv.id].append({
                    'Tipo': journal.journal_class_id.afip_code,
                    'PtoVta': journal.point_of_sale,
                    'Nro': rel_inv.invoice_number,
                })

        return r[ids] if isinstance(ids, int) else r

    def get_taxes(self, cr, uid, ids, *args):
        r = {}
        _ids = [ids] if isinstance(ids, int) else ids

        for inv in self.browse(cr, uid, _ids):
            r[inv.id] = []

            for tax in inv.tax_line:
                if tax.account_id.name == 'IVA a pagar':
                    continue
                if tax.tax_code_id:
                    r[inv.id].append({
                        'Id': tax.tax_code_id.parent_afip_code,
                        'Desc': tax.tax_code_id.name,
                        'BaseImp': tax.base_amount,
                        'Alic': (tax.tax_amount / tax.base_amount),
                        'Importe': tax.tax_amount,
                    })
                else:
                    raise osv.except_osv(_(u'TAX without tax-code'),
                                         _(u'Please, check if you set tax code for invoice or refund to tax %s.') % tax.name)

        return r[ids] if isinstance(ids, int) else r

    def get_vat(self, cr, uid, ids, *args):
        r = {}
        _ids = [ids] if isinstance(ids, int) else ids

        for inv in self.browse(cr, uid, _ids):
            r[inv.id] = []

            for tax in inv.tax_line:
                if tax.account_id.name != 'IVA a pagar':
                    continue
                r[inv.id].append({
                    'Id': tax.tax_code_id.parent_afip_code,
                    'BaseImp': tax.base_amount,
                    'Importe': tax.tax_amount,
                })

        return r[ids] if isinstance(ids, int) else r

    def get_optionals(self, cr, uid, ids, *args):
        optional_type_obj = self.pool.get('afip.optional_type')

        r = {}
        _ids = [ids] if isinstance(ids, int) else ids
        optional_type_ids = optional_type_obj.search(cr, uid, [])

        for inv in self.browse(cr, uid, _ids):
            r[inv.id] = []
            for optional_type in optional_type_obj.browse(cr, uid, optional_type_ids):
                if optional_type.apply_rule and optional_type.value_computation:
                    """
                    Debería evaluar apply_rule para saber si esta opción se computa
                    para esta factura. Y si se computa, se evalua value_computation
                    sobre la factura y se obtiene el valor que le corresponda.
                    Luego se debe agregar al output r.
                    """
                    raise NotImplemented

        return r[ids] if isinstance(ids, int) else r

    def action_retrieve_cae(self, cr, uid, ids, context=None):
        """
        Contact to the AFIP to get a CAE number.
        """
        if context is None:
            context = {}
        #TODO: not correct fix but required a frech values before reading it.
        self.write(cr, uid, ids, {})

        wsfe_error_obj = self.pool.get('afip.wsfe_error')
        conn_obj = self.pool.get('wsafip.connection')
        serv_obj = self.pool.get('wsafip.server')
        currency_obj = self.pool.get('res.currency')

        Servers = {}
        Requests = {}
        Inv2id = {}

        for inv in self.browse(cr, uid, ids, context=context):
            journal = inv.journal_id
            conn = journal.afip_connection_id

            # Ignore journals with cae
            if inv.afip_cae and inv.afip_cae_due: continue

            # Only process if set to connect to afip
            if not conn: continue

            # Ignore invoice if connection server is not type WSFE.
            if conn.server_id.code != 'wsfe': continue

            Servers[conn.id] = conn.server_id.id

            # Take the last number of the "number".
            prefix_re = ".*".join([ re.escape(w) for w in re_label.split(inv.journal_id.sequence_id.prefix or "")])
            suffix_re = ".*".join([ re.escape(w) for w in re_label.split(inv.journal_id.sequence_id.suffix or "")])
            re_number = re.compile(prefix_re + r"(\d+)" + suffix_re)
            invoice_number = int(re_number.search(inv.number).group(1) or -1)

            if invoice_number < 0:
                raise osv.except_osv(_(u'AFIP Validation Error'), _("Can't find invoice number. Please check the journal sequence prefix and suffix are not breaking the number generator."))

            _f_date = lambda d: d and d.replace('-','')

            # Build request dictionary
            if conn.id not in Requests: Requests[conn.id] = {}
            assert inv.currency_id.afip_code, 'Must defined afip_code for the currency.'
            Requests[conn.id][inv.id]=dict( (k,v) for k,v in {
                'CbteTipo': journal.journal_class_id.afip_code,
                'PtoVta': journal.point_of_sale,
                'Concepto': inv.afip_concept,
                'DocTipo': inv.partner_id.document_type_id.afip_code or '99',
                'DocNro': int(inv.partner_id.document_type_id.afip_code is not None and inv.partner_id.document_number),
                'CbteDesde': invoice_number,
                'CbteHasta': invoice_number,
                'CbteFch': _f_date(inv.date_invoice),
                'ImpTotal': inv.amount_total,
                'ImpTotConc': 0, # TODO: Averiguar como calcular el Importe Neto no Gravado
                'ImpNeto': inv.amount_untaxed,
                'ImpOpEx': inv.compute_all(line_filter=lambda line: len(line.invoice_line_tax_id)==0)['amount_total'],
                'ImpIVA': inv.compute_all(tax_filter=lambda tax: 'IVA' in _get_parents(tax.tax_code_id))['amount_tax'],
                'ImpTrib': inv.compute_all(tax_filter=lambda tax: 'IVA' not in _get_parents(tax.tax_code_id))['amount_tax'],
                'FchServDesde': _f_date(inv.afip_service_start) if inv.afip_concept != '1' else None,
                'FchServHasta': _f_date(inv.afip_service_end) if inv.afip_concept != '1' else None,
                'FchVtoPago': _f_date(inv.date_due) if inv.afip_concept != '1' else None,
                'MonId': inv.currency_id.afip_code,
                'MonCotiz': currency_obj.compute(cr, uid, inv.currency_id.id, inv.company_id.currency_id.id, 1.),
                'CbtesAsoc': [ {'CbteAsoc': c} for c in self.get_related_invoices(cr, uid, inv.id) ],
                'Tributos': [ {'Tributo': t} for t in self.get_taxes(cr, uid, inv.id) ],
                'Iva': [ {'AlicIva': a} for a in self.get_vat(cr, uid, inv.id) ],
                'Opcionales': [ {'Opcional': o} for o in self.get_optionals(cr, uid, inv.id) ],
            }.iteritems() if v is not None)
            Inv2id[invoice_number] = inv.id

        for c_id, req in Requests.iteritems():
            conn = conn_obj.browse(cr, uid, c_id)
            res = serv_obj.wsfe_get_cae(cr, uid, [conn.server_id.id], c_id, req)
            for k, v in res.iteritems():
                if 'CAE' in v:
                    self.write(cr, uid, Inv2id[k], {
                        'afip_cae': v['CAE'],
                        'afip_cae_due': v['CAEFchVto'],
                    })
                else:
                    # Muestra un mensaje de error por la factura con error.
                    # Se cancelan todas las facturas del batch!
                    msg = 'Factura %s:\n' % k + '\n'.join(
                        [ u'(%s) %s\n' % e for e in v['Errores']] +
                        [ u'(%s) %s\n' % e for e in v['Observaciones']]
                    )
                    raise osv.except_osv(_(u'AFIP Validation Error'), msg)

        return True

    def invoice_print(self, cr, uid, ids, context=None):
        '''
        This function prints the invoice and mark it as sent, so that we can see more easily the next step of the workflow
        Check if electronic invoice or normal invoice.
        '''
        assert len(ids) == 1, 'This option should only be used for a single id at a time.'
        self.write(cr, uid, ids, {'sent': True}, context=context)
        datas = {
            'ids': ids,
            'model': 'account.invoice',
            'form': self.read(cr, uid, ids[0], context=context)
        }
        is_electronic = bool(self.browse(cr, uid, ids[0]).journal_id.afip_connection_id)
        return {
            'type': 'ir.actions.report.xml',
            'report_name': 'l10n_ar_wsafip_fe.report_invoice' if is_electronic else 'account.report_invoice',
            'datas': datas,
            'nodestroy' : True
        }

invoice()

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<commit_msg>[REF] Pep8<commit_after># -*- coding: utf-8 -*-
from openerp.osv import fields, osv
from openerp.tools.translate import _
import re
import logging

_logger = logging.getLogger(__name__)

# Label filter to recover invoice number
re_label = re.compile(r'%\([^\)]+\)s')

def _get_parents(child, parents=[]):
    "Functions to list parents names."
    if child:
        return parents + [child.name] + _get_parents(child.parent_id)
    else:
        return parents

class invoice(osv.osv):
    _inherit = "account.invoice"
    _columns = {
        'afip_result': fields.selection([
            ('', 'No CAE'),
            ('A', 'Accepted'),
            ('R', 'Rejected'),
        ], 'Status', help='This state is asigned by the AFIP. '
            'If * No CAE * state mean you have no generate this invoice by '),
        'afip_batch_number': fields.integer('Batch Number', readonly=True),
        'afip_cae': fields.char('CAE number', size=24),
        'afip_cae_due': fields.date('CAE due'),
        'afip_error_id': fields.many2one('afip.wsfe_error', 'AFIP Status',
                                         readonly=True),
    }

    _defaults = {
        'afip_result': '',
    }

    def valid_batch(self, cr, uid, ids, *args):
        """
        Increment batch number groupping by afip connection server.
        """
        seq_obj = self.pool.get('ir.sequence')

        conns = []
        invoices = {}
        for inv in self.browse(cr, uid, ids):
            conn = inv.journal_id.afip_connection_id
            if not conn:
                continue
            if inv.journal_id.afip_items_generated + 1 != \
                    inv.journal_id.sequence_id.number_next:
                raise osv.except_osv(
                    _(u'Syncronization Error'),
                    _(u'La AFIP espera que el próximo número de secuencia sea '
                      u'%i, pero el sistema indica que será %i. '
                      u'Hable inmediatamente con su administrador del '
                      u'sistema para resolver este problema.') %
                    (inv.journal_id.afip_items_generated + 1,
                     inv.journal_id.sequence_id.number_next))
            conns.append(conn)
            invoices[conn.id] = invoices.get(conn.id, []) + [inv.id]

        for conn in conns:
            prefix = conn.batch_sequence_id.prefix or ''
            suffix = conn.batch_sequence_id.suffix or ''
            sid_re = re.compile('%s(\d*)%s' % (prefix, suffix))
            sid = seq_obj.next_by_id(cr, uid, conn.batch_sequence_id.id)
            self.write(cr, uid, invoices[conn.id], {
                'afip_batch_number': int(sid_re.search(sid).group(1)),
            })

        return True

    def get_related_invoices(self, cr, uid, ids, *args):
        """
        List related invoice information to fill CbtesAsoc
        """
        r = {}
        _ids = [ids] if isinstance(ids, int) else ids

        for inv in self.browse(cr, uid, _ids):
            r[inv.id] = []
            rel_inv_ids = self.search(cr, uid, [
                ('number', '=', inv.origin),
                ('state', 'not in', ['draft',
                                     'proforma',
                                     'proforma2',
                                     'cancel'])])
            for rel_inv in self.browse(cr, uid, rel_inv_ids):
                journal = rel_inv.journal_id
                r[inv.id].append({
                    'Tipo': journal.journal_class_id.afip_code,
                    'PtoVta': journal.point_of_sale,
                    'Nro': rel_inv.invoice_number,
                })

        return r[ids] if isinstance(ids, int) else r

    def get_taxes(self, cr, uid, ids, *args):
        r = {}
        _ids = [ids] if isinstance(ids, int) else ids

        for inv in self.browse(cr, uid, _ids):
            r[inv.id] = []

            for tax in inv.tax_line:
                if 'IVA' in _get_parents(tax.tax_code_id):
                    continue
                if tax.tax_code_id:
                    r[inv.id].append({
                        'Id': tax.tax_code_id.parent_afip_code,
                        'Desc': tax.tax_code_id.name,
                        'BaseImp': tax.base_amount,
                        'Alic': (tax.tax_amount / tax.base_amount),
                        'Importe': tax.tax_amount,
                    })
                else:
                    raise osv.except_osv(
                        _(u'TAX without tax-code'),
                        _(u'Please, check if you set tax code for '
                          u'invoice or refund to tax %s.') % tax.name)

        return r[ids] if isinstance(ids, int) else r

    def get_vat(self, cr, uid, ids, *args):
        r = {}
        _ids = [ids] if isinstance(ids, int) else ids

        for inv in self.browse(cr, uid, _ids):
            r[inv.id] = []

            for tax in inv.tax_line:
                if 'IVA' not in _get_parents(tax.tax_code_id):
                    continue
                r[inv.id].append({
                    'Id': tax.tax_code_id.parent_afip_code,
                    'BaseImp': tax.base_amount,
                    'Importe': tax.tax_amount,
                })

        return r[ids] if isinstance(ids, int) else r

    def get_optionals(self, cr, uid, ids, *args):
        opt_type_obj = self.pool.get('afip.opt_type')

        r = {}
        _ids = [ids] if isinstance(ids, int) else ids
        opt_type_ids = opt_type_obj.search(cr, uid, [])

        for inv in self.browse(cr, uid, _ids):
            r[inv.id] = []
            for opt_type in opt_type_obj.browse(cr, uid, opt_type_ids):
                if opt_type.apply_rule and opt_type.value_computation:
                    """
                    Debería evaluar apply_rule para saber si esta opción se
                    computa para esta factura. Y si se computa, se evalua
                    value_computation sobre la factura y se obtiene el valor
                    que le corresponda.  Luego se debe agregar al output r.
                    """
                    raise NotImplemented

        return r[ids] if isinstance(ids, int) else r

    def action_retrieve_cae(self, cr, uid, ids, context=None):
        """
        Contact to the AFIP to get a CAE number.
        """
        if context is None:
            context = {}
        # TODO: not correct fix but required a frech values before reading it.
        self.write(cr, uid, ids, {})

        conn_obj = self.pool.get('wsafip.connection')
        serv_obj = self.pool.get('wsafip.server')
        currency_obj = self.pool.get('res.currency')

        Servers = {}
        Requests = {}
        Inv2id = {}

        for inv in self.browse(cr, uid, ids, context=context):
            journal = inv.journal_id
            conn = journal.afip_connection_id

            # Ignore journals with cae
            if inv.afip_cae and inv.afip_cae_due:
                continue

            # Only process if set to connect to afip
            if not conn:
                continue

            # Ignore invoice if connection server is not type WSFE.
            if conn.server_id.code != 'wsfe':
                continue

            Servers[conn.id] = conn.server_id.id

            # Take the last number of the "number".
            prefix_re = ".*".join([
                re.escape(w)
                for w in re_label.split(inv.journal_id.sequence_id.prefix or "")
            ])
            suffix_re = ".*".join([
                re.escape(w)
                for w in re_label.split(inv.journal_id.sequence_id.suffix or "")
            ])
            re_number = re.compile(prefix_re + r"(\d+)" + suffix_re)
            invoice_number = int(re_number.search(inv.number).group(1) or -1)

            if invoice_number < 0:
                raise osv.except_osv(
                    _(u'AFIP Validation Error'),
                    _("Can't find invoice number. "
                      "Please check the journal sequence prefix and suffix "
                      "are not breaking the number generator."))

            def _f_date(d):
                return d and d.replace('-', '')

            def _iva_filter(t):
                return 'IVA' in _get_parents(t.tax_code_id)

            def _not_iva_filter(t):
                return 'IVA' not in _get_parents(t.tax_code_id)

            # Build request dictionary
            if conn.id not in Requests:
                Requests[conn.id] = {}

            assert inv.currency_id.afip_code, \
                'Must defined afip_code for the currency.'

            Requests[conn.id][inv.id] = dict((k, v) for k, v in {
                'CbteTipo': journal.journal_class_id.afip_code,
                'PtoVta': journal.point_of_sale,
                'Concepto': inv.afip_concept,
                'DocTipo': inv.partner_id.document_type_id.afip_code or '99',
                'DocNro': int(inv.partner_id.document_number
                              if inv.partner_id.document_type_id.afip_code
                              is not None
                              else False),
                'CbteDesde': invoice_number,
                'CbteHasta': invoice_number,
                'CbteFch': _f_date(inv.date_invoice),
                'ImpTotal': inv.amount_total,
                # TODO:
                # Averiguar como calcular el Importe Neto no Gravado
                'ImpTotConc': 0,
                'ImpNeto': inv.amount_untaxed,
                'ImpOpEx': inv.compute_all(
                    line_filter=lambda line: len(line.invoice_line_tax_id) == 0
                )['amount_total'],
                'ImpIVA': inv.compute_all(
                    tax_filter=_iva_filter)['amount_tax'],
                'ImpTrib': inv.compute_all(
                    tax_filter=_not_iva_filter)['amount_tax'],
                'FchServDesde': _f_date(inv.afip_service_start)
                if inv.afip_concept != '1' else None,
                'FchServHasta': _f_date(inv.afip_service_end)
                if inv.afip_concept != '1' else None,
                'FchVtoPago': _f_date(inv.date_due)
                if inv.afip_concept != '1' else None,
                'MonId': inv.currency_id.afip_code,
                'MonCotiz': currency_obj.compute(
                    cr, uid,
                    inv.currency_id.id, inv.company_id.currency_id.id, 1.),
                'CbtesAsoc': [
                    {'CbteAsoc': c}
                    for c in self.get_related_invoices(cr, uid, inv.id)],
                'Tributos': [
                    {'Tributo': t}
                    for t in self.get_taxes(cr, uid, inv.id)],
                'Iva': [
                    {'AlicIva': a}
                    for a in self.get_vat(cr, uid, inv.id)],
                'Opcionales': [
                    {'Opcional': o}
                    for o in self.get_optionals(cr, uid, inv.id)],
            }.iteritems() if v is not None)
            Inv2id[invoice_number] = inv.id

        for c_id, req in Requests.iteritems():
            conn = conn_obj.browse(cr, uid, c_id)
            res = serv_obj.wsfe_get_cae(cr, uid, [conn.server_id.id], c_id, req)
            for k, v in res.iteritems():
                if 'CAE' in v:
                    self.write(cr, uid, Inv2id[k], {
                        'afip_cae': v['CAE'],
                        'afip_cae_due': v['CAEFchVto'],
                    })
                else:
                    # Muestra un mensaje de error por la factura con error.
                    # Se cancelan todas las facturas del batch!
                    msg = 'Factura %s:\n' % k + '\n'.join(
                        [u'(%s) %s\n' % e for e in v['Errores']] +
                        [u'(%s) %s\n' % e for e in v['Observaciones']]
                    )
                    raise osv.except_osv(_(u'AFIP Validation Error'), msg)

        return True

    def invoice_print(self, cr, uid, ids, context=None):
        '''
        This function prints the invoice and mark it as sent,
        so that we can see more easily the next step of the workflow
        Check if electronic invoice or normal invoice.
        '''
        assert len(ids) == 1, \
            'This option should only be used for a single id at a time.'
        self.write(cr, uid, ids, {'sent': True}, context=context)
        datas = {
            'ids': ids,
            'model': 'account.invoice',
            'form': self.read(cr, uid, ids[0], context=context)
        }
        is_electronic = bool(
            self.browse(cr, uid, ids[0]).journal_id.afip_connection_id)
        return {
            'type': 'ir.actions.report.xml',
            'report_name': 'l10n_ar_wsafip_fe.report_invoice'
            if is_electronic else 'account.report_invoice',
            'datas': datas,
            'nodestroy': True
        }

invoice()

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


<commit_before>"""
Flash app that listens for GitHub web hooks
and triggers Jenkins jobs
"""
import json
import logging
import os
import sys
from pkg_resources import resource_filename

import jenkinsapi.jenkins as Jenkins
from flask import Flask, request

app = Flask(__name__)

from .config import Config

# log to stderr
logger = logging.getLogger('jenkins-webhooks')
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())

# read the config and setup Jenkins API
config_file = resource_filename(__package__, 'config.yaml')
config = Config.from_yaml(config_file)

jenkins = Jenkins.Jenkins(config.get_jenkins_host())

@app.route("/github-webhook/", methods=['POST'])
def index():
    """
    Process web hook request from GitHub
    """
    if request.headers.get('X-GitHub-Event') == "ping":
        return json.dumps({'msg': 'Hi!'})
    if request.headers.get('X-GitHub-Event') != "push":
        return json.dumps({'msg': "wrong event type"})

    # decode the payload
    # @see examples/push.json
    # @see https://developer.github.com/v3/activity/events/types/#pushevent
    payload = json.loads(request.data)
    meta = {
        'owner': payload['repository']['owner']['name'],
        'name': payload['repository']['name'],
        'branch': payload['ref'].replace('refs/heads/', ''),
        'author': payload['head_commit']['author']['name'],
        'commit': payload['head_commit']['id']
    }

    logger.info("Push received: %s", json.dumps(meta))

    # try to match the push with list of rules from the config file
    repo = '%s/%s' % (meta['owner'], meta['name'])
    match = config.get_match(repo, meta['branch'])

    if match is not None:
        logger.info("Push matches: %s", json.dumps(match))

        # run jobs
        job_params = {
            'branch': meta['branch'],
            'commit': meta['commit'],
            'author': meta['author']
        }

        if 'jobs' in match:
            for job_name in match['jobs']:
                logger.info("Running %s with params: %s", job_name, job_params)
                jenkins.build_job(job_name, job_params)
    else:
        logger.info("No match found")

    return 'OK'

def run():
    """
    Initialize Flask app
    """
    try:
        port_number = int(sys.argv[1])
    except:
        port_number = 8088

    logger.info("Starting a Flask app on port %d", port_number)

    is_dev = os.environ.get('DEBUG', None) == '1'
    if is_dev:
        logging.basicConfig(level=logging.DEBUG)

    app.run(host='0.0.0.0', port=port_number, debug=is_dev)

if __name__ == "__main__":
    run()
<commit_msg>Improve logging of requests<commit_after>"""
Flash app that listens for GitHub web hooks
and triggers Jenkins jobs
"""
import json
import logging
import os
import sys
from pkg_resources import resource_filename

import jenkinsapi.jenkins as Jenkins
from flask import Flask, request

app = Flask(__name__)

from .config import Config

# log to stderr
logger = logging.getLogger('jenkins-webhooks')
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())

# read the config and setup Jenkins API
config_file = resource_filename(__package__, 'config.yaml')
config = Config.from_yaml(config_file)

jenkins = Jenkins.Jenkins(config.get_jenkins_host())

@app.route("/github-webhook/", methods=['POST'])
def index():
    """
    Process web hook request from GitHub
    """
    event_type = request.headers.get('X-GitHub-Event')
    payload = request.get_json()

    logger.info("GitHub event type: %s", event_type)
    logger.info("JSON payload: %s", json.dumps(payload))

    if event_type == "ping":
        return json.dumps({'msg': 'Hi!'})
    if event_type != "push":
        return json.dumps({'msg': "wrong event type"})

    # decode the payload
    # @see examples/push.json
    # @see https://developer.github.com/v3/activity/events/types/#pushevent
    meta = {
        'owner': payload['repository']['owner']['name'],
        'name': payload['repository']['name'],
        'branch': payload['ref'].replace('refs/heads/', ''),
        'author': payload['head_commit']['author']['name'],
        'commit': payload['head_commit']['id']
    }

    logger.info("Push received: %s", json.dumps(meta))

    # try to match the push with list of rules from the config file
    repo = '%s/%s' % (meta['owner'], meta['name'])
    match = config.get_match(repo, meta['branch'])

    if match is not None:
        logger.info("Push matches: %s", json.dumps(match))

        # run jobs
        job_params = {
            'branch': meta['branch'],
            'commit': meta['commit'],
            'author': meta['author']
        }

        if 'jobs' in match:
            for job_name in match['jobs']:
                logger.info("Running %s with params: %s", job_name, job_params)
                jenkins.build_job(job_name, job_params)
    else:
        logger.info("No match found")

    return 'OK'

def run():
    """
    Initialize Flask app
    """
    try:
        port_number = int(sys.argv[1])
    except:
        port_number = 8088

    logger.info("Starting a Flask app on port %d", port_number)

    # is_dev = os.environ.get('DEBUG', None) == '1'
    is_dev = True  # force debug mode
    if is_dev:
        logging.basicConfig(level=logging.DEBUG)

    app.run(host='0.0.0.0', port=port_number, debug=is_dev)

if __name__ == "__main__":
    run()
<|endoftext|>


<commit_before>#!/usr/bin/python
"""
recv.py

Receive file contents from stdin, write to the base directory, and print
filename on stdout.

A main use case is to emulate the print-events (inotifywait) interface, but
on a remote machine.  webpipe send takes the filename stdin, the file is
transferred from remote to local, and webpipe recv echoes the filename to
stdout.
"""

import os
import sys

# outside
import tnet

class Error(Exception):
  pass

def log(msg, *args):
  if args:
    msg = msg % args
  print >>sys.stderr, 'recv: ' + msg

# Wrapper around tnet.laod
# - string or dict
# - True for error success
# - False for error fail

def GenRecords(f):
  while True:
    try:
      v = tnet.load(f)
      if not isinstance(v, (str, dict)):  # byte string or dict
        log('Invalid value %r', v)
        yield False
      yield v
    except ValueError, e:
      log('fatal: %s', e)
      yield False  # fatal error
    except EOFError:
      yield True  # end of stream, success

def main(argv):
  """Returns an exit code."""

  base_dir = argv[1]

  g = GenRecords(sys.stdin)

  try:
    header = g.next()
  except StopIteration:
    log('Expected header')
    return 0

  if isinstance(header, bool):
    return 0 if header else 1

  if not isinstance(header, dict):
    log('Invalid header: %r', header)
    return 1

  # For now, don't do anything with it.
  log('header: %s', header)

  while True:

    #
    # Get metadata
    #

    try:
      metadata = g.next()
    except StopIteration:
      return 0

    if isinstance(metadata, bool):
      return 0 if metadata else 1

    if not isinstance(metadata, dict):
      log('Invalid metadata: %r', metadata)
      return 1

    try:
      filename = metadata['filename']
    except KeyError, e:
      log('Record should have filename')
      return 1
    hostname = metadata.get('hostname')
    filetype = metadata.get('filetype')

    #
    # Get body
    #

    try:
      body = g.next()
    except StopIteration:
      log('Expected body record')
      return 1

    if isinstance(body, bool):
      return 0 if body else 1

    # TODO: also receive { dirname tar } messages?  Or { dirname vat } ?

    # either foo.txt or /full/path/foo.txt accepted, but not
    # rel/path/foo.txt.
    if not os.path.isabs(filename) and '/' in filename:
      log('Relative paths not accepted')
      continue

    path = os.path.join(base_dir, filename)
    with open(path, 'w') as f:
      f.write(body)

    basename = os.path.basename(filename)
    # Now the file is in base_dir, so just print the basename.
    print basename

if __name__ == '__main__':
  try:
    sys.exit(main(sys.argv))
  except Error, e:
    print >> sys.stderr, e.args[0]
    sys.exit(1)
<commit_msg>Add comment about header.<commit_after>#!/usr/bin/python
"""
recv.py

Receive file contents from stdin, write to the base directory, and print
filename on stdout.

A main use case is to emulate the print-events (inotifywait) interface, but
on a remote machine.  webpipe send takes the filename stdin, the file is
transferred from remote to local, and webpipe recv echoes the filename to
stdout.
"""

import os
import sys

# outside
import tnet

class Error(Exception):
  pass

def log(msg, *args):
  if args:
    msg = msg % args
  print >>sys.stderr, 'recv: ' + msg

# Wrapper around tnet.laod
# - string or dict
# - True for error success
# - False for error fail

def GenRecords(f):
  while True:
    try:
      v = tnet.load(f)
      if not isinstance(v, (str, dict)):  # byte string or dict
        log('Invalid value %r', v)
        yield False
      yield v
    except ValueError, e:
      log('fatal: %s', e)
      yield False  # fatal error
    except EOFError:
      yield True  # end of stream, success

def main(argv):
  """Returns an exit code."""

  base_dir = argv[1]

  g = GenRecords(sys.stdin)

  # TODO: use readline for the header instead.
  # Expected {"stream": "tnet", "description": "dict metadata, bytes data"}
  try:
    header = g.next()
  except StopIteration:
    log('Expected header')
    return 0

  if isinstance(header, bool):
    return 0 if header else 1

  if not isinstance(header, dict):
    log('Invalid header: %r', header)
    return 1

  # For now, don't do anything with it.
  log('header: %s', header)

  while True:

    #
    # Get metadata
    #

    try:
      metadata = g.next()
    except StopIteration:
      return 0

    if isinstance(metadata, bool):
      return 0 if metadata else 1

    if not isinstance(metadata, dict):
      log('Invalid metadata: %r', metadata)
      return 1

    try:
      filename = metadata['filename']
    except KeyError, e:
      log('Record should have filename')
      return 1
    hostname = metadata.get('hostname')
    filetype = metadata.get('filetype')

    #
    # Get body
    #

    try:
      body = g.next()
    except StopIteration:
      log('Expected body record')
      return 1

    if isinstance(body, bool):
      return 0 if body else 1

    # TODO: also receive { dirname tar } messages?  Or { dirname vat } ?

    # either foo.txt or /full/path/foo.txt accepted, but not
    # rel/path/foo.txt.
    if not os.path.isabs(filename) and '/' in filename:
      log('Relative paths not accepted')
      continue

    path = os.path.join(base_dir, filename)
    with open(path, 'w') as f:
      f.write(body)

    basename = os.path.basename(filename)
    # Now the file is in base_dir, so just print the basename.
    print basename

if __name__ == '__main__':
  try:
    sys.exit(main(sys.argv))
  except Error, e:
    print >> sys.stderr, e.args[0]
    sys.exit(1)
<|endoftext|>