##############################################################################
#
# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
#                    Sebastien Robin <seb@nexedi.com>
#
# 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 AccessControl import ClassSecurityInfo
from Acquisition import aq_base, aq_parent, aq_inner, aq_acquire
from Products.CMFCore.utils import getToolByName

from Products.ERP5Type import Permissions, PropertySheet, Constraint, interfaces
from Products.ERP5.Document.Rule import Rule

from zLOG import LOG, INFO

class PaymentRule(Rule):
  """Payment Rule generates payment simulation movement from invoice
  transaction simulation movements.
  """

  # CMF Type Definition
  meta_type = 'ERP5 Payment Rule'
  portal_type = 'Payment Rule'
  add_permission = Permissions.AddPortalContent

  # Declarative security
  security = ClassSecurityInfo()
  security.declareObjectProtected(Permissions.AccessContentsInformation)

  receivable_account_type_list = ('asset/receivable', )
  payable_account_type_list = ('liability/payable', )


  def _getPaymentConditionList(self, movement):
    """Returns payment conditions for this movement.
    """
    while 1:
      delivery_movement = movement.getDeliveryValue()
      if delivery_movement is not None:
        explanation = delivery_movement.getExplanationValue()
        payment_condition_list = explanation.contentValues(
               filter=dict(portal_type='Payment Condition'))
        if payment_condition_list:
          return payment_condition_list

      # 'order' category is deprecated. it is kept for compatibility.
      order_movement = movement.getOrderValue()
      if order_movement is not None:
        explanation = order_movement.getExplanationValue()
        payment_condition_list = explanation.contentValues(
               filter=dict(portal_type='Payment Condition'))
        if payment_condition_list:
          return payment_condition_list

      movement = movement.getParentValue().getParentValue()
      if movement.getPortalType() != self.movement_type:
        LOG('ERP5', INFO, "PaymentRule couldn't find payment condition")
        return []
   
  def _createMovementsForPaymentCondition(self,
        applied_rule, payment_condition):
    """Create simulation movements for this payment condition.
    """
    simulation_movement = applied_rule.getParentValue()
    date = payment_condition.TradeCondition_getDueDate()
    
    if payment_condition.getQuantity():
      quantity = payment_condition.getQuantity()
    else:
      ratio = payment_condition.getEfficiency(1)
      quantity = simulation_movement.getQuantity() * ratio

    edit_dict = dict(
          causality_value=payment_condition,
          payment_mode=payment_condition.getPaymentMode(),
          source=simulation_movement.getSource(),
          source_section=simulation_movement.getSourceSection(),
          source_payment=payment_condition.getSourcePayment() or
                            simulation_movement.getSourcePayment(),
          destination=simulation_movement.getDestination(),
          destination_section=simulation_movement.getDestinationSection(),
          destination_payment=payment_condition.getDestinationPayment() or
                            simulation_movement.getDestinationPayment(),
          resource=simulation_movement.getResource(),
          start_date=date,
          price=1,
          quantity= - quantity,)
    
    applied_rule.newContent( **edit_dict )

    edit_dict['source'] = self.getSourcePayment()
    edit_dict['destination'] = self.getDestinationPayment()
    edit_dict['quantity'] = - edit_dict['quantity']
    applied_rule.newContent( **edit_dict )
    
    
  security.declareProtected(Permissions.ModifyPortalContent, 'expand')
  def expand(self, applied_rule, **kw):
    """Expands the current movement downward.
    """
    my_parent_movement = applied_rule.getParentValue()
    # generate for source
    bank_account = self.getDestinationPaymentValue(
                           portal_type='Account')
    assert bank_account is not None

    for payment_condition in self._getPaymentConditionList(
                                          my_parent_movement):
      payment_condition_url = payment_condition.getRelativeUrl()
      # look for a movement for this payment condition:
      corresponding_movement_list = []
      for simulation_movement in applied_rule.contentValues():
        if simulation_movement.getCausality() == payment_condition_url:
          corresponding_movement_list.append(simulation_movement)
      if not corresponding_movement_list:
        self._createMovementsForPaymentCondition(applied_rule,
                                                 payment_condition)
      else:
        # TODO: update corresponding_movement_list
        pass
    
    #Rule.expand(self, applied_rule, **kw)

  def test(self, context, tested_base_category_list=None):
    """Test if this rule apply.
    """

    # XXX for now disable this rule
    return False

    if context.getParentValue()\
        .getSpecialiseValue().getPortalType() == 'Payment Rule':
      return False

    for account in ( context.getSourceValue(portal_type='Account'),
        context.getDestinationValue(portal_type='Account')):
      if account is not None:
        account_type = account.getAccountType()
        if account_type in self.receivable_account_type_list or \
            account_type in self.payable_account_type_list:
          return True

    return False