<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005-2009 University of Deusto
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution.
#
# This software consists of contributions made by many individuals,
# listed below:
#
# Author: Pablo Orduña <pablo@ordunya.com>
#

import time

import weblab.experiment.experiments.ud_xilinx.server as UdXilinxExperiment

from voodoo.override import Override

class FakeImpact(object):
    def __init__(self):
        super(FakeImpact,self).__init__()
        self.clear()
    def program_device(self, program_path):
        print "FakeImpact::program_device: ", program_path
        try:
            self._paths.append(open(program_path).read())
        except Exception as e:
            print "I tried to show the program but i couldn't: ", e
        nseconds = 2
        print "Waiting %s seconds (simulating 'programming device...')" % nseconds
        time.sleep(nseconds)
        print "%i seconds have passed" % nseconds
        #raise Exception("A common exception")
    def get_suffix(self):
        return "whatever"

    def clear(self):
        self._paths = []

class FakeSerialPort(object):
    def __init__(self):
        super(FakeSerialPort,self).__init__()
        self.clear()
    def open_serial_port(self, number):
        print "FakeSerialPort::open_serial_port:", number
        self.dict['open'].append((self.cycle, number))
        self.cycle += 1
    def send_code(self, n):
        print "FakeSerialPort::send_code: ", n
        self.dict['send'].append((self.cycle, n))
        self.cycle += 1
    def close_serial_port(self):
        print "FakeSerialPort::close_serial_port: "
        self.dict['close'].append((self.cycle, None))
        self.cycle += 1
    def clear(self):
        self.dict = {'open':[], 'close':[], 'send' : []}
        self.cycle = 0

class DummyExperiment(UdXilinxExperiment.UdXilinxExperiment):
    def __init__(self, coord_address, locator, cfg_manager, *args, **kwargs):
        super(DummyExperiment,self).__init__(coord_address, locator, cfg_manager, *args, **kwargs)

        self._xilinx_impact                 = FakeImpact()
        self._command_sender._serial_port   = FakeSerialPort()

    @Override(UdXilinxExperiment.UdXilinxExperiment)
    def do_dispose(self):
        print "Experiment disposed"
        return ""

    @Override(UdXilinxExperiment.UdXilinxExperiment)
    def do_start_experiment(self, *args, **kwargs):
        print "Experiment started", args, kwargs
        return '{ "initial_configuration" : "hi, from dummy experiment" }'

    @Override(UdXilinxExperiment.UdXilinxExperiment)
    def do_send_command_to_device(self, command):
        msg = "Received command: %s" % command
        print msg
        super(DummyExperiment, self).do_send_command_to_device(command)
        return msg

    @Override(UdXilinxExperiment.UdXilinxExperiment)
    def do_send_file_to_device(self, content, file_info):
        msg = "Received file with len: %s and file_info: %s" % (len(content), file_info)
        print msg
        return msg

<commit_msg>Simplify dummy experiment<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2005-2009 University of Deusto
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution.
#
# This software consists of contributions made by many individuals,
# listed below:
#
# Author: Pablo Orduña <pablo@ordunya.com>
#

import weblab.experiment.experiment as Experiment

from voodoo.override import Override

class DummyExperiment(Experiment.Experiment):
    def __init__(self, coord_address, locator, cfg_manager, *args, **kwargs):
        super(DummyExperiment, self).__init__(*args, **kwargs)

    @Override(Experiment.Experiment)
    def do_start_experiment(self, *args, **kwargs):
        print "Experiment started"

    @Override(Experiment.Experiment)
    def do_send_command_to_device(self, command):
        print "Received command: %s" % command
        return "Received command: %s" % command

    @Override(Experiment.Experiment)
    def do_send_file_to_device(self, content, file_info):
        print "Received file with len: %s and file_info: %s" % (len(content), file_info)
        return "Received file with len: %s and file_info: %s" % (len(content), file_info)

    @Override(Experiment.Experiment)
    def do_dispose(self):
        print "dispose"

<|endoftext|>


<commit_before>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""Basic Google Account and User (Model) query functions.
"""

__authors__ = [
  '"Chen Lunpeng" <forever.clp@gmail.com>',
  '"Todd Larsen" <tlarsen@google.com>',
  ]

from google.appengine.api import users

from soc.logic import models

import soc.logic.models.user

def isDeveloper(account=None, user=None):
  """Returns True if a Google Account is a Developer with special privileges.

  Since it only works on the current logged-in user, if account matches the
  current logged-in Google Account, the App Engine Users API function
  user.is_current_user_admin() is checked.  If that returns False, or
  account is not the currently logged-in user, the is_developer property of
  the User entity corresponding to the Google Account is checked next.

  This solves the "chicken-and-egg" problem of no User entity having its
  is_developer property set, but no one being able to set it.

  Args:
    account: a Google Account (users.User) object; if not supplied,
      the current logged-in user is checked
  """

  if user and (not account):
    account = user.account

  # Get the currently logged in user
  current = users.get_current_user()

  if not (account or current):
    # no Google Account was supplied or is logged in, so an unspecified
    # User is definitely *not* a Developer
    return False

  if (((not account) or (account == current))
      and users.is_current_user_admin()):
    # no account supplied, or current logged-in user, and that user is in the
    # Administration->Developers list in the App Engine console
    return True

  if not account:
    account = current

  if not user:
    user = models.user.logic.getForFields(
        {'account': account, 'status': 'valid'}, unique=True)

  if not user:
    # no User entity for this Google Account, and account is not the
    # currently logged-in user, so there is no conclusive way to check the
    # Administration->Developers list in the App Engine console
    return False

  return user.is_developer
<commit_msg>Add a normalizeAccount to logic.accounts<commit_after>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""Basic Google Account and User (Model) query functions.
"""

__authors__ = [
  '"Chen Lunpeng" <forever.clp@gmail.com>',
  '"Todd Larsen" <tlarsen@google.com>',
  ]

from google.appengine.api import users

from soc.logic import models

import soc.logic.models.user

def normalizeAccount(account):
  """Returns a normalized version of the specified account.
  """

  normalized = str(account).lower()

  if account.email() == normalized:
    return account

  return users.User(email=normalized)

def isDeveloper(account=None, user=None):
  """Returns True if a Google Account is a Developer with special privileges.

  Since it only works on the current logged-in user, if account matches the
  current logged-in Google Account, the App Engine Users API function
  user.is_current_user_admin() is checked.  If that returns False, or
  account is not the currently logged-in user, the is_developer property of
  the User entity corresponding to the Google Account is checked next.

  This solves the "chicken-and-egg" problem of no User entity having its
  is_developer property set, but no one being able to set it.

  Args:
    account: a Google Account (users.User) object; if not supplied,
      the current logged-in user is checked
  """

  if user and (not account):
    account = user.account

  # Get the currently logged in user
  current = users.get_current_user()

  if not (account or current):
    # no Google Account was supplied or is logged in, so an unspecified
    # User is definitely *not* a Developer
    return False

  if (((not account) or (account == current))
      and users.is_current_user_admin()):
    # no account supplied, or current logged-in user, and that user is in the
    # Administration->Developers list in the App Engine console
    return True

  if not account:
    account = current

  if not user:
    user = models.user.logic.getForFields(
        {'account': account, 'status': 'valid'}, unique=True)

  if not user:
    # no User entity for this Google Account, and account is not the
    # currently logged-in user, so there is no conclusive way to check the
    # Administration->Developers list in the App Engine console
    return False

  return user.is_developer
<|endoftext|>


<commit_before>#!/usr/bin/env python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""Common validation helper functions.
"""

__authors__ = [
  '"Lennard de Rijk" <ljvderijk@gmail.com>',
  '"Pawel Solyga" <pawel.solyga@gmail.com>',
  ]

import feedparser

from google.appengine.api import urlfetch
from google.appengine.api import urlfetch_errors

from soc.models import linkable

def isFeedURLValid(feed_url=None):
  """Returns True if provided url is valid ATOM or RSS.

  Args:
    feed_url: ATOM or RSS feed url
  """

  # a missing or empty feed url is never valid
  if not feed_url:
    return False

  try:
    result = urlfetch.fetch(feed_url)
  except urlfetch_errors.Error:
    return False

  # 200 is the status code for 'all ok'
  if result.status_code != 200:
    return False

  try:
    parsed_feed = feedparser.parse(result.content)
  except:
    return False

  # version is always present if the feed is valid
  if not parsed_feed.version:
    return False

  return True

def isLinkIdFormatValid(link_id):
  """Returns True if link_id is in a valid format.

  Args:
    link_id: link ID used in URLs for identification
  """
  if linkable.LINK_ID_REGEX.match(link_id):
    return True
  return False

def isScopePathFormatValid(scope_path):
  """Returns True if scope_path is in a valid format.

  Args:
    scope_path: scope path prepended to link ID
      used for identification.
  """

  if linkable.SCOPE_PATH_REGEX.match(scope_path):
    return True

  return False

def isAgeSufficient(birth_date, minimal_age, as_of_date):
  """Returns True if the specified birth_date indicates that minimal_age
  has been reached no later than on as_of_date.
  """
  min_year = as_of_date.year - minimal_age
  min_date = as_of_date.replace(year=min_year)

  return True if birth_date <= min_date else False
<commit_msg>isAgeSufficient renamed to isAgeSufficientForProgram and reimplemented.<commit_after>#!/usr/bin/env python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""Common validation helper functions.
"""

__authors__ = [
  '"Lennard de Rijk" <ljvderijk@gmail.com>',
  '"Pawel Solyga" <pawel.solyga@gmail.com>',
  ]

import feedparser

from google.appengine.api import urlfetch
from google.appengine.api import urlfetch_errors

from soc.models import linkable

def isFeedURLValid(feed_url=None):
  """Returns True if provided url is valid ATOM or RSS.

  Args:
    feed_url: ATOM or RSS feed url
  """

  # a missing or empty feed url is never valid
  if not feed_url:
    return False

  try:
    result = urlfetch.fetch(feed_url)
  except urlfetch_errors.Error:
    return False

  # 200 is the status code for 'all ok'
  if result.status_code != 200:
    return False

  try:
    parsed_feed = feedparser.parse(result.content)
  except:
    return False

  # version is always present if the feed is valid
  if not parsed_feed.version:
    return False

  return True

def isLinkIdFormatValid(link_id):
  """Returns True if link_id is in a valid format.

  Args:
    link_id: link ID used in URLs for identification
  """
  if linkable.LINK_ID_REGEX.match(link_id):
    return True
  return False

def isScopePathFormatValid(scope_path):
  """Returns True if scope_path is in a valid format.

  Args:
    scope_path: scope path prepended to link ID
      used for identification.
  """

  if linkable.SCOPE_PATH_REGEX.match(scope_path):
    return True

  return False

def isAgeSufficientForProgram(birth_date, program):
  """Returns True if the specified birth_date indicates that minimal_age
  has been reached no later than on as_of_date for the specified program.
  """

  # do not check if the data is not present
  if program.student_min_age_as_of and program.student_min_age:
    min_year = program.student_min_age_as_of.year - program.student_min_age
    min_date = program.student_min_age_as_of.replace(year=min_year)
    return True if birth_date <= min_date else False
  else:
    return True
<|endoftext|>


<commit_before>from google.appengine.ext import db

class Profile(db.Model):
  """
  """

  #:
  profile = db.StringProperty(required=True)

  #:
  path = db.StringProperty(required=True)
<commit_msg>Removed unused Profile model.<commit_after><|endoftext|>


<commit_before>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""This module contains the Request Model."""

__authors__ = [
  '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  '"Lennard de Rijk" <ljvderijk@gmail.com>',
]

from google.appengine.ext import db

from django.utils.translation import ugettext

import soc.models.user
import soc.models.group

class Request(soc.models.linkable.Linkable):
  """A request is made to allow a person to create a new Role entity.
  """

  role = db.StringProperty(required=True)
  role.help_text = ugettext(
      'This should be the type of the role that is requested')

  role_verbose = db.StringProperty(required=True)
  role_verbose.help_text = ugettext(
      'This should be the verbose name of the role that is in this request')

  # property that determines the status of the request
  # new : new Request
  # group_accepted : The group has accepted this request
  # completed : This request has been handled either following a creation of
  #             the role entity
  # rejected : This request has been rejected by either the user or the group
  # ignored : The request has been ignored by the group and will not give
  #           the user access to create the role
  status = db.StringProperty(required=True, default='new',
      choices=['new', 'group_accepted', 'completed', 'rejected','ignored'])
  status.help_text = ugettext('Shows the status of the request')

  #: DateTime when the request was created
  created_on = db.DateTimeProperty(auto_now_add=True)
<commit_msg>Redone the Request object to contain a message property and work on ID-basis.<commit_after>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""This module contains the Request Model."""

__authors__ = [
  '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  '"Lennard de Rijk" <ljvderijk@gmail.com>',
]

from google.appengine.ext import db

from django.utils.translation import ugettext

from soc.models.base import ModelWithFieldAttributes
from soc.models.group import Group
from soc.models.user import User

class Request(ModelWithFieldAttributes):
  """A request is made to allow a person to create a new Role entity.
  """

  #: The internal name of the role
  role = db.StringProperty(required=True)

  #: The user this request is from
  user = db.ReferenceProperty(
      reference_class=User,
      required=True, collection_name='requests',
      verbose_name=ugettext('User'))

  #: The group this request is for
  group = db.ReferenceProperty(
      reference_class=Group,
      required=True, collection_name='requests',
      verbose_name=ugettext('Group'))

  #: An optional message shown to the receiving end of this request
  message = db.TextProperty(required=False, default='',
                            verbose_name=ugettext("Message"))
  message.help_text = ugettext(
      'This is an optional message shown to the receiver of this request.')

  # property that determines the status of the request
  # new : new Request
  # group_accepted : The group has accepted this request
  # completed : This request has been handled either following a creation of
  #             the role entity
  # rejected : This request has been rejected by either the user or the group
  # ignored : The request has been ignored by the group and will not give
  #           the user access to create the role
  status = db.StringProperty(required=True, default='new',
      choices=['new', 'group_accepted', 'completed', 'rejected','ignored'])
  status.help_text = ugettext('Shows the status of the request.')

  #: DateTime when the request was created
  created_on = db.DateTimeProperty(auto_now_add=True)

  #: DateTime when this request was last modified
  modified_on = db.DateTimeProperty(auto_now=True)
<|endoftext|>


<commit_before>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""Seeds or clears the datastore.
"""

__authors__ = [
    '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  ]

import datetime
import itertools

from google.appengine.api import users
from google.appengine.api import memcache
from google.appengine.ext import db

from django import http

from soc.logic.models.ranker_root import logic as ranker_root_logic
from soc.models import student_proposal
from soc.models.document import Document
from soc.models.host import Host
from soc.models.mentor import Mentor
from soc.models.notification import Notification
from soc.models.org_admin import OrgAdmin
from soc.models.organization import Organization
from soc.models.org_app import OrgApplication
from soc.models.program import Program
from soc.models.site import Site
from soc.models.sponsor import Sponsor
from soc.models.timeline import Timeline
from soc.models.user import User

def seed(request, *args, **kwargs):
  """Seeds the datastore with some default values.

  Understands the following GET args:
    many_users: create 200 users instead of 15, out of which 100 have
        a e-mail address in the auth domain
    user_start: where to start adding new users at
    user_end: where to stop adding new users at
    user_goal: how many users to add in total
    user_step: how many users to add per request, defaults to 15
    many_orgs: create 200 pre-accepted and 200 pre-denied org apps
        instead of just 1- pre-accepted ones, also create 200
        orgs instead of just 15.

    user is redirected to if user_end < user_goal, incrementing both
    user_start and user_end with user_step.
  """

  get_args = request.GET

  site_properties = {
      'key_name': 'site',
      'link_id': 'site',
      }

  site = Site(**site_properties)
  site.put()

  account = users.get_current_user()

  if not account:
    account = users.User(email='test@example.com')

  user_properties = {
      'key_name': 'test',
      'link_id': 'test',
      'account': account,
      'name': 'Test',
      }

  current_user = User(**user_properties)
  current_user.put()

  many_users = get_args.get('many_users')
  user_goal = int(get_args.get('user_goal', '0'))
  user_start = int(get_args.get('user_start', '0'))
  user_end = int(get_args.get('user_end', '0'))
  user_step = int(get_args.get('user_step', '15'))

  for i in range(100 if many_users else 15):
    user_properties = {
        'key_name': 'user_%d' % i,
        'link_id': 'user_%d' % i,
        'account': users.User(email='user_%d@example.com' % i),
        'name': 'User %d' % i,
        }
    entity = User(**user_properties)
    entity.put()

  for i in range(100, 200) if many_users else []:
    user_properties = {
        'key_name': 'user_%d' % i,
        'link_id': 'user_%d' % i,
        'account': users.User(email='user_%d' % i),
        'name': 'User %d' % i,
        }
    entity = User(**user_properties)
    entity.put()

  for i in range(user_start, user_end) if (user_start and user_end) else []:
    user_properties = {
        'key_name': 'lots_user_%d' % i,
        'link_id': 'lots_user_%d' % i,
        'account': users.User(email='lots_user_%d@example.com' % i),
        'name': 'Lots User %d' % i,
        }
    entity = User(**user_properties)
    entity.put()

  if user_end < user_goal:
    url = '/seed_db?user_start=%d&user_end=%d&user_goal=%d' % (
        user_start+user_step, user_end+user_step, user_goal)
    return http.HttpResponseRedirect(url)

  group_properties = {
       'key_name': 'google',
       'link_id': 'google',
       'name': 'Google Inc.',
       'short_name': 'Google',
       'founder': current_user,
       'home_page': 'http://www.google.com',
       'email': 'ospo@google.com',
       'description': 'This is the profile for Google.',
       'contact_street': 'Some Street',
       'contact_city': 'Some City',
       'contact_country': 'United States',
       'contact_postalcode': '12345',
       'phone': '1-555-BANANA',
       'status': 'active',
       }

  google = Sponsor(**group_properties)
  google.put()

  role_properties = {
      'key_name': 'google/test',
      'link_id': 'test',
      'scope': google,
      'scope_path': 'google',
      'user': current_user,
      'given_name': 'Test',
      'surname': 'Example',
      'name_on_documents': 'Test Example',
      'email': 'test@example.com',
      'res_street': 'Some Street',
      'res_city': 'Some City',
      'res_state': 'Some State',
      'res_country': 'United States',
      'res_postalcode': '12345',
      'phone': '1-555-BANANA',
      'birth_date': db.DateProperty.now(),
      'agreed_to_tos': True,
      }

  google_host = Host(**role_properties)
  google_host.put()

  timeline_properties = {
        'key_name': 'google/gsoc2009',
        'link_id': 'gsoc2009',
        'scope_path': 'google',
        'scope': google,
        }

  gsoc2009_timeline = Timeline(**timeline_properties)
  gsoc2009_timeline.put()

  program_properties = {
      'key_name': 'google/gsoc2009',
      'link_id': 'gsoc2009',
      'scope_path': 'google',
      'scope': google,
      'name': 'Google Summer of Code 2009',
      'short_name': 'GSoC 2009',
      'group_label': 'GSOC',
      'description': 'This is the program for GSoC 2009.',
      'apps_tasks_limit': 42,
      'slots': 42,
      'workflow': 'gsoc',
      'timeline': gsoc2009_timeline,
      'status': 'visible',
      }

  gsoc2009 = Program(**program_properties)
  gsoc2009.put()

  timeline_properties = {
        'key_name': 'google/ghop2009',
        'link_id': 'ghop2009',
        'scope_path': 'google',
        'scope': google,
        }

  ghop2009_timeline = Timeline(**timeline_properties)
  ghop2009_timeline.put()

  program_properties.update({
      'key_name': 'google/ghop2009',
      'link_id': 'ghop2009',
      'name': 'Google Highly Open Participation Contest 2009',
      'short_name': 'GHOP 2009',
      'group_label': 'GHOP',
      'description': 'This is the program for GHOP 2009.',
      'workflow': 'ghop',
      'timeline': ghop2009_timeline,
      })

  ghop2009 = Program(**program_properties)
  ghop2009.put()

  many_orgs = get_args.get('many_orgs')

  org_app_properties = {
    'scope_path': 'google/gsoc2009',
    'scope': gsoc2009,
    'applicant': current_user,
    'home_page': 'http://www.google.com',
    'email': 'org@example.com',
    'irc_channel': '#care',
    'pub_mailing_list': 'http://groups.google.com',
    'dev_mailing_list': 'http://groups.google.com',
    'description': 'This is an awesome org!',
    'why_applying': 'Because we can',
    'member_criteria': 'They need to be awesome',
    'status': 'pre-accepted',
    'license_name': 'Apache License, 2.0',
    'ideas': 'http://code.google.com/p/soc/issues',
    'contrib_disappears': 'We use google to find them',
    'member_disappears': 'See above',
    'encourage_contribs': 'We offer them cookies.',
    'continued_contribs': 'We promise them a cake.',
    'agreed_to_admin_agreement': True,
    }

  for i in range(200 if many_orgs else 10):
    org_app_properties['key_name'] = 'google/gsoc2009/wannabe_%d' % i
    org_app_properties['link_id'] = 'wannabe_%d' % i
    org_app_properties['name'] = 'Wannabe %d' % i
    entity = OrgApplication(**org_app_properties)
    entity.put()

  org_app_properties['status'] = 'pre-rejected'

  for i in range(200, 400) if many_orgs else []:
    org_app_properties['key_name'] = 'google/gsoc2009/loser_%d' % i
    org_app_properties['link_id'] = 'loser_%d' % i
    org_app_properties['name'] = 'Loser %d' % i
    entity = OrgApplication(**org_app_properties)
    entity.put()

  group_properties.update({
    'key_name': 'google/ghop2009/melange',
    'link_id': 'melange',
    'name': 'Melange Development Team',
    'short_name': 'Melange',
    'scope_path': 'google/ghop2009',
    'scope': ghop2009,
    'home_page': 'http://code.google.com/p/soc',
    'description': 'Melange, share the love!',
    'license_name': 'Apache License',
    'ideas': 'http://code.google.com/p/soc/issues',
    })

  melange = Organization(**group_properties)
  melange.put()
  # create a new ranker
  ranker_root_logic.create(student_proposal.DEF_RANKER_NAME, melange,
      student_proposal.DEF_SCORE, 100)

  group_properties.update({
    'scope_path': 'google/gsoc2009',
    'scope': gsoc2009,
    })

  for i in range(200 if many_orgs else 15):
    group_properties.update({
        'key_name': 'google/gsoc2009/org_%d' % i,
        'link_id': 'org_%d' % i,
        'name': 'Organization %d' % i,
        'short_name': 'Org %d' % i,
        'description': 'Organization %d!' % i,
        })

    entity = Organization(**group_properties)
    entity.put()
    # create a new ranker
    ranker_root_logic.create(student_proposal.DEF_RANKER_NAME, entity,
        student_proposal.DEF_SCORE, 100)

  role_properties.update({
      'key_name': 'google/ghop2009/melange/test',
      'link_id': 'test',
      'scope_path': 'google/ghop2009/melange',
      'scope': melange,
      'program': ghop2009,
      })

  melange_admin = OrgAdmin(**role_properties)
  melange_admin.put()

  melange_mentor = Mentor(**role_properties)
  melange_mentor.put()

  document_properties = {
      'key_name': 'site/site/home',
      'link_id': 'home',
      'scope_path': 'site',
      'scope': site,
      'prefix': 'site',
      'author': current_user,
      'title': 'Home Page',
      'short_name': 'Home',
      'content': 'This is the Home Page',
      'modified_by': current_user,
      }

  home_document = Document(**document_properties)
  home_document.put()

  document_properties = {
      'key_name': 'user/test/notes',
      'link_id': 'notes',
      'scope_path': 'test',
      'scope': current_user,
      'prefix': 'user',
      'author': current_user,
      'title': 'My Notes',
      'short_name': 'Notes',
      'content': 'These are my notes',
      'modified_by': current_user,
      }

  notes_document = Document(**document_properties)
  notes_document.put()

  site.home = home_document
  site.put()

  memcache.flush_all()

  return http.HttpResponse('Done')

def clear(*args, **kwargs):
  """Removes all entities from the datastore.
  """

  entities = itertools.chain(*[
      Notification.all(),
      Mentor.all(),
      OrgAdmin.all(),
      Organization.all(),
      OrgApplication.all(),
      Timeline.all(),
      Program.all(),
      Host.all(),
      Sponsor.all(),
      User.all(),
      Site.all(),
      Document.all(),
      ])

  for entity in entities:
    entity.delete()

  memcache.flush_all()

  return http.HttpResponse('Done')

def reseed(*args, **kwargs):
  """Clears and seeds the datastore.
  """

  clear(*args, **kwargs)
  seed(*args, **kwargs)

  return http.HttpResponse('Done')
<commit_msg>Make it possible to only add users<commit_after>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""Seeds or clears the datastore.
"""

__authors__ = [
    '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  ]

import datetime
import itertools

from google.appengine.api import users
from google.appengine.api import memcache
from google.appengine.ext import db

from django import http

from soc.logic.models.ranker_root import logic as ranker_root_logic
from soc.models import student_proposal
from soc.models.document import Document
from soc.models.host import Host
from soc.models.mentor import Mentor
from soc.models.notification import Notification
from soc.models.org_admin import OrgAdmin
from soc.models.organization import Organization
from soc.models.org_app import OrgApplication
from soc.models.program import Program
from soc.models.site import Site
from soc.models.sponsor import Sponsor
from soc.models.timeline import Timeline
from soc.models.user import User

def seed(request, *args, **kwargs):
  """Seeds the datastore with some default values.

  Understands the following GET args:
    many_users: create 200 users instead of 15, out of which 100 have
        a e-mail address in the auth domain
    user_start: where to start adding new users at
    user_end: where to stop adding new users at
    user_goal: how many users to add in total, implies user_only
    user_step: how many users to add per request, defaults to 15
    user_only: stop after adding new users
    many_orgs: create 200 pre-accepted and 200 pre-denied org apps
        instead of just 1- pre-accepted ones, also create 200
        orgs instead of just 15.

    user is redirected to if user_end < user_goal, incrementing both
    user_start and user_end with user_step.
  """

  get_args = request.GET

  site_properties = {
      'key_name': 'site',
      'link_id': 'site',
      }

  site = Site(**site_properties)
  site.put()

  account = users.get_current_user()

  if not account:
    account = users.User(email='test@example.com')

  user_properties = {
      'key_name': 'test',
      'link_id': 'test',
      'account': account,
      'name': 'Test',
      }

  current_user = User(**user_properties)
  current_user.put()

  many_users = get_args.get('many_users')
  user_goal = int(get_args.get('user_goal', '0'))
  user_start = int(get_args.get('user_start', '0'))
  user_end = int(get_args.get('user_end', '0'))
  user_step = int(get_args.get('user_step', '15'))
  user_only = get_args.get('user_only') or user_goal

  for i in range(100 if many_users else 15):
    user_properties = {
        'key_name': 'user_%d' % i,
        'link_id': 'user_%d' % i,
        'account': users.User(email='user_%d@example.com' % i),
        'name': 'User %d' % i,
        }
    entity = User(**user_properties)
    entity.put()

  for i in range(100, 200) if many_users else []:
    user_properties = {
        'key_name': 'user_%d' % i,
        'link_id': 'user_%d' % i,
        'account': users.User(email='user_%d' % i),
        'name': 'User %d' % i,
        }
    entity = User(**user_properties)
    entity.put()

  for i in range(user_start, user_end) if (user_start and user_end) else []:
    user_properties = {
        'key_name': 'lots_user_%d' % i,
        'link_id': 'lots_user_%d' % i,
        'account': users.User(email='lots_user_%d@example.com' % i),
        'name': 'Lots User %d' % i,
        }
    entity = User(**user_properties)
    entity.put()

  if user_end < user_goal:
    url = '/seed_db?user_start=%d&user_end=%d&user_goal=%d' % (
        user_start+user_step, user_end+user_step, user_goal)
    return http.HttpResponseRedirect(url)

  if user_only:
    return http.HttpResponse('Done with users')

  group_properties = {
       'key_name': 'google',
       'link_id': 'google',
       'name': 'Google Inc.',
       'short_name': 'Google',
       'founder': current_user,
       'home_page': 'http://www.google.com',
       'email': 'ospo@google.com',
       'description': 'This is the profile for Google.',
       'contact_street': 'Some Street',
       'contact_city': 'Some City',
       'contact_country': 'United States',
       'contact_postalcode': '12345',
       'phone': '1-555-BANANA',
       'status': 'active',
       }

  google = Sponsor(**group_properties)
  google.put()

  role_properties = {
      'key_name': 'google/test',
      'link_id': 'test',
      'scope': google,
      'scope_path': 'google',
      'user': current_user,
      'given_name': 'Test',
      'surname': 'Example',
      'name_on_documents': 'Test Example',
      'email': 'test@example.com',
      'res_street': 'Some Street',
      'res_city': 'Some City',
      'res_state': 'Some State',
      'res_country': 'United States',
      'res_postalcode': '12345',
      'phone': '1-555-BANANA',
      'birth_date': db.DateProperty.now(),
      'agreed_to_tos': True,
      }

  google_host = Host(**role_properties)
  google_host.put()

  timeline_properties = {
        'key_name': 'google/gsoc2009',
        'link_id': 'gsoc2009',
        'scope_path': 'google',
        'scope': google,
        }

  gsoc2009_timeline = Timeline(**timeline_properties)
  gsoc2009_timeline.put()

  program_properties = {
      'key_name': 'google/gsoc2009',
      'link_id': 'gsoc2009',
      'scope_path': 'google',
      'scope': google,
      'name': 'Google Summer of Code 2009',
      'short_name': 'GSoC 2009',
      'group_label': 'GSOC',
      'description': 'This is the program for GSoC 2009.',
      'apps_tasks_limit': 42,
      'slots': 42,
      'workflow': 'gsoc',
      'timeline': gsoc2009_timeline,
      'status': 'visible',
      }

  gsoc2009 = Program(**program_properties)
  gsoc2009.put()

  timeline_properties = {
        'key_name': 'google/ghop2009',
        'link_id': 'ghop2009',
        'scope_path': 'google',
        'scope': google,
        }

  ghop2009_timeline = Timeline(**timeline_properties)
  ghop2009_timeline.put()

  program_properties.update({
      'key_name': 'google/ghop2009',
      'link_id': 'ghop2009',
      'name': 'Google Highly Open Participation Contest 2009',
      'short_name': 'GHOP 2009',
      'group_label': 'GHOP',
      'description': 'This is the program for GHOP 2009.',
      'workflow': 'ghop',
      'timeline': ghop2009_timeline,
      })

  ghop2009 = Program(**program_properties)
  ghop2009.put()

  many_orgs = get_args.get('many_orgs')

  org_app_properties = {
    'scope_path': 'google/gsoc2009',
    'scope': gsoc2009,
    'applicant': current_user,
    'home_page': 'http://www.google.com',
    'email': 'org@example.com',
    'irc_channel': '#care',
    'pub_mailing_list': 'http://groups.google.com',
    'dev_mailing_list': 'http://groups.google.com',
    'description': 'This is an awesome org!',
    'why_applying': 'Because we can',
    'member_criteria': 'They need to be awesome',
    'status': 'pre-accepted',
    'license_name': 'Apache License, 2.0',
    'ideas': 'http://code.google.com/p/soc/issues',
    'contrib_disappears': 'We use google to find them',
    'member_disappears': 'See above',
    'encourage_contribs': 'We offer them cookies.',
    'continued_contribs': 'We promise them a cake.',
    'agreed_to_admin_agreement': True,
    }

  for i in range(200 if many_orgs else 10):
    org_app_properties['key_name'] = 'google/gsoc2009/wannabe_%d' % i
    org_app_properties['link_id'] = 'wannabe_%d' % i
    org_app_properties['name'] = 'Wannabe %d' % i
    entity = OrgApplication(**org_app_properties)
    entity.put()

  org_app_properties['status'] = 'pre-rejected'

  for i in range(200, 400) if many_orgs else []:
    org_app_properties['key_name'] = 'google/gsoc2009/loser_%d' % i
    org_app_properties['link_id'] = 'loser_%d' % i
    org_app_properties['name'] = 'Loser %d' % i
    entity = OrgApplication(**org_app_properties)
    entity.put()

  group_properties.update({
    'key_name': 'google/ghop2009/melange',
    'link_id': 'melange',
    'name': 'Melange Development Team',
    'short_name': 'Melange',
    'scope_path': 'google/ghop2009',
    'scope': ghop2009,
    'home_page': 'http://code.google.com/p/soc',
    'description': 'Melange, share the love!',
    'license_name': 'Apache License',
    'ideas': 'http://code.google.com/p/soc/issues',
    })

  melange = Organization(**group_properties)
  melange.put()
  # create a new ranker
  ranker_root_logic.create(student_proposal.DEF_RANKER_NAME, melange,
      student_proposal.DEF_SCORE, 100)

  group_properties.update({
    'scope_path': 'google/gsoc2009',
    'scope': gsoc2009,
    })

  for i in range(200 if many_orgs else 15):
    group_properties.update({
        'key_name': 'google/gsoc2009/org_%d' % i,
        'link_id': 'org_%d' % i,
        'name': 'Organization %d' % i,
        'short_name': 'Org %d' % i,
        'description': 'Organization %d!' % i,
        })

    entity = Organization(**group_properties)
    entity.put()
    # create a new ranker
    ranker_root_logic.create(student_proposal.DEF_RANKER_NAME, entity,
        student_proposal.DEF_SCORE, 100)

  role_properties.update({
      'key_name': 'google/ghop2009/melange/test',
      'link_id': 'test',
      'scope_path': 'google/ghop2009/melange',
      'scope': melange,
      'program': ghop2009,
      })

  melange_admin = OrgAdmin(**role_properties)
  melange_admin.put()

  melange_mentor = Mentor(**role_properties)
  melange_mentor.put()

  document_properties = {
      'key_name': 'site/site/home',
      'link_id': 'home',
      'scope_path': 'site',
      'scope': site,
      'prefix': 'site',
      'author': current_user,
      'title': 'Home Page',
      'short_name': 'Home',
      'content': 'This is the Home Page',
      'modified_by': current_user,
      }

  home_document = Document(**document_properties)
  home_document.put()

  document_properties = {
      'key_name': 'user/test/notes',
      'link_id': 'notes',
      'scope_path': 'test',
      'scope': current_user,
      'prefix': 'user',
      'author': current_user,
      'title': 'My Notes',
      'short_name': 'Notes',
      'content': 'These are my notes',
      'modified_by': current_user,
      }

  notes_document = Document(**document_properties)
  notes_document.put()

  site.home = home_document
  site.put()

  memcache.flush_all()

  return http.HttpResponse('Done')

def clear(*args, **kwargs):
  """Removes all entities from the datastore.
  """

  entities = itertools.chain(*[
      Notification.all(),
      Mentor.all(),
      OrgAdmin.all(),
      Organization.all(),
      OrgApplication.all(),
      Timeline.all(),
      Program.all(),
      Host.all(),
      Sponsor.all(),
      User.all(),
      Site.all(),
      Document.all(),
      ])

  for entity in entities:
    entity.delete()

  memcache.flush_all()

  return http.HttpResponse('Done')

def reseed(*args, **kwargs):
  """Clears and seeds the datastore.
  """

  clear(*args, **kwargs)
  seed(*args, **kwargs)

  return http.HttpResponse('Done')
<|endoftext|>


<commit_before>import tika

def from_file(filename):
    """Parse filename using tika's AutoDetectParser."""
    stream = tika.FileInputStream(tika.File(filename))
    return __parse(stream)

def from_buffer(string):
    """Parse raw binary string using tika's AutoDetectParser."""
    stream = tika.ByteArrayInputStream(tika.JArray_byte(string))
    return __parse(stream)

def to_xml_from_file(filename):
    stream = tika.FileInputStream(tika.File(filename))
    return __handler(stream)

def to_xml_from_string(string):
    stream =  stream = tika.ByteArrayInputStream(tika.JArray_byte(string))
    return __handler(stream)

def __handler(stream):
    handler = tika.toHTMLContentHandler()
    met = tika.Metadata()
    pc = tika.ParseContext()
    parser = tika.AutoDetectParser()
    parser.parse(stream, handler, met, pc)
    return handler.toString()

def __parse(stream):
    parsed = {}
    parser = tika.AutoDetectParser()
    content = tika.BodyContentHandler(-1)
    metadata = tika.Metadata()
    context = tika.ParseContext()
    parser.parse(stream, content, metadata, context)
    parsed["content"] = content.toString()
    parsed["metadata"] = {}
    for n in metadata.names():
        parsed["metadata"][n] = metadata.get(n)
    return parsed
<commit_msg>Update __init__.py<commit_after>import tika

def from_file(filename):
    """Parse filename using tika's AutoDetectParser."""
    stream = tika.FileInputStream(tika.File(filename))
    return __parse(stream)

def from_buffer(string):
    """Parse raw binary string using tika's AutoDetectParser."""
    stream = tika.ByteArrayInputStream(tika.JArray_byte(string))
    return __parse(stream)

def to_xml_from_file(filename):
    stream = tika.FileInputStream(tika.File(filename))
    return __handler(stream)

def to_xml_from_string(string):
    stream =  stream = tika.ByteArrayInputStream(tika.JArray_byte(string))
    return __handler(stream)

def __handler(stream):
    handler = tika.ToHTMLContentHandler()
    met = tika.Metadata()
    pc = tika.ParseContext()
    parser = tika.AutoDetectParser()
    parser.parse(stream, handler, met, pc)
    return handler.toString()

def __parse(stream):
    parsed = {}
    parser = tika.AutoDetectParser()
    content = tika.BodyContentHandler(-1)
    metadata = tika.Metadata()
    context = tika.ParseContext()
    parser.parse(stream, content, metadata, context)
    parsed["content"] = content.toString()
    parsed["metadata"] = {}
    for n in metadata.names():
        parsed["metadata"][n] = metadata.get(n)
    return parsed
<|endoftext|>


<commit_before>from decimal import Decimal
from datetime import timedelta
from optparse import make_option

from django.core.management.base import BaseCommand
from django.utils import timezone
from dateutil.relativedelta import *

from silver.models import (Customer, MeteredFeatureUnitsLog, Invoice,
                           DocumentEntry, Proforma, Subscription)

class Command(BaseCommand):
    help = 'Generates the billing documents (Invoices, Proformas).'
    option_list = BaseCommand.option_list + (
        make_option('--subscription',
            action='store',
            dest='subscription_id',
            type="int"),
    )

    def _get_proration_percent_and_status(self, subscription, start_date,
                                          end_date):
        """
        Returns proration percent (how much of the interval will be billed) and
        the status (if the subscription is prorated or not).

        :param date: the date at which the percent and status are computed
        :returns: a tuple containing (Decimal(percent), status) where status
            can be one of [True, False]. The decimal value will from the
            interval [0.00; 1.00].
        :rtype: tuple
        """

        intervals = {
            'year': {'years': -subscription.plan.interval_count},
            'month': {'months': -subscription.plan.interval_count},
            'week': {'weeks': -subscription.plan.interval_count},
            'day': {'days': -subscription.plan.interval_count},
        }

        # This will be UTC, which implies a max difference of 27 hours ~= 1 day
        # NOTE (IMPORTANT): this will be a negative interval (e.g.: -1 month,
        # -1 week, etc.)
        interval_len = relativedelta(**intervals[subscription.plan.interval])

        if end_date + interval_len >= start_date:
            # Not prorated
            return False, Decimal('1.00')
        else:
            # Proration
            interval_start = end_date + interval_len
            days_in_interval = (end_date - interval_start).days
            days_since_subscription_start = (end_date - start_date).days
            percent = 100.0 * days_since_subscription_start / days_in_interval
            percent = Decimal(percent).quantize(Decimal('0.00')) / Decimal('100.0')

            return True, percent

    def _add_plan_trial(self, subscription, end_date, invoice=None,
                        proforma=None):
        unit = '%ss' % subscription.plan.interval
        interval = '%sly' % subscription.plan.interval

        start_date = subscription.start_date
        plan_price = Decimal('0.00')

        description = "{plan_name} plan trial subscription ({start_date} -"\
                      " {end_date})".format(plan_name=subscription.plan.name,
                                            interval=interval,
                                            start_date=start_date,
                                            end_date=end_date)
        DocumentEntry.objects.create(
            invoice=invoice, proforma=proforma, description=description,
            unit=unit, unit_price=plan_price, quantity=Decimal('1.00'),
            product_code=subscription.plan.product_code, prorated=prorated,
            start_date=start_date, end_date=end_date
        )

    def _add_plan_entry(self, subscription, now_date, invoice=None,
                  proforma=None):

        unit = '%ss' % subscription.plan.interval
        interval = '%sly' % subscription.plan.interval

        if subscription.is_billed_first_time:
            # First time billing and on trial => add only the trial entry
            if subscription.is_on_trial:
                # Add the trial
                self._add_plan_trial(subscription, now_date, invoice, proforma)
                return
            else:
                # First time billing and with ended trial => 2 entries:
                # 1) The trial one
                # 2) The remaining period

                # Add the trial
                self._add_plan_trial(subscription=subscription,
                                     end_date=subscription.trial_end,
                                     invoice=invoice, proforma=proforma)

                # Add prorated entry with dates between trial_end and now
                # E.g.: start_date = 2015-01-01
                #       trial_end  = 2015-01-10
                #       now_date   = 2015-01-20
                # will generate prorated entry between 2015-01-10 -> 2015-01-20
                start_date = subscription.trial_end
                end_date = now_date
        else:
            # Was billed before => we use the last_billing_date to determine
            # the current end date
            start_date = subscription.last_billing_date

            if subscription.state == 'canceled':
                end_date = now_date
            else:
                intervals = {
                    'year': {'years': +subscription.plan.interval_count},
                    'month': {'months': +subscription.plan.interval_count},
                    'week': {'weeks': +subscription.plan.interval_count},
                    'day': {'days': +subscription.plan.interval_count},
                }
                interval_len = relativedelta(**intervals[subscription.plan.interval])

                end_date = subscription.last_billing_date + interval_len

        prorated, percent = self._get_proration_percent_and_status(
            subscription, start_date, end_date
        )

        # Get the prorated value
        plan_price = subscription.plan.amount * percent

        # E.g.: PlanName monthly plan subscription (2015-01-01 - 2015-02-02)
        description = "{plan_name} {interval} plan subscription ({start_date}"\
                      " - {end_date})".format(plan_name=subscription.plan.name,
                                              interval=interval,
                                              start_date=start_date,
                                              end_date=end_date)

        # Add the document
        DocumentEntry.objects.create(
            invoice=invoice, proforma=proforma, description=description,
            unit=unit, unit_price=plan_price, quantity=Decimal('1.00'),
            product_code=subscription.plan.product_code, prorated=prorated,
            start_date=start_date, end_date=end_date
        )

    def _get_consumed_units(self, included_units, consumed_units):
        if included_units - consumed_units >= 0:
            return 0
        return consumed_units - included_units

    def _get_included_units(self, subscription, metered_feature, now_date):
        if subscription.is_on_trial:
            return metered_feature.included_units

        last_billing_date = subscription.last_billing_date
        if last_billing_date:
            # Was billed before
            start_date = last_billing_date
        else:
            # First billing cycle and the subscription is not on trial
            start_date = subscription.trial_end

        end_date = now_date

        prorated, percent = self._get_proration_percent_and_status(
            subscription, start_date, end_date)

        if not prorated:
            return metered_feature.included_units
        return percent * metered_feature.included_units

    def _add_mf_entries(self, subscription, now_date, invoice=None,
                        proforma=None):
        if subscription.last_billing_date:
            start_date = subscription.last_billing_date
        else:
            start_date = subscription.start_date

        for mf in subscription.plan.metered_features.all():
            criteria = {
                'metered_feature': mf,
                'subscription': subscription,
                'start_date__gte': start_date,
            }

            consumed_mf_log = MeteredFeatureUnitsLog.objects.filter(**criteria)
            for log_item in consumed_mf_log:
                included_units = self._get_included_units(subscription, mf,
                                                          now_date)
                total_units = self._get_consumed_units(included_units,
                                                       log_item.consumed_units)
                unit_price = Decimal('0.00') if subscription.is_on_trial else mf.price_per_unit
                description = "{name} ({start_date} - {end_date})".format(
                    name=mf.name,
                    start_date=log_item.start_date,
                    end_date=log_item.end_date)

                DocumentEntry.objects.create(
                    invoice=invoice, proforma=proforma, description=description,
                    unit=mf.unit, unit_price=unit_price, quantity=total_units,
                    product_code=mf.product_code, start_date=log_item.start_date,
                    end_date=log_item.end_date
                )

    def _add_plan(self, document, subscription, now_date):
        if subscription.plan.provider_flow == 'proforma':
            plan_entry_args = {'proforma': document}
        else:
            plan_entry_args = {'invoice': document}

        plan_entry_args.update({'subscription': subscription,
                                'now_date': now_date})
        self._add_plan_entry(**plan_entry_args)

    def _add_metered_features(self, document, subscription, now_date):
        if subscription.plan.provider_flow == 'proforma':
            mf_entry_args = {'proforma': document}
        else:
            mf_entry_args = {'invoice': document}

        mf_entry_args.update({'subscription': subscription,
                              'now_date': now_date})
        self._add_mf_entries(**mf_entry_args)

    def _create_document(self, provider, customer, subscription, now_date):
        provider_flow = subscription.plan.provider_flow
        DocumentModel = Proforma if provider_flow == 'proforma' else Invoice

        delta = timedelta(days=customer.payment_due_days)
        due_date = now_date + delta
        document = DocumentModel.objects.create(
            provider=subscription.plan.provider, customer=customer,
            due_date=due_date
        )

        return document

    def _print_status_to_stdout(self, subscription, created=False):
        if subscription.plan.provider_flow == 'proforma':
            doc_name = 'Proforma'
        else:
            doc_name = 'Invoice'
        action = 'Generating' if created else 'Updating'
        msg = '{action} {doc_name} for {subscription}.'.format(
            action=action, doc_name=doc_name, subscription=subscription)

        self.stdout.write(msg)

    def _generate_single_document(self, subscription_id):
        subscription = Subscription.objects.get(id=subscription_id)

        provider = subscription.plan.provider
        customer = subscription.customer
        now = timezone.now().date()

        document = self._create_document(provider, customer, subscription, now)
        self._print_status_to_stdout(subscription, created=True)

        # Add plan to invoice/proforma
        self._add_plan(document, subscription, now)
        # Add mf units to proforma/invoice
        self._add_metered_features(document, subscription, now)

        if subscription.state == 'canceled':
            subscription.end()

        if provider.default_document_state == 'issued':
            document.issue()
            document.save()

    def handle(self, *args, **options):
        # Use the same exact date for all the generated documents
        now = timezone.now().date()

        if options['subscription_id']:
            self._generate_single_document(options['subscription_id'])
            return

        for customer in Customer.objects.all():
            if customer.consolidated_billing:
                # Intermediary document for each provider
                document_per_provider = {}

                # Default doc state (issued, draft) for each provider
                default_doc_state = {}

                # TODO:
                # 1) If the subscription was on trial for a part of the month
                # add separate entry for the trial period and a prorated one
                # for the rest of the interval
                # => start_date -> trial_end; trial_end+1 -> now
                # 2) Add separate messages for the trial entry and the normal
                # one

                # Process all the active or canceled subscriptions
                criteria = {'state__in': ['active', 'canceled']}
                for subscription in customer.subscriptions.filter(**criteria):
                    if not subscription.should_be_billed:
                        continue

                    provider = subscription.plan.provider

                    default_doc_state[provider] = provider.default_document_state
                    if provider in document_per_provider:
                        document = document_per_provider[provider]
                        self._print_status_to_stdout(subscription,
                                                     created=False)
                    else:
                        document = self._create_document(provider, customer,
                                                         subscription, now)
                        document_per_provider[provider] = document
                        self._print_status_to_stdout(subscription,
                                                     created=True)

                    # Add plan to invoice/proforma
                    self._add_plan(document, subscription, now)
                    # Add mf units to proforma/invoice
                    self._add_metered_features(document, subscription, now)

                    if subscription.state == 'canceled':
                        subscription.end()
                        subscription.save()

                for provider, document in document_per_provider.iteritems():
                    if default_doc_state[provider] == 'issued':
                        document.issue()
                        document.save()
            else:
                # Generate an invoice for each subscription
                criteria = {'state__in': ['active', 'canceled']}
                for subscription in customer.subscriptions.filter(**criteria):
                    if not subscription.should_be_billed:
                        continue

                    provider = subscription.plan.provider
                    document = self._create_document(provider, customer,
                                                     subscription, now)
                    self._print_status_to_stdout(subscription, created=True)

                    # Add plan to invoice/proforma
                    self._add_plan(document, subscription, now)
                    # Add mf units to proforma/invoice
                    self._add_metered_features(document, subscription, now)

                    if subscription.state == 'canceled':
                        subscription.end()
                        subscription.save()

                    if provider.default_document_state == 'issued':
                        document.issue()
                        document.save()
<commit_msg>Changes :construction_worker:<commit_after>from decimal import Decimal
from datetime import timedelta
from optparse import make_option

from django.core.management.base import BaseCommand
from django.utils import timezone
from dateutil.relativedelta import *

from silver.models import (Customer, MeteredFeatureUnitsLog, Invoice,
                           DocumentEntry, Proforma, Subscription)

class Command(BaseCommand):
    help = 'Generates the billing documents (Invoices, Proformas).'
    option_list = BaseCommand.option_list + (
        make_option('--subscription',
            action='store',
            dest='subscription_id',
            type="int"),
    )

    def _get_proration_percent_and_status(self, subscription, start_date,
                                          end_date):
        """
        Returns proration percent (how much of the interval will be billed) and
        the status (if the subscription is prorated or not).

        :param date: the date at which the percent and status are computed
        :returns: a tuple containing (Decimal(percent), status) where status
            can be one of [True, False]. The decimal value will from the
            interval [0.00; 1.00].
        :rtype: tuple
        """

        intervals = {
            'year': {'years': -subscription.plan.interval_count},
            'month': {'months': -subscription.plan.interval_count},
            'week': {'weeks': -subscription.plan.interval_count},
            'day': {'days': -subscription.plan.interval_count},
        }

        # This will be UTC, which implies a max difference of 27 hours ~= 1 day
        # NOTE (IMPORTANT): this will be a negative interval (e.g.: -1 month,
        # -1 week, etc.)
        interval_len = relativedelta(**intervals[subscription.plan.interval])

        if end_date + interval_len >= start_date:
            # Not prorated
            return False, Decimal('1.00')
        else:
            # Proration
            interval_start = end_date + interval_len
            days_in_interval = (end_date - interval_start).days
            days_since_subscription_start = (end_date - start_date).days
            percent = 100.0 * days_since_subscription_start / days_in_interval
            percent = Decimal(percent).quantize(Decimal('0.00')) / Decimal('100.0')

            return True, percent

    def _add_plan_trial(self, subscription, end_date, invoice=None,
                        proforma=None):
        unit = '%ss' % subscription.plan.interval
        interval = '%sly' % subscription.plan.interval

        start_date = subscription.start_date
        plan_price = Decimal('0.00')

        description = "{plan_name} plan trial subscription ({start_date} -"\
                      " {end_date})".format(plan_name=subscription.plan.name,
                                            interval=interval,
                                            start_date=start_date,
                                            end_date=end_date)
        DocumentEntry.objects.create(
            invoice=invoice, proforma=proforma, description=description,
            unit=unit, unit_price=plan_price, quantity=Decimal('1.00'),
            product_code=subscription.plan.product_code, prorated=prorated,
            start_date=start_date, end_date=end_date
        )

    def _add_plan_entry(self, subscription, now_date, invoice=None,
                  proforma=None):

        unit = '%ss' % subscription.plan.interval
        interval = '%sly' % subscription.plan.interval

        if subscription.is_billed_first_time:
            # First time billing and on trial => add only the trial entry
            if subscription.is_on_trial:
                # Add the trial and exit
                self._add_plan_trial(subscription=subscription,
                                     end_date=now_date, invoice=invoice,
                                     proforma=proforma)
                return
            else:
                # First time billing and with ended trial => 2 entries:
                # 1) The trial one
                # 2) The remaining period

                # Add the trial
                self._add_plan_trial(subscription=subscription,
                                     end_date=subscription.trial_end,
                                     invoice=invoice, proforma=proforma)

                # Add prorated entry with dates between trial_end and now
                # E.g.: start_date = 2015-01-01
                #       trial_end  = 2015-01-10
                #       now_date   = 2015-01-20
                # will generate prorated entry between 2015-01-10 -> 2015-01-20
                # NOTE: even if the subscription was canceled before now_date
                # now_date is still considered the end interval chunk.
                start_date = subscription.trial_end
                end_date = now_date
        else:
            # Was billed before => we use the last_billing_date to determine
            # the current end date
            start_date = subscription.last_billing_date

            if subscription.state == 'canceled':
                end_date = now_date
            else:
                intervals = {
                    'year': {'years': +subscription.plan.interval_count},
                    'month': {'months': +subscription.plan.interval_count},
                    'week': {'weeks': +subscription.plan.interval_count},
                    'day': {'days': +subscription.plan.interval_count},
                }
                interval_len = relativedelta(**intervals[subscription.plan.interval])

                end_date = start_date + interval_len

        prorated, percent = self._get_proration_percent_and_status(
            subscription, start_date, end_date
        )

        # Get the plan's prorated value
        plan_price = subscription.plan.amount * percent

        # E.g.: PlanName monthly plan subscription (2015-01-01 - 2015-02-02)
        description = "{plan_name} {interval} plan subscription ({start_date}"\
                      " - {end_date})".format(plan_name=subscription.plan.name,
                                              interval=interval,
                                              start_date=start_date,
                                              end_date=end_date)

        # Add the document
        DocumentEntry.objects.create(
            invoice=invoice, proforma=proforma, description=description,
            unit=unit, unit_price=plan_price, quantity=Decimal('1.00'),
            product_code=subscription.plan.product_code, prorated=prorated,
            start_date=start_date, end_date=end_date
        )

    def _get_consumed_units(self, included_units, consumed_units):
        if included_units - consumed_units >= 0:
            return 0
        return consumed_units - included_units

    def _get_included_units(self, subscription, metered_feature, now_date):
        if subscription.is_on_trial:
            return metered_feature.included_units

        last_billing_date = subscription.last_billing_date
        if last_billing_date:
            # Was billed before
            start_date = last_billing_date
        else:
            # First billing cycle and the subscription is not on trial
            start_date = subscription.trial_end

        end_date = now_date

        prorated, percent = self._get_proration_percent_and_status(
            subscription, start_date, end_date)

        if not prorated:
            return metered_feature.included_units
        return percent * metered_feature.included_units

    def _add_mf_entries(self, subscription, now_date, invoice=None,
                        proforma=None):
        if subscription.last_billing_date:
            start_date = subscription.last_billing_date
        else:
            start_date = subscription.start_date

        for mf in subscription.plan.metered_features.all():
            criteria = {
                'metered_feature': mf,
                'subscription': subscription,
                'start_date__gte': start_date,
            }

            consumed_mf_log = MeteredFeatureUnitsLog.objects.filter(**criteria)
            for log_item in consumed_mf_log:
                included_units = self._get_included_units(subscription, mf,
                                                          now_date)
                total_units = self._get_consumed_units(included_units,
                                                       log_item.consumed_units)
                unit_price = Decimal('0.00') if subscription.is_on_trial else mf.price_per_unit
                description = "{name} ({start_date} - {end_date})".format(
                    name=mf.name,
                    start_date=log_item.start_date,
                    end_date=log_item.end_date)

                DocumentEntry.objects.create(
                    invoice=invoice, proforma=proforma, description=description,
                    unit=mf.unit, unit_price=unit_price, quantity=total_units,
                    product_code=mf.product_code, start_date=log_item.start_date,
                    end_date=log_item.end_date
                )

    def _add_plan(self, document, subscription, now_date):
        if subscription.plan.provider_flow == 'proforma':
            plan_entry_args = {'proforma': document}
        else:
            plan_entry_args = {'invoice': document}

        plan_entry_args.update({'subscription': subscription,
                                'now_date': now_date})
        self._add_plan_entry(**plan_entry_args)

    def _add_metered_features(self, document, subscription, now_date):
        if subscription.plan.provider_flow == 'proforma':
            mf_entry_args = {'proforma': document}
        else:
            mf_entry_args = {'invoice': document}

        mf_entry_args.update({'subscription': subscription,
                              'now_date': now_date})
        self._add_mf_entries(**mf_entry_args)

    def _create_document(self, provider, customer, subscription, now_date):
        provider_flow = subscription.plan.provider_flow
        DocumentModel = Proforma if provider_flow == 'proforma' else Invoice

        delta = timedelta(days=customer.payment_due_days)
        due_date = now_date + delta
        document = DocumentModel.objects.create(
            provider=subscription.plan.provider, customer=customer,
            due_date=due_date
        )

        return document

    def _print_status_to_stdout(self, subscription, created=False):
        if subscription.plan.provider_flow == 'proforma':
            doc_name = 'Proforma'
        else:
            doc_name = 'Invoice'
        action = 'Generating' if created else 'Updating'
        msg = '{action} {doc_name} for {subscription}.'.format(
            action=action, doc_name=doc_name, subscription=subscription)

        self.stdout.write(msg)

    def _generate_single_document(self, subscription_id):
        subscription = Subscription.objects.get(id=subscription_id)

        provider = subscription.plan.provider
        customer = subscription.customer
        now = timezone.now().date()

        document = self._create_document(provider, customer, subscription, now)
        self._print_status_to_stdout(subscription, created=True)

        # Add plan to invoice/proforma
        self._add_plan(document, subscription, now)
        # Add mf units to proforma/invoice
        self._add_metered_features(document, subscription, now)

        if subscription.state == 'canceled':
            subscription.end()

        if provider.default_document_state == 'issued':
            document.issue()
            document.save()

    def handle(self, *args, **options):
        # Use the same exact date for all the generated documents
        now = timezone.now().date()

        if options['subscription_id']:
            self._generate_single_document(options['subscription_id'])
            return

        for customer in Customer.objects.all():
            if customer.consolidated_billing:
                # Intermediary document for each provider
                document_per_provider = {}

                # Default doc state (issued, draft) for each provider
                default_doc_state = {}

                # TODO:
                # 1) If the subscription was on trial for a part of the month
                # add separate entry for the trial period and a prorated one
                # for the rest of the interval
                # => start_date -> trial_end; trial_end+1 -> now
                # 2) Add separate messages for the trial entry and the normal
                # one

                # Process all the active or canceled subscriptions
                criteria = {'state__in': ['active', 'canceled']}
                for subscription in customer.subscriptions.filter(**criteria):
                    if not subscription.should_be_billed:
                        continue

                    provider = subscription.plan.provider

                    default_doc_state[provider] = provider.default_document_state
                    if provider in document_per_provider:
                        document = document_per_provider[provider]
                        self._print_status_to_stdout(subscription,
                                                     created=False)
                    else:
                        document = self._create_document(provider, customer,
                                                         subscription, now)
                        document_per_provider[provider] = document
                        self._print_status_to_stdout(subscription,
                                                     created=True)

                    # Add plan to invoice/proforma
                    self._add_plan(document, subscription, now)
                    # Add mf units to proforma/invoice
                    self._add_metered_features(document, subscription, now)

                    if subscription.state == 'canceled':
                        subscription.end()
                        subscription.save()

                for provider, document in document_per_provider.iteritems():
                    if default_doc_state[provider] == 'issued':
                        document.issue()
                        document.save()
            else:
                # Generate an invoice for each subscription
                criteria = {'state__in': ['active', 'canceled']}
                for subscription in customer.subscriptions.filter(**criteria):
                    if not subscription.should_be_billed:
                        continue

                    provider = subscription.plan.provider
                    document = self._create_document(provider, customer,
                                                     subscription, now)
                    self._print_status_to_stdout(subscription, created=True)

                    # Add plan to invoice/proforma
                    self._add_plan(document, subscription, now)
                    # Add mf units to proforma/invoice
                    self._add_metered_features(document, subscription, now)

                    if subscription.state == 'canceled':
                        subscription.end()
                        subscription.save()

                    if provider.default_document_state == 'issued':
                        document.issue()
                        document.save()
<|endoftext|>


<commit_before>from decimal import Decimal
from datetime import timedelta
from optparse import make_option

from django.core.management.base import BaseCommand
from django.utils import timezone
from django.conf import settings

from silver.models import (Customer, MeteredFeatureUnitsLog, Invoice,
                           DocumentEntry, Proforma)

class Command(BaseCommand):
    help = 'Generates the billing documents (Invoices, Proformas).'
    option_list = BaseCommand.option_list + (
        make_option('--state',
                    action='store',
                    dest='state',
                    type='string',
                    default='draft',
                    help='The final state for the generated documents'),
    )

    def _add_plan_document_entry(self, subscription, plan, invoice=None,
                                 proforma=None):

        description = subscription.description or '%s plan subscription.' % plan.name
        DocumentEntry.objects.create(invoice=invoice, proforma=proforma,
                                     description=description,
                                     unit_price=plan.amount,
                                     quantity=Decimal('1.00'),
                                     product_code=plan.product_code)

    def _add_mf_document_entries(self, subscription, invoice=None,
                                 proforma=None):

        for mf in subscription.plan.metered_features.all():
            criteria = {'metered_feature': mf,
                        'subscription': subscription}
            total_units_consumed = 0
            consumed_mf_log = MeteredFeatureUnitsLog.objects.filter(**criteria)
            for log_item in consumed_mf_log:
                total_units_consumed += log_item.consumed_units
            final_units_count = max(0, total_units_consumed - mf.included_units)
            if final_units_count != 0:
                # Add the metered feature to the invoice
                DocumentEntry.objects.create(invoice=invoice,
                                             proforma=proforma,
                                             description=mf.name,
                                             unit_price=mf.price_per_unit,
                                             quantity=final_units_count,
                                             product_code=mf.product_code)

    def _add_plan_entry(self, provider_flow, subscription, plan, document):
        if provider_flow == 'proforma':
            entry_args = {'proforma': document}
        else:
            entry_args = {'invoice': document}

        doc_entry_args = entry_args.copy()
        doc_entry_args.update({'subscription': subscription,
                               'plan': plan})
        self._add_plan_document_entry(**doc_entry_args)

    def _add_mf_entries(self, provider_flow, document, subscription):
        if provider_flow == 'proforma':
            entry_args = {'proforma': document}
        else:
            entry_args = {'invoice': document}

        mf_entry_args = entry_args.copy()
        mf_entry_args.update({'subscription': subscription})
        self._add_mf_document_entries(**mf_entry_args)

    def handle(self, *args, **options):
        final_state = options['state']
        for customer in Customer.objects.all():
            self.stdout.write('Generating invoice(s) for: %s' % customer)
            if customer.consolidated_billing:
                # Cache the invoice/proforma per provider
                document_per_provider = {}
                for subscription in customer.subscriptions.all():
                    provider_flow = subscription.plan.provider_flow
                    DocumentModel = Proforma if provider_flow == 'proforma' else Invoice

                    plan = subscription.plan
                    if plan.provider in document_per_provider:
                        document = document_per_provider[plan.provider]
                    else:
                        delta = timedelta(days=settings.PAYMENT_DUE_DAYS)
                        due_date = timezone.now().date() + delta
                        document = DocumentModel.objects.create(
                            provider=plan.provider, customer=customer,
                            due_date=due_date)
                        document_per_provider[plan.provider] = document

                    # Add plan to invoice/proforma
                    self._add_plan_entry(provider_flow, subscription, plan,
                                         document)
                    # Add mf units to proforma/invoice
                    self._add_mf_entries(provider_flow, document, subscription)

                    if final_state == 'issued':
                        for document in document_per_provider.values():
                            document.issue()
                            document.save()
            else:
                # Generate an invoice for each subscription
                for subscription in customer.subscriptions.all():
                    provider_flow = subscription.plan.provider_flow
                    DocumentModel = Proforma if provider_flow == 'proforma' else Invoice

                    plan = subscription.plan
                    delta = timedelta(days=settings.PAYMENT_DUE_DAYS)
                    due_date = timezone.now().date() + delta
                    document = DocumentModel.objects.create(
                        provider=plan.provider, customer=customer,
                        due_date=due_date)

                    # Add plan to invoice/proforma
                    self._add_plan_entry(provider_flow, subscription, plan,
                                         document)
                    # Add mf units to proforma/invoice
                    self._add_mf_entries(provider_flow, document, subscription)

                    if final_state == 'issued':
                        for document in document_per_provider.values():
                            document.issue()
                            document.save()
<commit_msg>If the Subscription is on_trial, generate the invoice but use 0 as the value for all the items<commit_after>from decimal import Decimal
from datetime import timedelta
from optparse import make_option

from django.core.management.base import BaseCommand
from django.utils import timezone
from django.conf import settings

from silver.models import (Customer, MeteredFeatureUnitsLog, Invoice,
                           DocumentEntry, Proforma)

class Command(BaseCommand):
    help = 'Generates the billing documents (Invoices, Proformas).'
    option_list = BaseCommand.option_list + (
        make_option('--state',
                    action='store',
                    dest='state',
                    type='string',
                    default='draft',
                    help='The final state for the generated documents'),
    )

    def _add_plan_document_entry(self, subscription, plan, invoice=None,
                                 proforma=None):

        description = subscription.description or '%s plan subscription.' % plan.name

        unit_price = Decimal('0.00') if subscription.on_trial else plan.amount
        DocumentEntry.objects.create(invoice=invoice, proforma=proforma,
                                     description=description,
                                     unit_price=unit_price,
                                     quantity=Decimal('1.00'),
                                     product_code=plan.product_code)

    def _add_mf_document_entries(self, subscription, invoice=None,
                                 proforma=None):

        for mf in subscription.plan.metered_features.all():
            criteria = {'metered_feature': mf,
                        'subscription': subscription}
            total_units_consumed = 0
            consumed_mf_log = MeteredFeatureUnitsLog.objects.filter(**criteria)
            for log_item in consumed_mf_log:
                total_units_consumed += log_item.consumed_units
            final_units_count = max(0, total_units_consumed - mf.included_units)
            if final_units_count != 0:
                unit_price = Decimal('0.00') if subscription.on_trial else mf.price_per_unit
                # Add the metered feature to the invoice
                DocumentEntry.objects.create(invoice=invoice,
                                             proforma=proforma,
                                             description=mf.name,
                                             unit_price=unit_price,
                                             quantity=final_units_count,
                                             product_code=mf.product_code)

    def _add_plan_entry(self, provider_flow, subscription, plan, document):
        if provider_flow == 'proforma':
            entry_args = {'proforma': document}
        else:
            entry_args = {'invoice': document}

        doc_entry_args = entry_args.copy()
        doc_entry_args.update({'subscription': subscription, 'plan': plan})
        self._add_plan_document_entry(**doc_entry_args)

    def _add_mf_entries(self, provider_flow, document, subscription):
        if provider_flow == 'proforma':
            entry_args = {'proforma': document}
        else:
            entry_args = {'invoice': document}

        mf_entry_args = entry_args.copy()
        mf_entry_args.update({'subscription': subscription})
        self._add_mf_document_entries(**mf_entry_args)

    def handle(self, *args, **options):
        final_state = options['state']
        for customer in Customer.objects.all():
            self.stdout.write('Generating invoice(s) for: %s' % customer)
            if customer.consolidated_billing:
                # Cache the invoice/proforma per provider
                document_per_provider = {}
                for subscription in customer.subscriptions.all():
                    provider_flow = subscription.plan.provider_flow
                    DocumentModel = Proforma if provider_flow == 'proforma' else Invoice

                    plan = subscription.plan
                    if plan.provider in document_per_provider:
                        document = document_per_provider[plan.provider]
                    else:
                        delta = timedelta(days=settings.PAYMENT_DUE_DAYS)
                        due_date = timezone.now().date() + delta
                        document = DocumentModel.objects.create(
                            provider=plan.provider, customer=customer,
                            due_date=due_date)
                        document_per_provider[plan.provider] = document

                    # Add plan to invoice/proforma
                    self._add_plan_entry(provider_flow, subscription, plan,
                                         document)
                    # Add mf units to proforma/invoice
                    self._add_mf_entries(provider_flow, document, subscription)

                    if final_state == 'issued':
                        for document in document_per_provider.values():
                            document.issue()
                            document.save()
            else:
                # Generate an invoice for each subscription
                for subscription in customer.subscriptions.all():
                    provider_flow = subscription.plan.provider_flow
                    DocumentModel = Proforma if provider_flow == 'proforma' else Invoice

                    plan = subscription.plan
                    delta = timedelta(days=settings.PAYMENT_DUE_DAYS)
                    due_date = timezone.now().date() + delta
                    document = DocumentModel.objects.create(
                        provider=plan.provider, customer=customer,
                        due_date=due_date)

                    # Add plan to invoice/proforma
                    self._add_plan_entry(provider_flow, subscription, plan,
                                         document)
                    # Add mf units to proforma/invoice
                    self._add_mf_entries(provider_flow, document, subscription)

                    if final_state == 'issued':
                        for document in document_per_provider.values():
                            document.issue()
                            document.save()
<|endoftext|>