<commit_before>#!/usr/bin/python

# This file is a part of the OpenSurgSim project.
# Copyright 2012-2013, SimQuest Solutions Inc.
#
# 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.

"""Runs Google's cpplint.py and some other checks on C++ files.

This script tries to flag violations of the OpenSurgSim coding
standards in C++ code.

This is certainly not a substitute for looking at the code by hand:
many violations will not be caught by the script, and some amount of
flagged code will turn out to be correct.  But it does make it easier
to notice certain common errors.
"""

# TODO(bert): add some more checks.

import argparse
import sys
import subprocess
import re

STANDARD_WARNING_FORMAT = \
    "{file}:{line}: {text} [{category}] [{level}]"
VISUAL_STUDIO_WARNING_FORMAT = \
    "{file}({line}): {warning} {vscategory}[{level}]: {text}"
WARNING_FORMAT = STANDARD_WARNING_FORMAT

def emit_warning(fields):
  fields = dict(fields)
  fmt = WARNING_FORMAT
  # add a "vscategory" field which is like "category" but never empty
  if 'category' in fields and fields['category'] is not None:
    fields['vscategory'] = fields['category']
  else:
    fmt = re.sub(r'\s*\[\{category[^\}]*\}\]', '', fmt)
    fmt = re.sub(r'\s*\{category[^\}]*\}', '', fmt)
    fields['category'] = '???'  # panic button
    fields['vscategory'] = 'RL'
  if 'level' not in fields:
    fmt = re.sub(r'\s*\[\{level[^\}]*\}\]', '', fmt)
    fmt = re.sub(r'\s*\{level[^\}]*\}', '', fmt)
    fields['level'] = '???'  # panic button
  if 'line' not in fields:
    fmt = re.sub(r'\s*\{line[^\}]*\}:', '', fmt)
    fmt = re.sub(r'\s*\(\{line[^\}]*\}\)', '', fmt)
    fmt = re.sub(r'\s*\{line[^\}]*\}', '', fmt)
    fields['line'] = '???'  # panic button
  if 'warning' not in fields:
    fields['warning'] = 'warning'
  print fmt.format(**fields)

def emit_error(fields):
  fields = dict(fields)
  fields['warning'] = 'error'
  emit_warning(fields)

def slurp_lines(file):
  try:
    with open(file, 'r') as f:
      return f.read().splitlines()
  except IOError as e:
    print >> sys.stderr, e
    #emit_error({'file': file, 'text': str(e)})
    return None

def run_cpplint(script, filter, files):
  if not files:
    return False
  argv = [sys.executable, script]
  if filter is not None:
    argv.extend(['--filter', filter])
  argv.extend(files)

  try:
    cmd = subprocess.Popen(argv, stdout=subprocess.PIPE,
                           stderr=subprocess.STDOUT)
  except OSError as e:
    print "Failed to run '" + script + "':\n\t", e
    return False

  saw_output = False
  for line in cmd.stdout:
    saw_output = True
    line = line.rstrip()
    match = re.search(r'^(.*?):(\d+):\s+(.*?)\s+\[(\S+)\]\s+\[(\d+)\]\s*$',
                      line)
    if match:
      fields = dict(zip(['file', 'line', 'text', 'category', 'level'],
                        match.groups()))
      emit_warning(fields)
    elif re.search(r'\[(\S+)\]\s+\[(\d+)\]\s*$', line):
      emit_error({'file': "run-lint",
                  'text': ("failed to parse likely warning line: '" +
                           line + "'")})
    elif re.search(r':\d+:', line):
      emit_error({'file': "run-lint",
                  'text': ("failed to parse line with likely line number: '" +
                           line + "'")})
    else:
      print line

  # The output is done, so the command should be finished.
  assert cmd.wait() is not None
  if not saw_output:
    emit_error({'file': "run-lint", 'text': "cpplint produced no output!"})
    return False
  return cmd.returncode == 0

def check_header_guard(flags, file):
  lines = slurp_lines(file)
  if not lines:
    emit_warning({'file': file, 'text': "file is missing or empty."})
    return False

  ifndef = filter(lambda x: re.search(r'^\s*#\s*ifndef\b', x), lines)
  if not ifndef:
    emit_warning({'file': file, 'text': "no #ifndef lines!"})
    return False
#  elif len(ifndef) > 1:
#    emit_warning({'file': file,
#                  'text': "multiple #ifndef lines; using first."})

  guard = ifndef[0]
  guard = re.sub(r'//.*', '', guard)
  guard = re.sub(r'/\*.*?\*/', '', guard)
  guard_match = re.search(r'^\s*#\s*ifndef\s+(\w+)\s*$', guard)
  if not guard_match:
    emit_error({'file': file,
                'text': "script error: failed to parse #ifndef line!"})
    return False
  guard = guard_match.group(1)

  namespace = filter(lambda x: re.search(r'^\s*namespace\b', x), lines)
  if not namespace:
    emit_warning({'file': file, 'text': "no 'namespace' lines!"})
  if filter(lambda x: re.search(r'^\s', x), namespace):
    emit_warning({'file': file,
                  'text': "one or more namespace declarations are indented!"})
  namespace = map(lambda x: re.sub(r'^\s*namespace\b', '', x).strip(),
                  namespace)
  if filter(lambda x: re.search(r'{$', x), namespace):
    emit_warning({'file': file,
                  'text': "'{' on the same line as a namespace declaration!"})
    namespace = map(lambda x: re.sub(r'\s*{$', '', x), namespace)

  namespace_re = "".join(
    map(lambda x: "(?:" + re.sub(r'[^\w\d]+', '', x.upper()) + "_)?",
        namespace))
  if len(namespace_re):
    namespace_re += r'(?<=.)'

  file_guard_re = re.sub(r'\W+', '_',
                         re.sub(r'.*/', '', file)).upper()
  guard_re = r'^' + namespace_re + file_guard_re + r'$'

  if not re.search(guard_re, guard):
    emit_warning({'file': file,
                  'text': ("unexpected guard '{}'!  expected /{}/."
                           .format(guard, guard_re)) })
  define = filter(lambda x: re.search(r'^\s*#\s*define\b', x), lines)
  if not define:
    emit_warning({'file': file, 'text': "no #define lines!"})
  else:
    def_match = re.match(r'^\s*#\s*define\s+(\w+)\s*$',
                         re.sub(r'/\*.*?\*/', '',
                                re.sub(r'//.*', '', define[0])))
    if not def_match:
      emit_error({'file': file,
                  'text': "script error: failed to parse #define line!"})
    elif def_match.group(1) != guard:
      emit_warning({'file': file, 'text': "#define doesn't match #ifndef!"})

  endif = filter(lambda x: re.search(r'^\s*#\s*endif\b', x), lines)
  if not endif:
    emit_warning({'file': file, 'text': "no #endif lines!"})
  elif re.search(r'^\s*#\s*endif\s*$', endif[-1]):
    if flags.missing_endif_comments:
      emit_warning({'file': file, 'text': "#endif with no comment."})
  else:
    if re.search(r'^\s*#\s*endif\s*///', endif[-1]):
      emit_warning({'file': file,
                    'text': "#endif with a Doxygen style /// comment."})
    endif_match = re.search(r'^\s*#\s*endif\s*//+\s*(.*?)\s*$', endif[-1])
    if not endif_match:
      emit_error({'file': file,
                  'text': "script error: failed to parse #endif comment."})
    elif endif_match.group(1) != guard:
      emit_warning({'file': file,
                    'text': ("#endif comment doesn't match #ifndef! (" + \
                               endif_match.group(1) + ")")})

def check_guards(flags, files):
  return all(map(lambda f: check_header_guard(flags, f), files))

if __name__ == '__main__':
  parser = argparse.ArgumentParser(
    description='Check source files for coding standard violations.')
  parser.add_argument('--cpplint-script', metavar='PATH_TO_SCRIPT',
                      help='The path to Google\'s cpplint.py script.',
                      default='cpplint.py')
  parser.add_argument('--cpplint-filter', '--filter', metavar='FILTER',
                      help='The --filter argument to pass to cpplint.')
  parser.add_argument('--no-cpplint', action='store_false', dest='do_cpplint',
                      help='Do not run the cpplint.py script.')
  parser.add_argument('--missing-endif-comments', action='store_true',
                      help='Flag missing include guard #endif comments, too.')
  parser.add_argument('--ignore-guards',
                      action='store_false', dest='do_check_guards',
                      help='Do not check the header file include guards.')
  parser.add_argument('--ignore-ext',
                      action='store_false', dest='do_check_extension',
                      help='Do not check the file extensions.')
  parser.add_argument('--format',
                      help='The format string for warnings and errors.')
  parser.add_argument('--visual-studio', '--vs', action='store_true',
                      help='Use defaults tailored for Visual Studio.')
  parser.add_argument('files', metavar='FILE', nargs='*',
                      help='The file names to check.')
  args = parser.parse_args()

  if args.format is not None:
    WARNING_FORMAT = args.format
  elif args.visual_studio:
    WARNING_FORMAT = VISUAL_STUDIO_WARNING_FORMAT
  else:
    WARNING_FORMAT = STANDARD_WARNING_FORMAT

  ok = True

  if args.do_check_extension:
    bad_ext = filter(lambda x: not re.search(r'\.(?:h|cpp)$', x), args.files)
    for file in bad_ext:
      emit_warning({'file': file,
                    'text': "unknown extension (expected .h or .cpp)"})
      ok = False

  if args.do_cpplint:
    if not run_cpplint(args.cpplint_script, args.cpplint_filter,
                       filter(lambda x: re.search(r'\.(?:h|cpp)$', x),
                              args.files)):
      ok = False

  if args.do_check_guards:
    if not check_guards(args,
                        filter(lambda x: re.search(r'\.h$', x), args.files)):
      ok = False

  if not ok:
    sys.exit(1)
<commit_msg>Add line numbers to the run-lint.py guard checking output.<commit_after>#!/usr/bin/python

# This file is a part of the OpenSurgSim project.
# Copyright 2012-2013, SimQuest Solutions Inc.
#
# 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.

"""Runs Google's cpplint.py and some other checks on C++ files.

This script tries to flag violations of the OpenSurgSim coding
standards in C++ code.

This is certainly not a substitute for looking at the code by hand:
many violations will not be caught by the script, and some amount of
flagged code will turn out to be correct.  But it does make it easier
to notice certain common errors.
"""

# TODO(bert): add some more checks.

import argparse
import sys
import subprocess
import re

STANDARD_WARNING_FORMAT = \
    "{file}:{line}: {text} [{category}] [{level}]"
VISUAL_STUDIO_WARNING_FORMAT = \
    "{file}({line}): {warning} {vscategory}[{level}]: {text}"
WARNING_FORMAT = STANDARD_WARNING_FORMAT

def emit_warning(fields):
  fields = dict(fields)
  fmt = WARNING_FORMAT
  # add a "vscategory" field which is like "category" but never empty
  if 'category' in fields and fields['category'] is not None:
    fields['vscategory'] = fields['category']
  else:
    fmt = re.sub(r'\s*\[\{category[^\}]*\}\]', '', fmt)
    fmt = re.sub(r'\s*\{category[^\}]*\}', '', fmt)
    fields['category'] = '???'  # panic button
    fields['vscategory'] = 'RL'
  if 'level' not in fields:
    fmt = re.sub(r'\s*\[\{level[^\}]*\}\]', '', fmt)
    fmt = re.sub(r'\s*\{level[^\}]*\}', '', fmt)
    fields['level'] = '???'  # panic button
  if 'line' not in fields:
    fmt = re.sub(r'\s*\{line[^\}]*\}:', '', fmt)
    fmt = re.sub(r'\s*\(\{line[^\}]*\}\)', '', fmt)
    fmt = re.sub(r'\s*\{line[^\}]*\}', '', fmt)
    fields['line'] = '???'  # panic button
  if 'warning' not in fields:
    fields['warning'] = 'warning'
  print fmt.format(**fields)

def emit_error(fields):
  fields = dict(fields)
  fields['warning'] = 'error'
  emit_warning(fields)

def slurp_lines(file):
  try:
    with open(file, 'r') as f:
      return f.read().splitlines()
  except IOError as e:
    print >> sys.stderr, e
    #emit_error({'file': file, 'text': str(e)})
    return None

def run_cpplint(script, filter, files):
  if not files:
    return False
  argv = [sys.executable, script]
  if filter is not None:
    argv.extend(['--filter', filter])
  argv.extend(files)

  try:
    cmd = subprocess.Popen(argv, stdout=subprocess.PIPE,
                           stderr=subprocess.STDOUT)
  except OSError as e:
    print "Failed to run '" + script + "':\n\t", e
    return False

  saw_output = False
  for line in cmd.stdout:
    saw_output = True
    line = line.rstrip()
    match = re.search(r'^(.*?):(\d+):\s+(.*?)\s+\[(\S+)\]\s+\[(\d+)\]\s*$',
                      line)
    if match:
      fields = dict(zip(['file', 'line', 'text', 'category', 'level'],
                        match.groups()))
      emit_warning(fields)
    elif re.search(r'\[(\S+)\]\s+\[(\d+)\]\s*$', line):
      emit_error({'file': "run-lint",
                  'text': ("failed to parse likely warning line: '" +
                           line + "'")})
    elif re.search(r':\d+:', line):
      emit_error({'file': "run-lint",
                  'text': ("failed to parse line with likely line number: '" +
                           line + "'")})
    else:
      print line

  # The output is done, so the command should be finished.
  assert cmd.wait() is not None
  if not saw_output:
    emit_error({'file': "run-lint", 'text': "cpplint produced no output!"})
    return False
  return cmd.returncode == 0

def check_header_guard(flags, file):
  lines = slurp_lines(file)
  if not lines:
    emit_warning({'file': file, 'category': "opensurgsim/no_lines",
                  'text': "file is missing or empty."})
    return False

  lines = list(enumerate(lines))

  ifndef = filter(lambda x: re.search(r'^\s*#\s*ifndef\b', x[1]), lines)
  if not ifndef:
    emit_warning({'file': file, 'category': "opensurgsim/no_ifndef",
                  'text': "no #ifndef lines!"})
    return False
#  elif len(ifndef) > 1:
#    emit_warning({'file': file, 'line': ifndef[1][0],
#                  'category': "opensurgsim/several_ifndef",
#                  'text': "multiple #ifndef lines; using first."})

  guard = ifndef[0][1]
  guard = re.sub(r'//.*', '', guard)
  guard = re.sub(r'/\*.*?\*/', '', guard)
  guard_match = re.search(r'^\s*#\s*ifndef\s+(\w+)\s*$', guard)
  if not guard_match:
    emit_error({'file': file, 'line': ifndef[0][0],
                'category': "opensurgsim/internal",
                'text': "script error: failed to parse #ifndef line!"})
    return False
  guard = guard_match.group(1)

  namespace = filter(lambda x: re.search(r'^\s*namespace\b', x[1]), lines)
  if not namespace:
    emit_warning({'file': file, 'category': "opensurgsim/no_namespace",
                  'text': "no 'namespace' lines!"})
  indented_namespace = filter(lambda x: re.search(r'^\s', x[1]), namespace)
  if indented_namespace:
    emit_warning({'file': file, 'line': indented_namespace[0][0],
                  'category': "opensurgsim/namespace_indented",
                  'text': "one or more namespace declarations are indented!"})
  curly_namespace = filter(lambda x: re.search(r'{$', x[1]), namespace)
  if curly_namespace:
    emit_warning({'file': file, 'line': curly_namespace[0][0],
                  'category': "opensurgsim/namespace_brace",
                  'text': "'{' on the same line as a namespace declaration!"})
    namespace = map(lambda x: (x[0], re.sub(r'\s*{$', '', x[1])), namespace)
  namespace = map(lambda x: re.sub(r'^\s*namespace\b', '', x[1]).strip(),
                  namespace)

  namespace_re = "".join(
    map(lambda x: "(?:" + re.sub(r'[^\w\d]+', '', x.upper()) + "_)?",
        namespace))
  if len(namespace_re):
    namespace_re += r'(?<=.)'

  file_guard_re = re.sub(r'\W+', '_',
                         re.sub(r'.*/', '', file)).upper()
  guard_re = r'^' + namespace_re + file_guard_re + r'$'

  if not re.search(guard_re, guard):
    emit_warning({'file': file, 'line': ifndef[0][0],
                  'category': "opensurgsim/header_guard",
                  'text': ("unexpected guard '{}'!  expected /{}/."
                           .format(guard, guard_re)) })

  define = filter(lambda x: re.search(r'^\s*#\s*define\b', x[1]), lines)
  if not define:
    emit_warning({'file': file, 'category': "opensurgsim/no_define",
                  'text': "no #define lines!"})
  else:
    def_match = re.match(r'^\s*#\s*define\s+(\w+)\s*$',
                         re.sub(r'/\*.*?\*/', '',
                                re.sub(r'//.*', '', define[0])))
    if not def_match:
      emit_error({'file': file, 'line': define[0][0],
                  'category': "opensurgsim/internal",
                  'text': "script error: failed to parse #define line!"})
    elif def_match.group(1) != guard:
      emit_warning({'file': file, 'line': define[0][0],
                    'category': "opensurgsim/guard_mismatch",
                    'text': "#define doesn't match #ifndef!"})

  endif = filter(lambda x: re.search(r'^\s*#\s*endif\b', x[1]), lines)
  if not endif:
    emit_warning({'file': file, 'category': "opensurgsim/no_endif",
                  'text': "no #endif lines!"})
  elif re.search(r'^\s*#\s*endif\s*$', endif[-1][1]):
    if flags.missing_endif_comments:
      emit_warning({'file': file, 'line': endif[-1][0],
                    'category': "opensurgsim/endif_no_comment",
                    'text': "#endif with no comment."})
  else:
    if re.search(r'^\s*#\s*endif\s*///', endif[-1][1]):
      emit_warning({'file': file, 'line': endif[-1][0],
                    'category': "opensurgsim/endif_doxygen",
                    'text': "#endif with a Doxygen style /// comment."})
    endif_match = re.search(r'^\s*#\s*endif\s*//+\s*(.*?)\s*$', endif[-1][1])
    if not endif_match:
      emit_error({'file': file, 'line': endif[-1][0],
                  'category': "opensurgsim/internal",
                  'text': "script error: failed to parse #endif comment."})
    elif endif_match.group(1) != guard:
      emit_warning({'file': file, 'line': endif[-1][0],
                    'category': "opensurgsim/endif_mismatch",
                    'text': ("#endif comment doesn't match #ifndef! (" + \
                               endif_match.group(1) + ")")})

def check_guards(flags, files):
  return all(map(lambda f: check_header_guard(flags, f), files))

if __name__ == '__main__':
  parser = argparse.ArgumentParser(
    description='Check source files for coding standard violations.')
  parser.add_argument('--cpplint-script', metavar='PATH_TO_SCRIPT',
                      help='The path to Google\'s cpplint.py script.',
                      default='cpplint.py')
  parser.add_argument('--cpplint-filter', '--filter', metavar='FILTER',
                      help='The --filter argument to pass to cpplint.')
  parser.add_argument('--no-cpplint', action='store_false', dest='do_cpplint',
                      help='Do not run the cpplint.py script.')
  parser.add_argument('--missing-endif-comments', action='store_true',
                      help='Flag missing include guard #endif comments, too.')
  parser.add_argument('--ignore-guards',
                      action='store_false', dest='do_check_guards',
                      help='Do not check the header file include guards.')
  parser.add_argument('--ignore-ext',
                      action='store_false', dest='do_check_extension',
                      help='Do not check the file extensions.')
  parser.add_argument('--format',
                      help='The format string for warnings and errors.')
  parser.add_argument('--visual-studio', '--vs', action='store_true',
                      help='Use defaults tailored for Visual Studio.')
  parser.add_argument('files', metavar='FILE', nargs='*',
                      help='The file names to check.')
  args = parser.parse_args()

  if args.format is not None:
    WARNING_FORMAT = args.format
  elif args.visual_studio:
    WARNING_FORMAT = VISUAL_STUDIO_WARNING_FORMAT
  else:
    WARNING_FORMAT = STANDARD_WARNING_FORMAT

  ok = True

  if args.do_check_extension:
    bad_ext = filter(lambda x: not re.search(r'\.(?:h|cpp)$', x), args.files)
    for file in bad_ext:
      emit_warning({'file': file,
                    'text': "unknown extension (expected .h or .cpp)"})
      ok = False

  if args.do_cpplint:
    if not run_cpplint(args.cpplint_script, args.cpplint_filter,
                       filter(lambda x: re.search(r'\.(?:h|cpp)$', x),
                              args.files)):
      ok = False

  if args.do_check_guards:
    if not check_guards(args,
                        filter(lambda x: re.search(r'\.h$', x), args.files)):
      ok = False

  if not ok:
    sys.exit(1)
<|endoftext|>


<commit_before>"""Models for the events application."""

import operator
from django.db import models
from django.urls import reverse
from autoslug import AutoSlugField
from django_google_maps import fields as map_fields

class Location(models.Model):
    """Model for location of session."""

    slug = AutoSlugField(unique=True, populate_from="name")
    name = models.CharField(max_length=150)
    description = models.TextField(blank=True)
    address = map_fields.AddressField(max_length=200)
    geolocation = map_fields.GeoLocationField(max_length=100)

    def get_absolute_url(self):
        """Return URL of object on website.

        Returns:
            URL as a string.
        """
        return reverse("events:location", kwargs={"location_slug": self.slug})

    def __str__(self):
        """Text representation of Location object.

        Returns:
            Name of location (str).
        """
        return self.name

class LocationImage(models.Model):
    """Model for image of location model."""

    name = models.CharField(max_length=255)
    image = models.ImageField(upload_to="images/locations/")
    location = models.ForeignKey(
        Location,
        related_name="images",
    )

    def __str__(self):
        """Text representation of LocationImage object.

        Returns:
            Name of image (str).
        """
        return self.name

class Series(models.Model):
    """Model for event series."""

    slug = AutoSlugField(unique=True, populate_from="name")
    name = models.CharField(max_length=150)
    logo = models.ImageField(upload_to="images/series/", null=True, blank=True)
    description = models.TextField()

    def find_closest_event(self):
        from events.utils import calculate_days_difference
        events = self.events.filter(is_published=True)
        closest_event = None
        for event in events:
            event.days_difference = calculate_days_difference(event)
            if closest_event is None or (event.days_difference >= 0 and event.days_difference < closest_event.days_difference):
                closest_event = event
            elif closest_event is None or (event.days_difference < 0 and event.days_difference > closest_event.days_difference):
                closest_event = event
        return closest_event

    def __str__(self):
        """Text representation of Series object.

        Returns:
            Name of series (str).
        """
        return self.name

class Sponsor(models.Model):
    """Model for sponsor of event."""

    name = models.CharField(max_length=200)
    url = models.URLField()
    logo = models.ImageField(upload_to="images/sponsors/", null=True, blank=True)

    def __str__(self):
        """Text representation of Sponsor object.

        Returns:
            Name of sponsor (str).
        """
        return self.name

class EventBase(models.Model):
    """Abstract base class for event models."""

    slug = AutoSlugField(unique=True, populate_from="name")
    name = models.CharField(max_length=150)
    description = models.TextField()
    start_date = models.DateField()
    end_date = models.DateField()
    is_published = models.BooleanField(default=False)

    class Meta:
        """Meta attributes of the class."""

        abstract = True

class Event(EventBase):
    """Model for event in database."""

    location = models.ForeignKey(
        Location,
        related_name="events",
        null=True,
    )
    series = models.ForeignKey(
        Series,
        related_name="events",
        null=True,
        blank=True,
    )
    sponsors = models.ManyToManyField(
        Sponsor,
        related_name="events",
        blank=True,
    )

    def get_absolute_url(self):
        """Return URL of object on website.

        Returns:
            URL as a string.
        """
        return reverse("events:event", kwargs={"event_slug": self.slug})

    def __str__(self):
        """Text representation of Event object.

        Returns:
            Name of event (str).
        """
        if self.series:
            return "{}: {}".format(self.series.name, self.name)
        else:
            return self.name

class EventImage(models.Model):
    """Model for image of event model."""

    name = models.CharField(max_length=255)
    image = models.ImageField(upload_to="images/events/")
    location = models.ForeignKey(
        Event,
        related_name="images",
    )

    def __str__(self):
        """Text representation of EventImage object.

        Returns:
            Name of image (str).
        """
        return self.name

class Resource(models.Model):
    """Model for resource used in sessions."""

    slug = AutoSlugField(unique=True, populate_from="name")
    name = models.CharField(max_length=150)
    url = models.URLField()
    description = models.TextField(blank=True)
    image = models.ImageField(upload_to="images/resources/", null=True, blank=True)

    def __str__(self):
        """Text representation of Resource object.

        Returns:
            Name of resource (str).
        """
        return self.name

class Session(models.Model):
    """Model for session of event."""

    slug = AutoSlugField(unique_with=["event__slug"], populate_from="name")
    event = models.ForeignKey(
        Event,
        on_delete=models.CASCADE,
        related_name="sessions",
    )
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    image = models.ImageField(upload_to="images/sessions/", null=True, blank=True)
    start_datetime = models.DateTimeField()
    end_datetime = models.DateTimeField()
    locations = models.ManyToManyField(
        Location,
        related_name="sessions",
        blank=True,
    )
    resources = models.ManyToManyField(
        Resource,
        related_name="sessions",
        blank=True,
    )

    def __str__(self):
        """Text representation of Session object.

        Returns:
            Name of session (str).
        """
        return self.name

class ThirdPartyEvent(EventBase):
    """Model for third party event in database."""

    url = models.URLField()
    location = models.ForeignKey(
        Location,
        related_name="third_party_events",
        null=True,
    )

    def get_absolute_url(self):
        """Return URL of object on website.

        Returns:
            URL as a string.
        """
        return reverse("events:third_party_event", kwargs={"event_slug": self.slug})

    def __str__(self):
        """Text representation of Event object.

        Returns:
            Name of event (str).
        """
        return self.name
<commit_msg>Add missing docstring<commit_after>"""Models for the events application."""

from django.db import models
from django.urls import reverse
from autoslug import AutoSlugField
from django_google_maps import fields as map_fields

class Location(models.Model):
    """Model for location of session."""

    slug = AutoSlugField(unique=True, populate_from="name")
    name = models.CharField(max_length=150)
    description = models.TextField(blank=True)
    address = map_fields.AddressField(max_length=200)
    geolocation = map_fields.GeoLocationField(max_length=100)

    def get_absolute_url(self):
        """Return URL of object on website.

        Returns:
            URL as a string.
        """
        return reverse("events:location", kwargs={"location_slug": self.slug})

    def __str__(self):
        """Text representation of Location object.

        Returns:
            Name of location (str).
        """
        return self.name

class LocationImage(models.Model):
    """Model for image of location model."""

    name = models.CharField(max_length=255)
    image = models.ImageField(upload_to="images/locations/")
    location = models.ForeignKey(
        Location,
        related_name="images",
    )

    def __str__(self):
        """Text representation of LocationImage object.

        Returns:
            Name of image (str).
        """
        return self.name

class Series(models.Model):
    """Model for event series."""

    slug = AutoSlugField(unique=True, populate_from="name")
    name = models.CharField(max_length=150)
    logo = models.ImageField(upload_to="images/series/", null=True, blank=True)
    description = models.TextField()

    def find_closest_event(self):
        """Find the closest event of the series.

        Chooses the first event to match one of the following rules:
        1. Event currently occuring.
        2. Closest event in future.
        3. Closest event in past.

        Returns:
            Event object, or None if no events.
        """
        from events.utils import calculate_days_difference
        events = self.events.filter(is_published=True)
        closest_event = None
        for event in events:
            event.days_difference = calculate_days_difference(event)
            if closest_event is None or (
                event.days_difference >= 0 and event.days_difference < closest_event.days_difference
            ):
                closest_event = event
            elif closest_event is None or (
                event.days_difference < 0 and event.days_difference > closest_event.days_difference
            ):
                closest_event = event
        return closest_event

    def __str__(self):
        """Text representation of Series object.

        Returns:
            Name of series (str).
        """
        return self.name

class Sponsor(models.Model):
    """Model for sponsor of event."""

    name = models.CharField(max_length=200)
    url = models.URLField()
    logo = models.ImageField(upload_to="images/sponsors/", null=True, blank=True)

    def __str__(self):
        """Text representation of Sponsor object.

        Returns:
            Name of sponsor (str).
        """
        return self.name

class EventBase(models.Model):
    """Abstract base class for event models."""

    slug = AutoSlugField(unique=True, populate_from="name")
    name = models.CharField(max_length=150)
    description = models.TextField()
    start_date = models.DateField()
    end_date = models.DateField()
    is_published = models.BooleanField(default=False)

    class Meta:
        """Meta attributes of the class."""

        abstract = True

class Event(EventBase):
    """Model for event in database."""

    location = models.ForeignKey(
        Location,
        related_name="events",
        null=True,
    )
    series = models.ForeignKey(
        Series,
        related_name="events",
        null=True,
        blank=True,
    )
    sponsors = models.ManyToManyField(
        Sponsor,
        related_name="events",
        blank=True,
    )

    def get_absolute_url(self):
        """Return URL of object on website.

        Returns:
            URL as a string.
        """
        return reverse("events:event", kwargs={"event_slug": self.slug})

    def __str__(self):
        """Text representation of Event object.

        Returns:
            Name of event (str).
        """
        if self.series:
            return "{}: {}".format(self.series.name, self.name)
        else:
            return self.name

class EventImage(models.Model):
    """Model for image of event model."""

    name = models.CharField(max_length=255)
    image = models.ImageField(upload_to="images/events/")
    location = models.ForeignKey(
        Event,
        related_name="images",
    )

    def __str__(self):
        """Text representation of EventImage object.

        Returns:
            Name of image (str).
        """
        return self.name

class Resource(models.Model):
    """Model for resource used in sessions."""

    slug = AutoSlugField(unique=True, populate_from="name")
    name = models.CharField(max_length=150)
    url = models.URLField()
    description = models.TextField(blank=True)
    image = models.ImageField(upload_to="images/resources/", null=True, blank=True)

    def __str__(self):
        """Text representation of Resource object.

        Returns:
            Name of resource (str).
        """
        return self.name

class Session(models.Model):
    """Model for session of event."""

    slug = AutoSlugField(unique_with=["event__slug"], populate_from="name")
    event = models.ForeignKey(
        Event,
        on_delete=models.CASCADE,
        related_name="sessions",
    )
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    image = models.ImageField(upload_to="images/sessions/", null=True, blank=True)
    start_datetime = models.DateTimeField()
    end_datetime = models.DateTimeField()
    locations = models.ManyToManyField(
        Location,
        related_name="sessions",
        blank=True,
    )
    resources = models.ManyToManyField(
        Resource,
        related_name="sessions",
        blank=True,
    )

    def __str__(self):
        """Text representation of Session object.

        Returns:
            Name of session (str).
        """
        return self.name

class ThirdPartyEvent(EventBase):
    """Model for third party event in database."""

    url = models.URLField()
    location = models.ForeignKey(
        Location,
        related_name="third_party_events",
        null=True,
    )

    def get_absolute_url(self):
        """Return URL of object on website.

        Returns:
            URL as a string.
        """
        return reverse("events:third_party_event", kwargs={"event_slug": self.slug})

    def __str__(self):
        """Text representation of Event object.

        Returns:
            Name of event (str).
        """
        return self.name
<|endoftext|>


<commit_before>##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# $Id: hr.py 3751 2006-08-09 13:15:36Z mvd $
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

from mx import DateTime
import time

from osv import fields, osv

def _employee_get(obj,cr,uid,context={}):
	ids = obj.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)])
	if ids:
		return ids[0]
	return False

class hr_expense_expense(osv.osv):
	def copy(self, cr, uid, id, default=None, context={}):
		if not default: default = {}
		default.update( {'invoice_id':False,'date_confirm':False,'date_valid':False,'user_valid':False})
		return super(hr_expense_expense, self).copy(cr, uid, id, default, context)

	def _amount(self, cr, uid, ids, field_name, arg, context):
		id_set = ",".join(map(str, ids))
		cr.execute("SELECT s.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_expense s LEFT OUTER JOIN hr_expense_line l ON (s.id=l.expense_id) WHERE s.id IN ("+id_set+") GROUP BY s.id ")
		res = dict(cr.fetchall())
		return res

	def _get_currency(self, cr, uid, context):
		user = self.pool.get('res.users').browse(cr, uid, [uid])[0]
		if user.company_id:
			return user.company_id.currency_id.id
		else:
			return self.pool.get('res.currency').search(cr, uid, [('rate','=',1.0)])[0]

	_name = "hr.expense.expense"
	_description = "Expense"
	_columns = {
		'name': fields.char('Expense Sheet', size=128, required=True),
		'id': fields.integer('Sheet ID', readonly=True),
		'ref': fields.char('Reference', size=32),
		'date': fields.date('Date'),
		'journal_id': fields.many2one('account.journal', 'Force Journal'),
		'employee_id': fields.many2one('hr.employee', 'Employee', required=True),
		'user_id': fields.many2one('res.users', 'User', required=True),
		'date_confirm': fields.date('Date Confirmed'),
		'date_valid': fields.date('Date Valided'),
		'user_valid': fields.many2one('res.users', 'Validation User'),
		'account_move_id': fields.many2one('account.move', 'Account Move'),
		'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines'),
		'note': fields.text('Note'),
		'amount': fields.function(_amount, method=True, string='Total Amount'),
		'invoice_id': fields.many2one('account.invoice', 'Invoice'),
		'currency_id': fields.many2one('res.currency', 'Currency', required=True),

		'state': fields.selection([
			('draft', 'Draft'),
			('confirm', 'Waiting confirmation'),
			('accepted', 'Accepted'),
			('invoiced', 'Invoiced'),
			('paid', 'Reimbursed'),
			('canceled', 'Canceled')],
			'State', readonly=True),
	}
	_defaults = {
		'date' : lambda *a: time.strftime('%Y-%m-%d'),
		'state': lambda *a: 'draft',
		'employee_id' : _employee_get,
		'user_id' : lambda cr,uid,id,c={}: id,
		'currency_id': _get_currency,
	}
	def expense_confirm(self, cr, uid, ids, *args):
		#for exp in self.browse(cr, uid, ids):
		self.write(cr, uid, ids, {
			'state':'confirm',
			'date_confirm': time.strftime('%Y-%m-%d')
		})
		return True

	def expense_accept(self, cr, uid, ids, *args):
		self.write(cr, uid, ids, {
			'state':'accepted',
			'date_valid':time.strftime('%Y-%m-%d'),
			'user_valid': uid,
			})
		return True

	def expense_canceled(self, cr, uid, ids, *args):
		self.write(cr, uid, ids, {'state':'canceled'})
		return True

	def expense_paid(self, cr, uid, ids, *args):
		self.write(cr, uid, ids, {'state':'paid'})
		return True

	def action_invoice_create(self, cr, uid, ids):
		res = False
		for exp in self.browse(cr, uid, ids):
			lines = []
			for l in exp.line_ids:
				tax_id = []
				if l.product_id:
					acc = l.product_id.product_tmpl_id.property_account_expense.id
					if not acc:
						acc = l.product_id.categ_id.property_account_expense_categ.id
					tax_id = [x.id for x in l.product_id.supplier_taxes_id]
				else:
					acc = self.pool.get('ir.property').get(cr, uid, 'property_account_expense_categ', 'product.category')
				lines.append((0, False, {
					'name': l.name,
					'account_id': acc,
					'price_unit': l.unit_amount,
					'quantity': l.unit_quantity,
					'uos_id': l.uom_id.id,
					'product_id': l.product_id and l.product_id.id or False,
					'invoice_line_tax_id': tax_id and [(6, 0, tax_id)] or False,
					'account_analytic_id': l.analytic_account.id,
				}))
			if not exp.employee_id.address_id:
				raise osv.except_osv('Error !', 'The employee must have a contact address')
			acc = exp.employee_id.address_id.partner_id.property_account_payable.id
			inv = {
				'name': exp.name,
				'reference': self.pool.get('ir.sequence').get(cr, uid, 'hr.expense.invoice'),
				'account_id': acc,
				'type': 'in_invoice',
				'partner_id': exp.employee_id.address_id.partner_id.id,
				'address_invoice_id': exp.employee_id.address_id.id,
				'address_contact_id': exp.employee_id.address_id.id,
				'origin': exp.name,
				'invoice_line': lines,
				'price_type': 'tax_included',
				'currency_id': exp.currency_id.id,
			}
			if exp.journal_id:
				inv['journal_id']=exp.journal_id.id
			inv_id = self.pool.get('account.invoice').create(cr, uid, inv, {'type':'in_invoice'})
			self.pool.get('account.invoice').button_compute(cr, uid, [inv_id], {'type':'in_invoice'}, set_total=True)
			self.write(cr, uid, [exp.id], {'invoice_id': inv_id, 'state': 'invoiced'})
			res = inv_id
		return res
hr_expense_expense()

class hr_expense_line(osv.osv):
	_name = "hr.expense.line"
	_description = "Expense Line"
	def _amount(self, cr, uid, ids, field_name, arg, context):
		if not len(ids):
			return {}
		id_set = ",".join(map(str, ids))
		cr.execute("SELECT l.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_line l WHERE id IN ("+id_set+") GROUP BY l.id ")
		res = dict(cr.fetchall())
		return res

	_columns = {
		'name': fields.char('Short Description', size=128, required=True),
		'date_value': fields.date('Date', required=True),
		'expense_id': fields.many2one('hr.expense.expense', 'Expense', ondelete='cascade', select=True),
		'total_amount': fields.function(_amount, method=True, string='Total'),
		'unit_amount': fields.float('Unit Price', readonly=True, states={'draft':[('readonly',False)]}),
		'unit_quantity': fields.float('Quantities', readonly=True, states={'draft':[('readonly',False)]}),
		'product_id': fields.many2one('product.product', 'Product', readonly=True, states={'draft':[('readonly',False)]}),
		'uom_id': fields.many2one('product.uom', 'UoM', readonly=True, states={'draft':[('readonly',False)]}),
		'description': fields.text('Description'),
		'analytic_account': fields.many2one('account.analytic.account','Analytic account'),
		'ref': fields.char('Reference', size=32),
		'sequence' : fields.integer('Sequence'),
	}
	_defaults = {
		'unit_quantity': lambda *a: 1,
		'date_value' : lambda *a: time.strftime('%Y-%m-%d'),
	}
	_order = "sequence"
	def onchange_product_id(self, cr, uid, ids, product_id, uom_id, context={}):
		v={}
		if product_id:
			product=self.pool.get('product.product').browse(cr,uid,product_id, context=context)
			v['name']=product.name
			v['unit_amount']=product.standard_price
			if not uom_id:
				v['uom_id']=product.uom_id.id
		return {'value':v}

hr_expense_line()

# vim:tw=0:noexpandtab
<commit_msg>Fix payment term for invoice generate by expense<commit_after>##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# $Id: hr.py 3751 2006-08-09 13:15:36Z mvd $
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

from mx import DateTime
import time

from osv import fields, osv

def _employee_get(obj,cr,uid,context={}):
	ids = obj.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)])
	if ids:
		return ids[0]
	return False

class hr_expense_expense(osv.osv):
	def copy(self, cr, uid, id, default=None, context={}):
		if not default: default = {}
		default.update( {'invoice_id':False,'date_confirm':False,'date_valid':False,'user_valid':False})
		return super(hr_expense_expense, self).copy(cr, uid, id, default, context)

	def _amount(self, cr, uid, ids, field_name, arg, context):
		id_set = ",".join(map(str, ids))
		cr.execute("SELECT s.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_expense s LEFT OUTER JOIN hr_expense_line l ON (s.id=l.expense_id) WHERE s.id IN ("+id_set+") GROUP BY s.id ")
		res = dict(cr.fetchall())
		return res

	def _get_currency(self, cr, uid, context):
		user = self.pool.get('res.users').browse(cr, uid, [uid])[0]
		if user.company_id:
			return user.company_id.currency_id.id
		else:
			return self.pool.get('res.currency').search(cr, uid, [('rate','=',1.0)])[0]

	_name = "hr.expense.expense"
	_description = "Expense"
	_columns = {
		'name': fields.char('Expense Sheet', size=128, required=True),
		'id': fields.integer('Sheet ID', readonly=True),
		'ref': fields.char('Reference', size=32),
		'date': fields.date('Date'),
		'journal_id': fields.many2one('account.journal', 'Force Journal'),
		'employee_id': fields.many2one('hr.employee', 'Employee', required=True),
		'user_id': fields.many2one('res.users', 'User', required=True),
		'date_confirm': fields.date('Date Confirmed'),
		'date_valid': fields.date('Date Valided'),
		'user_valid': fields.many2one('res.users', 'Validation User'),
		'account_move_id': fields.many2one('account.move', 'Account Move'),
		'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines'),
		'note': fields.text('Note'),
		'amount': fields.function(_amount, method=True, string='Total Amount'),
		'invoice_id': fields.many2one('account.invoice', 'Invoice'),
		'currency_id': fields.many2one('res.currency', 'Currency', required=True),

		'state': fields.selection([
			('draft', 'Draft'),
			('confirm', 'Waiting confirmation'),
			('accepted', 'Accepted'),
			('invoiced', 'Invoiced'),
			('paid', 'Reimbursed'),
			('canceled', 'Canceled')],
			'State', readonly=True),
	}
	_defaults = {
		'date' : lambda *a: time.strftime('%Y-%m-%d'),
		'state': lambda *a: 'draft',
		'employee_id' : _employee_get,
		'user_id' : lambda cr,uid,id,c={}: id,
		'currency_id': _get_currency,
	}
	def expense_confirm(self, cr, uid, ids, *args):
		#for exp in self.browse(cr, uid, ids):
		self.write(cr, uid, ids, {
			'state':'confirm',
			'date_confirm': time.strftime('%Y-%m-%d')
		})
		return True

	def expense_accept(self, cr, uid, ids, *args):
		self.write(cr, uid, ids, {
			'state':'accepted',
			'date_valid':time.strftime('%Y-%m-%d'),
			'user_valid': uid,
			})
		return True

	def expense_canceled(self, cr, uid, ids, *args):
		self.write(cr, uid, ids, {'state':'canceled'})
		return True

	def expense_paid(self, cr, uid, ids, *args):
		self.write(cr, uid, ids, {'state':'paid'})
		return True

	def action_invoice_create(self, cr, uid, ids):
		res = False
		invoice_obj = self.pool.get('account.invoice')
		for exp in self.browse(cr, uid, ids):
			lines = []
			for l in exp.line_ids:
				tax_id = []
				if l.product_id:
					acc = l.product_id.product_tmpl_id.property_account_expense.id
					if not acc:
						acc = l.product_id.categ_id.property_account_expense_categ.id
					tax_id = [x.id for x in l.product_id.supplier_taxes_id]
				else:
					acc = self.pool.get('ir.property').get(cr, uid, 'property_account_expense_categ', 'product.category')
				lines.append((0, False, {
					'name': l.name,
					'account_id': acc,
					'price_unit': l.unit_amount,
					'quantity': l.unit_quantity,
					'uos_id': l.uom_id.id,
					'product_id': l.product_id and l.product_id.id or False,
					'invoice_line_tax_id': tax_id and [(6, 0, tax_id)] or False,
					'account_analytic_id': l.analytic_account.id,
				}))
			if not exp.employee_id.address_id:
				raise osv.except_osv('Error !', 'The employee must have a contact address')
			acc = exp.employee_id.address_id.partner_id.property_account_payable.id
			payment_term_id = exp.employee_id.address_id.partner_id.property_payment_term.id
			inv = {
				'name': exp.name,
				'reference': self.pool.get('ir.sequence').get(cr, uid, 'hr.expense.invoice'),
				'account_id': acc,
				'type': 'in_invoice',
				'partner_id': exp.employee_id.address_id.partner_id.id,
				'address_invoice_id': exp.employee_id.address_id.id,
				'address_contact_id': exp.employee_id.address_id.id,
				'origin': exp.name,
				'invoice_line': lines,
				'price_type': 'tax_included',
				'currency_id': exp.currency_id.id,
				'payment_term': payment_term_id,
			}
			if payment_term_id:
				to_update = invoice_obj.onchange_payment_term_date_invoice(cr, uid, [],
						payment_term_id, None)
				if to_update:
					inv.update(to_update['value'])
			if exp.journal_id:
				inv['journal_id']=exp.journal_id.id
			inv_id = invoice_obj.create(cr, uid, inv, {'type':'in_invoice'})
			invoice_obj.button_compute(cr, uid, [inv_id], {'type':'in_invoice'},
					set_total=True)
			self.write(cr, uid, [exp.id], {'invoice_id': inv_id, 'state': 'invoiced'})
			res = inv_id
		return res
hr_expense_expense()

class hr_expense_line(osv.osv):
	_name = "hr.expense.line"
	_description = "Expense Line"
	def _amount(self, cr, uid, ids, field_name, arg, context):
		if not len(ids):
			return {}
		id_set = ",".join(map(str, ids))
		cr.execute("SELECT l.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_line l WHERE id IN ("+id_set+") GROUP BY l.id ")
		res = dict(cr.fetchall())
		return res

	_columns = {
		'name': fields.char('Short Description', size=128, required=True),
		'date_value': fields.date('Date', required=True),
		'expense_id': fields.many2one('hr.expense.expense', 'Expense', ondelete='cascade', select=True),
		'total_amount': fields.function(_amount, method=True, string='Total'),
		'unit_amount': fields.float('Unit Price', readonly=True, states={'draft':[('readonly',False)]}),
		'unit_quantity': fields.float('Quantities', readonly=True, states={'draft':[('readonly',False)]}),
		'product_id': fields.many2one('product.product', 'Product', readonly=True, states={'draft':[('readonly',False)]}),
		'uom_id': fields.many2one('product.uom', 'UoM', readonly=True, states={'draft':[('readonly',False)]}),
		'description': fields.text('Description'),
		'analytic_account': fields.many2one('account.analytic.account','Analytic account'),
		'ref': fields.char('Reference', size=32),
		'sequence' : fields.integer('Sequence'),
	}
	_defaults = {
		'unit_quantity': lambda *a: 1,
		'date_value' : lambda *a: time.strftime('%Y-%m-%d'),
	}
	_order = "sequence"
	def onchange_product_id(self, cr, uid, ids, product_id, uom_id, context={}):
		v={}
		if product_id:
			product=self.pool.get('product.product').browse(cr,uid,product_id, context=context)
			v['name']=product.name
			v['unit_amount']=product.standard_price
			if not uom_id:
				v['uom_id']=product.uom_id.id
		return {'value':v}

hr_expense_line()

# vim:tw=0:noexpandtab
<|endoftext|>


<commit_before>"""
Explore integration of rotationally symmetric shapes
"""

from __future__ import print_function, division

import os, sys
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))

import numpy as np
from numpy import pi, sin, cos, sqrt, exp, expm1, degrees, log10
from scipy.integrate import dblquad, simps, romb, romberg
import pylab

from sasmodels.special import square
from sasmodels.special import Gauss20Wt, Gauss20Z
from sasmodels.special import Gauss76Wt, Gauss76Z
from sasmodels.special import Gauss150Wt, Gauss150Z
from sasmodels.special import sas_2J1x_x, sas_sinx_x, sas_3j1x_x

SLD = 3.0
SLD_SOLVENT = 6.3
CONTRAST = SLD - SLD_SOLVENT

def make_cylinder(radius, length):
    def cylinder(qab, qc):
        return sas_2J1x_x(qab*radius) * sas_sinx_x(qc*0.5*length)
    volume = pi*radius**2*length
    norm = 1e-4*volume*CONTRAST**2
    return norm, cylinder

def make_sphere(radius):
    def sphere(qab, qc):
        q = sqrt(qab**2 + qc**2)
        return sas_3j1x_x(q*radius)
    volume = 4*pi*radius**3/3
    norm = 1e-4*volume*CONTRAST**2
    return norm, sphere

THETA_LOW, THETA_HIGH = 0, pi
SCALE = 1

def kernel(q, theta):
    """
    S(q) kernel for paracrystal forms.
    """
    qab = q*sin(theta)
    qc = q*cos(theta)
    return NORM*KERNEL(qab, qc)**2

def gauss_quad(q, n=150):
    """
    Compute the integral using gaussian quadrature for n = 20, 76 or 150.
    """
    if n == 20:
        z, w = Gauss20Z, Gauss20Wt
    elif n == 76:
        z, w = Gauss76Z, Gauss76Wt
    else:
        z, w = Gauss150Z, Gauss150Wt
    theta = (THETA_HIGH-THETA_LOW)*(z + 1)/2 + THETA_LOW
    sin_theta = abs(sin(theta))
    Zq = kernel(q=q, theta=theta)
    return np.sum(Zq*w*sin_theta)*SCALE/2

def gridded_integrals(q, n=300):
    """
    Compute the integral on a regular grid using rectangular, trapezoidal,
    simpsons, and romberg integration.  Romberg integration requires that
    the grid be of size n = 2**k + 1.
    """
    theta = np.linspace(THETA_LOW, THETA_HIGH, n)
    Zq = kernel(q=q, theta=theta)
    Zq *= abs(sin(theta))
    dx = theta[1]-theta[0]
    print("rect", n, np.sum(Zq)*dx*SCALE/pi)
    print("trapz", n, np.trapz(Zq, dx=dx)*SCALE/pi)
    print("simpson", n, simps(Zq, dx=dx)*SCALE/pi)
    print("romb", n, romb(Zq, dx=dx)*SCALE/pi)

def scipy_romberg(q):
    """
    Compute the integral using romberg integration.  This function does not
    complete in a reasonable time.  No idea if it is accurate.
    """
    evals = [0]
    def outer(theta):
        evals[0] += 1
        return kernel(q, theta=theta)*abs(sin(theta))
    result = romberg(outer, THETA_LOW, THETA_HIGH, divmax=100)*SCALE/pi
    print("scipy romberg", evals[0], result)

def plot(q, n=300):
    """
    Plot the 2D surface that needs to be integrated in order to compute
    the BCC S(q) at a particular q, dnn and d_factor.  *n* is the number
    of points in the grid.
    """
    theta = np.linspace(THETA_LOW, THETA_HIGH, n)
    Zq = kernel(q=q, theta=theta)
    Zq *= abs(sin(theta))
    pylab.semilogy(degrees(theta), np.fmax(Zq, 1.e-6), label="Q=%g"%q)
    pylab.title("%s I(q, theta) sin(theta)" % (KERNEL.__name__,))
    pylab.xlabel("theta (degrees)")
    pylab.ylabel("Iq 1/cm")

NORM, KERNEL = make_cylinder(radius=10., length=100000.)
#NORM, KERNEL = make_cylinder(radius=10., length=10000.)
#NORM, KERNEL = make_cylinder(radius=10., length=30.)
#NORM, KERNEL = make_sphere(radius=50.)

if __name__ == "__main__":
    Q = 0.8
    print("gauss", 20, gauss_quad(Q, n=20))
    print("gauss", 76, gauss_quad(Q, n=76))
    print("gauss", 150, gauss_quad(Q, n=150))
    gridded_integrals(Q, n=2**8+1)
    gridded_integrals(Q, n=2**10+1)
    gridded_integrals(Q, n=2**13+1)
    gridded_integrals(Q, n=2**16+1)
    gridded_integrals(Q, n=2**19+1)
    #scipy_romberg(Q)
    plot(0.5, n=2000)
    plot(0.6, n=2000)
    plot(0.8, n=2000)
    pylab.legend()
    pylab.show()
<commit_msg>play with cylinder integral<commit_after>"""
Explore integration of rotationally symmetric shapes
"""

from __future__ import print_function, division

import os, sys
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))

import numpy as np
from numpy import pi, sin, cos, sqrt, exp, expm1, degrees, log10
from scipy.integrate import dblquad, simps, romb, romberg
import pylab

from sasmodels.special import square
from sasmodels.special import Gauss20Wt, Gauss20Z
from sasmodels.special import Gauss76Wt, Gauss76Z
from sasmodels.special import Gauss150Wt, Gauss150Z
from sasmodels.special import sas_2J1x_x, sas_sinx_x, sas_3j1x_x

SLD = 3.0
SLD_SOLVENT = 6.3
CONTRAST = SLD - SLD_SOLVENT

def make_cylinder(radius, length):
    def cylinder(qab, qc):
        return sas_2J1x_x(qab*radius) * sas_sinx_x(qc*0.5*length)
    volume = pi*radius**2*length
    norm = 1e-4*volume*CONTRAST**2
    return norm, cylinder

def make_sphere(radius):
    def sphere(qab, qc):
        q = sqrt(qab**2 + qc**2)
        return sas_3j1x_x(q*radius)
    volume = 4*pi*radius**3/3
    norm = 1e-4*volume*CONTRAST**2
    return norm, sphere

THETA_LOW, THETA_HIGH = 0, pi
SCALE = 1

def kernel(q, theta):
    """
    S(q) kernel for paracrystal forms.
    """
    qab = q*sin(theta)
    qc = q*cos(theta)
    return NORM*KERNEL(qab, qc)**2

def gauss_quad(q, n=150):
    """
    Compute the integral using gaussian quadrature for n = 20, 76 or 150.
    """
    if n == 20:
        z, w = Gauss20Z, Gauss20Wt
    elif n == 76:
        z, w = Gauss76Z, Gauss76Wt
    else:
        z, w = Gauss150Z, Gauss150Wt
    theta = (THETA_HIGH-THETA_LOW)*(z + 1)/2 + THETA_LOW
    sin_theta = abs(sin(theta))
    Zq = kernel(q=q, theta=theta)
    return np.sum(Zq*w*sin_theta)*SCALE/2

def gridded_integrals(q, n=300):
    """
    Compute the integral on a regular grid using rectangular, trapezoidal,
    simpsons, and romberg integration.  Romberg integration requires that
    the grid be of size n = 2**k + 1.
    """
    theta = np.linspace(THETA_LOW, THETA_HIGH, n)
    Zq = kernel(q=q, theta=theta)
    Zq *= abs(sin(theta))
    dx = theta[1]-theta[0]
    print("rect", n, np.sum(Zq)*dx*SCALE/pi)
    print("trapz", n, np.trapz(Zq, dx=dx)*SCALE/pi)
    print("simpson", n, simps(Zq, dx=dx)*SCALE/pi)
    print("romb", n, romb(Zq, dx=dx)*SCALE/pi)

def scipy_romberg(q):
    """
    Compute the integral using romberg integration.  This function does not
    complete in a reasonable time.  No idea if it is accurate.
    """
    evals = [0]
    def outer(theta):
        evals[0] += 1
        return kernel(q, theta=theta)*abs(sin(theta))
    result = romberg(outer, THETA_LOW, THETA_HIGH, divmax=100)*SCALE/pi
    print("scipy romberg", evals[0], result)

def plot(q, n=300):
    """
    Plot the 2D surface that needs to be integrated in order to compute
    the BCC S(q) at a particular q, dnn and d_factor.  *n* is the number
    of points in the grid.
    """
    theta = np.linspace(THETA_LOW, THETA_HIGH, n)
    Zq = kernel(q=q, theta=theta)
    Zq *= abs(sin(theta))
    pylab.semilogy(degrees(theta), np.fmax(Zq, 1.e-6), label="Q=%g"%q)
    pylab.title("%s I(q, theta) sin(theta)" % (KERNEL.__name__,))
    pylab.xlabel("theta (degrees)")
    pylab.ylabel("Iq 1/cm")

def Iq_trapz(q, n):
    theta = np.linspace(THETA_LOW, THETA_HIGH, n)
    Zq = kernel(q=q, theta=theta)
    Zq *= abs(sin(theta))
    dx = theta[1]-theta[0]
    return np.trapz(Zq, dx=dx)*SCALE/pi

def plot_Iq(q, n, form="trapz"):
    if form == "trapz":
        I = np.array([Iq_trapz(qk, n) for qk in q])
    elif form == "gauss":
        I = np.array([gauss_quad(qk, n) for qk in q])
    pylab.loglog(q, I, label="%s, n=%d"%(form, n))
    pylab.xlabel("q (1/A)")
    pylab.ylabel("Iq (1/cm)")

NORM, KERNEL = make_cylinder(radius=10., length=100000.)
#NORM, KERNEL = make_cylinder(radius=10., length=10000.)
#NORM, KERNEL = make_cylinder(radius=10., length=30.)
#NORM, KERNEL = make_sphere(radius=50.)

if __name__ == "__main__":
    Q = 0.8
    print("gauss", 20, gauss_quad(Q, n=20))
    print("gauss", 76, gauss_quad(Q, n=76))
    print("gauss", 150, gauss_quad(Q, n=150))
    gridded_integrals(Q, n=2**8+1)
    gridded_integrals(Q, n=2**10+1)
    gridded_integrals(Q, n=2**13+1)
    gridded_integrals(Q, n=2**16+1)
    gridded_integrals(Q, n=2**19+1)
    #scipy_romberg(Q)
    plot(0.5, n=2000)
    plot(0.6, n=2000)
    plot(0.8, n=2000)
    pylab.legend()
    pylab.figure()
    plot_Iq(np.logspace(-3,0,200), n=2**16+1, form="trapz")
    plot_Iq(np.logspace(-3,0,200), n=2**10+1, form="trapz")
    plot_Iq(np.logspace(-3,0,200), n=150, form="gauss")
    pylab.legend()
    pylab.show()
<|endoftext|>


<commit_before>
from .column_sliced import ColumnSlicedView
from .column_id import IdColumn
from .loc import Loc

from ..core.bitmap import bitmap
import numpy as np

class IdColumnSlicedView(ColumnSlicedView):
    def __init__(self, base, view_slice):
        super(IdColumnSlicedView, self).__init__(IdColumn.INTERNAL_ID, base,
                                                 None, view_slice)
        self._update_mask = None

    # def __delitem__(self, index):
    #     index = self.view_to_base(index)
    #     #pylint: disable=protected-access
    #     self._base._delete_ids(index)

    def __repr__(self):
        return 'IdColumnSlicedView(%s,dshape=%s)' % (
            self.name, str(self.dshape))

    def id_to_index(self, loc, as_slice=True):
        res = self._base.id_to_index(loc, as_slice)
        return self.base_to_view(res)

    def __contains__(self, loc):
        start = self._view_slice.start
        stop = self._view_slice.stop or self.base.size
        ids = self.base.index.id_to_index(loc, True)
        v = Loc.dispatch(ids)
        if v == Loc.INT:
            return start <= ids and ids < stop
        if v == Loc.SLICE:
            return start <= ids.start and ids.stop <= stop
        return ids in bitmap(self._view_slice)

    def resize(self, _):
        pass  # ignore

    @property
    def update_mask(self):
        if self._update_mask is None or \
          (self._view_slice.stop is None
           and self._update_mask.max() != self.size-1):
            self._update_mask = bitmap(self._base[self.view_slice])

        return self._update_mask

    def to_array(self):
        return np.array(bitmap(self._view_slice))

    def compute_updates(self, start, now, mid=None, cleanup=True):
        #TODO the mask should be maintained in ID space, not index space
        mask = self.update_mask
        updates = self._base.compute_updates(start, now, mid, cleanup=True)
        updates.created &= mask
        updates.updated &= mask
        updates.deleted &= mask
        return updates
<commit_msg>fix to_array in sliced columns/tables<commit_after>
from .column_sliced import ColumnSlicedView
from .column_id import IdColumn
from .loc import Loc

from ..core.bitmap import bitmap
import numpy as np

class IdColumnSlicedView(ColumnSlicedView):
    def __init__(self, base, view_slice):
        super(IdColumnSlicedView, self).__init__(IdColumn.INTERNAL_ID, base,
                                                 None, view_slice)
        self._update_mask = None

    # def __delitem__(self, index):
    #     index = self.view_to_base(index)
    #     #pylint: disable=protected-access
    #     self._base._delete_ids(index)

    def __repr__(self):
        return 'IdColumnSlicedView(%s,dshape=%s)' % (
            self.name, str(self.dshape))

    def id_to_index(self, loc, as_slice=True):
        res = self._base.id_to_index(loc, as_slice)
        return self.base_to_view(res)

    def __contains__(self, loc):
        start = self._view_slice.start
        stop = self._view_slice.stop or self.base.size
        ids = self.base.index.id_to_index(loc, True)
        v = Loc.dispatch(ids)
        if v == Loc.INT:
            return start <= ids and ids < stop
        if v == Loc.SLICE:
            return start <= ids.start and ids.stop <= stop
        return ids in bitmap(range(start, stop, 1))  # self._view_slice)

    def resize(self, _):
        pass  # ignore

    @property
    def update_mask(self):
        if self._update_mask is None or \
          (self._view_slice.stop is None
           and self._update_mask.max() != self.size-1):
            self._update_mask = bitmap(self._base[self.view_slice])

        return self._update_mask

    def to_array(self):
        start = self._view_slice.start
        stop = self._view_slice.stop or self.base.size
        return np.array(bitmap(range(start, stop, 1)))

    def compute_updates(self, start, now, mid=None, cleanup=True):
        # TODO the mask should be maintained in ID space, not index space
        mask = self.update_mask
        updates = self._base.compute_updates(start, now, mid, cleanup=True)
        updates.created &= mask
        updates.updated &= mask
        updates.deleted &= mask
        return updates
<|endoftext|>


<commit_before>__author__ = 'ievans3024'

from flask import Flask, render_template
from importlib import import_module

app = Flask('blackbook')
app.config.from_pyfile('config.py', silent=True)

try:
    api = import_module("api", package=app.config.get("DATABASE_HANDLER"))
except AttributeError:
    raise ValueError("Config option 'DATABASE_HANDLER' is an invalid value or does not exist.")
except ValueError:
    raise ValueError("Config option 'DATABASE_HANDLER' cannot be empty.")
except ImportError:
    raise ValueError("Config option 'DATABASE_HANDLER' is {value} but there is no module to support that".format(value=app.config.get("DATABASE_HANDLER")))

app.register_blueprint(api)

@app.route("/")
@app.route("/book/")
def home():
    return render_template("base.html")

if __name__ == "__main__":
    app.run()<commit_msg>* changed database plugin handler code to work with how importlib.import_module works<commit_after>__author__ = 'ievans3024'

from flask import Flask, render_template
from importlib import import_module

app = Flask('blackbook')
app.config.from_pyfile('config.py', silent=True)

try:
    plugin = import_module(app.config.get("DATABASE_HANDLER"))
except AttributeError:
    raise ValueError("Config option 'DATABASE_HANDLER' is an invalid value or does not exist.")
except ValueError:
    raise ValueError("Config option 'DATABASE_HANDLER' cannot be empty.")
except ImportError:
    raise ValueError("Config option 'DATABASE_HANDLER' is {value} but there is no module to support that".format(value=app.config.get("DATABASE_HANDLER")))

app.register_blueprint(plugin.api)

@app.route("/")
@app.route("/book/")
def home():
    return render_template("base.html")

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


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

import time

from osv import fields, osv
from tools.translate import _
import decimal_precision as dp
import netsvc

def _employee_get(obj, cr, uid, context=None):
    if context is None:
        context = {}
    ids = obj.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)], context=context)
    if ids:
        return ids[0]
    return False

class hr_expense_expense(osv.osv):

    def copy(self, cr, uid, id, default=None, context=None):
        if context is None:
            context = {}
        if not default: default = {}
        default.update({'invoice_id': False, 'date_confirm': False, 'date_valid': False, 'user_valid': False})
        return super(hr_expense_expense, self).copy(cr, uid, id, default, context=context)

    def _amount(self, cr, uid, ids, field_name, arg, context=None):
        cr.execute("SELECT s.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_expense s LEFT OUTER JOIN hr_expense_line l ON (s.id=l.expense_id) WHERE s.id IN %s GROUP BY s.id ", (tuple(ids),))
        res = dict(cr.fetchall())
        return res

    def _get_currency(self, cr, uid, context=None):
        user = self.pool.get('res.users').browse(cr, uid, [uid], context=context)[0]
        if user.company_id:
            return user.company_id.currency_id.id
        else:
            return self.pool.get('res.currency').search(cr, uid, [('rate','=',1.0)], context=context)[0]

    _name = "hr.expense.expense"
    _description = "Expense"
    _order = "id desc"
    _columns = {
        'name': fields.char('Description', size=128, required=True),
        'id': fields.integer('Sheet ID', readonly=True),
        'ref': fields.char('Reference', size=32),
        'date': fields.date('Date', select=True),
        'journal_id': fields.many2one('account.journal', 'Force Journal', help = "The journal used when the expense is invoiced"),
        'employee_id': fields.many2one('hr.employee', "Employee", required=True),
        'user_id': fields.many2one('res.users', 'User', required=True),
        'date_confirm': fields.date('Confirmation Date', select=True, help = "Date of the confirmation of the sheet expense. It's filled when the button Confirm is pressed."),
        'date_valid': fields.date('Validation Date', select=True, help = "Date of the acceptation of the sheet expense. It's filled when the button Accept is pressed."),
        'user_valid': fields.many2one('res.users', 'Validation User'),
        'account_move_id': fields.many2one('account.move', 'Ledger Posting'),
        'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines', readonly=True, states={'draft':[('readonly',False)]} ),
        'note': fields.text('Note'),
        'amount': fields.function(_amount, string='Total Amount'),
        'invoice_id': fields.many2one('account.invoice', "Employee's Invoice"),
        'currency_id': fields.many2one('res.currency', 'Currency', required=True),
        'department_id':fields.many2one('hr.department','Department'),
        'company_id': fields.many2one('res.company', 'Company', required=True),
        'state': fields.selection([
            ('draft', 'New'),
            ('confirm', 'Waiting Approval'),
            ('accepted', 'Approved'),
            ('invoiced', 'Invoiced'),
            ('paid', 'Reimbursed'),
            ('cancelled', 'Refused')],
            'State', readonly=True, help='When the expense request is created the state is \'Draft\'.\n It is confirmed by the user and request is sent to admin, the state is \'Waiting Confirmation\'.\
            \nIf the admin accepts it, the state is \'Accepted\'.\n If an invoice is made for the expense request, the state is \'Invoiced\'.\n If the expense is paid to user, the state is \'Reimbursed\'.'),
    }
    _defaults = {
        'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'hr.employee', context=c),
        'date': fields.date.context_today,
        'state': 'draft',
        'employee_id': _employee_get,
        'user_id': lambda cr, uid, id, c={}: id,
        'currency_id': _get_currency,
    }

    def onchange_employee_id(self, cr, uid, ids, employee_id, context=None):
        emp_obj = self.pool.get('hr.employee')
        department_id = False
        company_id = False
        if employee_id:
            employee = emp_obj.browse(cr, uid, employee_id, context=context)
            department_id = employee.department_id.id
            company_id = employee.company_id.id
        return {'value': {'department_id': department_id, 'company_id': company_id}}

    def expense_confirm(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {
            'state':'confirm',
            'date_confirm': time.strftime('%Y-%m-%d')
        })
        return True

    def expense_accept(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {
            'state':'accepted',
            'date_valid':time.strftime('%Y-%m-%d'),
            'user_valid': uid,
            })
        return True

    def expense_canceled(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {'state':'cancelled'})
        return True

    def expense_paid(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {'state':'paid'})
        return True

    def invoice(self, cr, uid, ids, context=None):
        wf_service = netsvc.LocalService("workflow")
        mod_obj = self.pool.get('ir.model.data')
        res = mod_obj.get_object_reference(cr, uid, 'account', 'invoice_supplier_form')
        inv_ids = []
        for id in ids:
            wf_service.trg_validate(uid, 'hr.expense.expense', id, 'invoice', cr)
            inv_ids.append(self.browse(cr, uid, id).invoice_id.id)
        return {
            'name': _('Supplier Invoices'),
            'view_type': 'form',
            'view_mode': 'form',
            'view_id': [res and res[1] or False],
            'res_model': 'account.invoice',
            'context': "{'type':'out_invoice', 'journal_type': 'purchase'}",
            'type': 'ir.actions.act_window',
            'nodestroy': True,
            'target': 'current',
            'res_id': inv_ids and inv_ids[0] or False,
        }

    def action_invoice_create(self, cr, uid, ids):
        res = False
        invoice_obj = self.pool.get('account.invoice')
        property_obj = self.pool.get('ir.property')
        sequence_obj = self.pool.get('ir.sequence')
        analytic_journal_obj = self.pool.get('account.analytic.journal')
        account_journal = self.pool.get('account.journal')
        for exp in self.browse(cr, uid, ids):
            company_id = exp.company_id.id
            lines = []
            for l in exp.line_ids:
                tax_id = []
                if l.product_id:
                    acc = l.product_id.product_tmpl_id.property_account_expense
                    if not acc:
                        acc = l.product_id.categ_id.property_account_expense_categ
                    tax_id = [x.id for x in l.product_id.supplier_taxes_id]
                else:
                    acc = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category', context={'force_company': company_id})
                    if not acc:
                        raise osv.except_osv(_('Error !'), _('Please configure Default Expense account for Product purchase, `property_account_expense_categ`'))
                lines.append((0, False, {
                    'name': l.name,
                    'account_id': acc.id,
                    'price_unit': l.unit_amount,
                    'quantity': l.unit_quantity,
                    'uos_id': l.uom_id.id,
                    'product_id': l.product_id and l.product_id.id or False,
                    'invoice_line_tax_id': tax_id and [(6, 0, tax_id)] or False,
                    'account_analytic_id': l.analytic_account.id,
                }))
            if not exp.employee_id.address_home_id:
                raise osv.except_osv(_('Error !'), _('The employee must have a Home address.'))
            if not exp.employee_id.address_home_id.partner_id:
                raise osv.except_osv(_('Error !'), _("The employee's home address must have a partner linked."))
            acc = exp.employee_id.address_home_id.partner_id.property_account_payable.id
            payment_term_id = exp.employee_id.address_home_id.partner_id.property_payment_term.id
            inv = {
                'name': exp.name,
                'reference': sequence_obj.get(cr, uid, 'hr.expense.invoice'),
                'account_id': acc,
                'type': 'in_invoice',
                'partner_id': exp.employee_id.address_home_id.partner_id.id,
                'address_invoice_id': exp.employee_id.address_home_id.id,
                'address_contact_id': exp.employee_id.address_home_id.id,
                'company_id': company_id,
                'origin': exp.name,
                'invoice_line': lines,
                'currency_id': exp.currency_id.id,
                'payment_term': payment_term_id,
                'fiscal_position': exp.employee_id.address_home_id.partner_id.property_account_position.id
            }
            if payment_term_id:
                to_update = invoice_obj.onchange_payment_term_date_invoice(cr, uid, [], payment_term_id, None)
                if to_update:
                    inv.update(to_update['value'])
            journal = False
            if exp.journal_id:
                inv['journal_id']=exp.journal_id.id
                journal = exp.journal_id
            else:
                journal_id = invoice_obj._get_journal(cr, uid, context={'type': 'in_invoice', 'company_id': company_id})
                if journal_id:
                    inv['journal_id'] = journal_id
                    journal = account_journal.browse(cr, uid, journal_id)
            if journal and not journal.analytic_journal_id:
                analytic_journal_ids = analytic_journal_obj.search(cr, uid, [('type','=','purchase')])
                if analytic_journal_ids:
                    account_journal.write(cr, uid, [journal.id],{'analytic_journal_id':analytic_journal_ids[0]})
            inv_id = invoice_obj.create(cr, uid, inv, {'type': 'in_invoice'})
            invoice_obj.button_compute(cr, uid, [inv_id], {'type': 'in_invoice'}, set_total=True)
            self.write(cr, uid, [exp.id], {'invoice_id': inv_id, 'state': 'invoiced'})
            res = inv_id
        return res

hr_expense_expense()

class product_product(osv.osv):
    _inherit = "product.product"
    _columns = {
        'hr_expense_ok': fields.boolean('Can Constitute an Expense', help="Determines if the product can be visible in the list of product within a selection from an HR expense sheet line."),
    }

    def on_change_hr_expense_ok(self, cr, uid, id, hr_expense_ok):

        if not hr_expense_ok:
            return {}
        data_obj = self.pool.get('ir.model.data')
        cat_id = data_obj._get_id(cr, uid, 'hr_expense', 'cat_expense')
        categ_id = data_obj.browse(cr, uid, cat_id).res_id
        res = {'value' : {'type':'service','procure_method':'make_to_stock','supply_method':'buy','purchase_ok':True,'sale_ok' :False,'categ_id':categ_id }}
        return res

product_product()

class hr_expense_line(osv.osv):
    _name = "hr.expense.line"
    _description = "Expense Line"

    def _amount(self, cr, uid, ids, field_name, arg, context=None):
        if not ids:
            return {}
        cr.execute("SELECT l.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_line l WHERE id IN %s GROUP BY l.id ",(tuple(ids),))
        res = dict(cr.fetchall())
        return res

    _columns = {
        'name': fields.char('Expense Note', size=128, required=True),
        'date_value': fields.date('Date', required=True),
        'expense_id': fields.many2one('hr.expense.expense', 'Expense', ondelete='cascade', select=True),
        'total_amount': fields.function(_amount, string='Total', digits_compute=dp.get_precision('Account')),
        'unit_amount': fields.float('Unit Price', digits_compute=dp.get_precision('Account')),
        'unit_quantity': fields.float('Quantities' ),
        'product_id': fields.many2one('product.product', 'Product', domain=[('hr_expense_ok','=',True)]),
        'uom_id': fields.many2one('product.uom', 'UoM'),
        'description': fields.text('Description'),
        'analytic_account': fields.many2one('account.analytic.account','Analytic account'),
        'ref': fields.char('Reference', size=32),
        'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of expense lines."),
        }
    _defaults = {
        'unit_quantity': 1,
        'date_value': lambda *a: time.strftime('%Y-%m-%d'),
    }
    _order = "sequence, date_value desc"

    def onchange_product_id(self, cr, uid, ids, product_id, uom_id, employee_id, context=None):
        res = {}
        if product_id:
            product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
            res['name'] = product.name
            amount_unit = product.price_get('standard_price')[product.id]
            res['unit_amount'] = amount_unit
            if not uom_id:
                res['uom_id'] = product.uom_id.id
        return {'value': res}

hr_expense_line()

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<commit_msg>[MERGE] OPW 574652: hr_expense: add correct decimal precision on 'amount' field<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

import time

from osv import fields, osv
from tools.translate import _
import decimal_precision as dp
import netsvc

def _employee_get(obj, cr, uid, context=None):
    if context is None:
        context = {}
    ids = obj.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)], context=context)
    if ids:
        return ids[0]
    return False

class hr_expense_expense(osv.osv):

    def copy(self, cr, uid, id, default=None, context=None):
        if context is None:
            context = {}
        if not default: default = {}
        default.update({'invoice_id': False, 'date_confirm': False, 'date_valid': False, 'user_valid': False})
        return super(hr_expense_expense, self).copy(cr, uid, id, default, context=context)

    def _amount(self, cr, uid, ids, field_name, arg, context=None):
        cr.execute("SELECT s.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_expense s LEFT OUTER JOIN hr_expense_line l ON (s.id=l.expense_id) WHERE s.id IN %s GROUP BY s.id ", (tuple(ids),))
        res = dict(cr.fetchall())
        return res

    def _get_currency(self, cr, uid, context=None):
        user = self.pool.get('res.users').browse(cr, uid, [uid], context=context)[0]
        if user.company_id:
            return user.company_id.currency_id.id
        else:
            return self.pool.get('res.currency').search(cr, uid, [('rate','=',1.0)], context=context)[0]

    _name = "hr.expense.expense"
    _description = "Expense"
    _order = "id desc"
    _columns = {
        'name': fields.char('Description', size=128, required=True),
        'id': fields.integer('Sheet ID', readonly=True),
        'ref': fields.char('Reference', size=32),
        'date': fields.date('Date', select=True),
        'journal_id': fields.many2one('account.journal', 'Force Journal', help = "The journal used when the expense is invoiced"),
        'employee_id': fields.many2one('hr.employee', "Employee", required=True),
        'user_id': fields.many2one('res.users', 'User', required=True),
        'date_confirm': fields.date('Confirmation Date', select=True, help = "Date of the confirmation of the sheet expense. It's filled when the button Confirm is pressed."),
        'date_valid': fields.date('Validation Date', select=True, help = "Date of the acceptation of the sheet expense. It's filled when the button Accept is pressed."),
        'user_valid': fields.many2one('res.users', 'Validation User'),
        'account_move_id': fields.many2one('account.move', 'Ledger Posting'),
        'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines', readonly=True, states={'draft':[('readonly',False)]} ),
        'note': fields.text('Note'),
        'amount': fields.function(_amount, string='Total Amount', digits_compute=dp.get_precision('Account')),
        'invoice_id': fields.many2one('account.invoice', "Employee's Invoice"),
        'currency_id': fields.many2one('res.currency', 'Currency', required=True),
        'department_id':fields.many2one('hr.department','Department'),
        'company_id': fields.many2one('res.company', 'Company', required=True),
        'state': fields.selection([
            ('draft', 'New'),
            ('confirm', 'Waiting Approval'),
            ('accepted', 'Approved'),
            ('invoiced', 'Invoiced'),
            ('paid', 'Reimbursed'),
            ('cancelled', 'Refused')],
            'State', readonly=True, help='When the expense request is created the state is \'Draft\'.\n It is confirmed by the user and request is sent to admin, the state is \'Waiting Confirmation\'.\
            \nIf the admin accepts it, the state is \'Accepted\'.\n If an invoice is made for the expense request, the state is \'Invoiced\'.\n If the expense is paid to user, the state is \'Reimbursed\'.'),
    }
    _defaults = {
        'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'hr.employee', context=c),
        'date': fields.date.context_today,
        'state': 'draft',
        'employee_id': _employee_get,
        'user_id': lambda cr, uid, id, c={}: id,
        'currency_id': _get_currency,
    }

    def onchange_employee_id(self, cr, uid, ids, employee_id, context=None):
        emp_obj = self.pool.get('hr.employee')
        department_id = False
        company_id = False
        if employee_id:
            employee = emp_obj.browse(cr, uid, employee_id, context=context)
            department_id = employee.department_id.id
            company_id = employee.company_id.id
        return {'value': {'department_id': department_id, 'company_id': company_id}}

    def expense_confirm(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {
            'state':'confirm',
            'date_confirm': time.strftime('%Y-%m-%d')
        })
        return True

    def expense_accept(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {
            'state':'accepted',
            'date_valid':time.strftime('%Y-%m-%d'),
            'user_valid': uid,
            })
        return True

    def expense_canceled(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {'state':'cancelled'})
        return True

    def expense_paid(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {'state':'paid'})
        return True

    def invoice(self, cr, uid, ids, context=None):
        wf_service = netsvc.LocalService("workflow")
        mod_obj = self.pool.get('ir.model.data')
        res = mod_obj.get_object_reference(cr, uid, 'account', 'invoice_supplier_form')
        inv_ids = []
        for id in ids:
            wf_service.trg_validate(uid, 'hr.expense.expense', id, 'invoice', cr)
            inv_ids.append(self.browse(cr, uid, id).invoice_id.id)
        return {
            'name': _('Supplier Invoices'),
            'view_type': 'form',
            'view_mode': 'form',
            'view_id': [res and res[1] or False],
            'res_model': 'account.invoice',
            'context': "{'type':'out_invoice', 'journal_type': 'purchase'}",
            'type': 'ir.actions.act_window',
            'nodestroy': True,
            'target': 'current',
            'res_id': inv_ids and inv_ids[0] or False,
        }

    def action_invoice_create(self, cr, uid, ids):
        res = False
        invoice_obj = self.pool.get('account.invoice')
        property_obj = self.pool.get('ir.property')
        sequence_obj = self.pool.get('ir.sequence')
        analytic_journal_obj = self.pool.get('account.analytic.journal')
        account_journal = self.pool.get('account.journal')
        for exp in self.browse(cr, uid, ids):
            company_id = exp.company_id.id
            lines = []
            for l in exp.line_ids:
                tax_id = []
                if l.product_id:
                    acc = l.product_id.product_tmpl_id.property_account_expense
                    if not acc:
                        acc = l.product_id.categ_id.property_account_expense_categ
                    tax_id = [x.id for x in l.product_id.supplier_taxes_id]
                else:
                    acc = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category', context={'force_company': company_id})
                    if not acc:
                        raise osv.except_osv(_('Error !'), _('Please configure Default Expense account for Product purchase, `property_account_expense_categ`'))
                lines.append((0, False, {
                    'name': l.name,
                    'account_id': acc.id,
                    'price_unit': l.unit_amount,
                    'quantity': l.unit_quantity,
                    'uos_id': l.uom_id.id,
                    'product_id': l.product_id and l.product_id.id or False,
                    'invoice_line_tax_id': tax_id and [(6, 0, tax_id)] or False,
                    'account_analytic_id': l.analytic_account.id,
                }))
            if not exp.employee_id.address_home_id:
                raise osv.except_osv(_('Error !'), _('The employee must have a Home address.'))
            if not exp.employee_id.address_home_id.partner_id:
                raise osv.except_osv(_('Error !'), _("The employee's home address must have a partner linked."))
            acc = exp.employee_id.address_home_id.partner_id.property_account_payable.id
            payment_term_id = exp.employee_id.address_home_id.partner_id.property_payment_term.id
            inv = {
                'name': exp.name,
                'reference': sequence_obj.get(cr, uid, 'hr.expense.invoice'),
                'account_id': acc,
                'type': 'in_invoice',
                'partner_id': exp.employee_id.address_home_id.partner_id.id,
                'address_invoice_id': exp.employee_id.address_home_id.id,
                'address_contact_id': exp.employee_id.address_home_id.id,
                'company_id': company_id,
                'origin': exp.name,
                'invoice_line': lines,
                'currency_id': exp.currency_id.id,
                'payment_term': payment_term_id,
                'fiscal_position': exp.employee_id.address_home_id.partner_id.property_account_position.id
            }
            if payment_term_id:
                to_update = invoice_obj.onchange_payment_term_date_invoice(cr, uid, [], payment_term_id, None)
                if to_update:
                    inv.update(to_update['value'])
            journal = False
            if exp.journal_id:
                inv['journal_id']=exp.journal_id.id
                journal = exp.journal_id
            else:
                journal_id = invoice_obj._get_journal(cr, uid, context={'type': 'in_invoice', 'company_id': company_id})
                if journal_id:
                    inv['journal_id'] = journal_id
                    journal = account_journal.browse(cr, uid, journal_id)
            if journal and not journal.analytic_journal_id:
                analytic_journal_ids = analytic_journal_obj.search(cr, uid, [('type','=','purchase')])
                if analytic_journal_ids:
                    account_journal.write(cr, uid, [journal.id],{'analytic_journal_id':analytic_journal_ids[0]})
            inv_id = invoice_obj.create(cr, uid, inv, {'type': 'in_invoice'})
            invoice_obj.button_compute(cr, uid, [inv_id], {'type': 'in_invoice'}, set_total=True)
            self.write(cr, uid, [exp.id], {'invoice_id': inv_id, 'state': 'invoiced'})
            res = inv_id
        return res

hr_expense_expense()

class product_product(osv.osv):
    _inherit = "product.product"
    _columns = {
        'hr_expense_ok': fields.boolean('Can Constitute an Expense', help="Determines if the product can be visible in the list of product within a selection from an HR expense sheet line."),
    }

    def on_change_hr_expense_ok(self, cr, uid, id, hr_expense_ok):

        if not hr_expense_ok:
            return {}
        data_obj = self.pool.get('ir.model.data')
        cat_id = data_obj._get_id(cr, uid, 'hr_expense', 'cat_expense')
        categ_id = data_obj.browse(cr, uid, cat_id).res_id
        res = {'value' : {'type':'service','procure_method':'make_to_stock','supply_method':'buy','purchase_ok':True,'sale_ok' :False,'categ_id':categ_id }}
        return res

product_product()

class hr_expense_line(osv.osv):
    _name = "hr.expense.line"
    _description = "Expense Line"

    def _amount(self, cr, uid, ids, field_name, arg, context=None):
        if not ids:
            return {}
        cr.execute("SELECT l.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_line l WHERE id IN %s GROUP BY l.id ",(tuple(ids),))
        res = dict(cr.fetchall())
        return res

    _columns = {
        'name': fields.char('Expense Note', size=128, required=True),
        'date_value': fields.date('Date', required=True),
        'expense_id': fields.many2one('hr.expense.expense', 'Expense', ondelete='cascade', select=True),
        'total_amount': fields.function(_amount, string='Total', digits_compute=dp.get_precision('Account')),
        'unit_amount': fields.float('Unit Price', digits_compute=dp.get_precision('Account')),
        'unit_quantity': fields.float('Quantities' ),
        'product_id': fields.many2one('product.product', 'Product', domain=[('hr_expense_ok','=',True)]),
        'uom_id': fields.many2one('product.uom', 'UoM'),
        'description': fields.text('Description'),
        'analytic_account': fields.many2one('account.analytic.account','Analytic account'),
        'ref': fields.char('Reference', size=32),
        'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of expense lines."),
        }
    _defaults = {
        'unit_quantity': 1,
        'date_value': lambda *a: time.strftime('%Y-%m-%d'),
    }
    _order = "sequence, date_value desc"

    def onchange_product_id(self, cr, uid, ids, product_id, uom_id, employee_id, context=None):
        res = {}
        if product_id:
            product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
            res['name'] = product.name
            amount_unit = product.price_get('standard_price')[product.id]
            res['unit_amount'] = amount_unit
            if not uom_id:
                res['uom_id'] = product.uom_id.id
        return {'value': res}

hr_expense_line()

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