## $Id: utils.py 16524 2021-07-01 08:31:33Z henrik $
##
## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
## 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 time import time
from zope.component import createObject, getUtility
from waeup.kofa.fees import FeeTable
from waeup.kofa.interfaces import (IKofaUtils,
    ADMITTED, CLEARED, RETURNING, PAID, REGISTERED, VALIDATED)
from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
from kofacustom.coewarri.interfaces import MessageFactory as _
from kofacustom.coewarri.interswitch.browser import GATEWAY_AMT


def local_nonlocal(student):
    lga = getattr(student, 'lga')
    if lga and lga.startswith('delta'):
        return 'local'
    else:
        return 'non-local'

PAYMENT_LEVELS = (100, 110, 200, 210, 300, 310, 400, 410, 500, 999)

FEES_PARAMS = (
        ('local', 'non-local'),
        ('nce_ft', 'nce_pt', 'ug_ft', 'nce_we_pt'),
        PAYMENT_LEVELS
    )

FEES_VALUES = (
     ( # 100      110      200      210      300      310      400      410     500  999
       (43200.0, 43200.0, 43200.0, 43200.0, 37200.0, 37200.0, 0.0, 0.0, 0.0, 0.0), # nce_ft
       (55200.0, 55200.0, 49200.0, 49200.0, 53200.0, 53200.0, 49200.0, 49200.0, 0.0, 0.0), # nce_pt
       (75700.0, 75700.0, 64700.0, 64700.0, 68700.0, 68700.0, 62700.0, 62700.0, 0.0, 0.0), # ug_ft
       (33200.0, 33200.0, 28000.0, 28000.0, 32000.0, 32000.0, 28000.0, 28000.0, 0.0, 0.0), # nce_we_pt
     ), # local
     ( #
       (55800.0, 55800.0, 55700.0, 55700.0, 49700.0, 49700.0, 0.0, 0.0, 0.0, 0.0), # nce_ft
       (55200.0, 55200.0, 49200.0, 49200.0, 53200.0, 53200.0, 49200.0, 49200.0, 0.0, 0.0), # nce_pt
       (85700.0, 85700.0, 74700.0, 74700.0, 78700.0, 78700.0, 72700.0, 72700.0, 0.0, 0.0), # ug_ft
       (33200.0, 33200.0, 28000.0, 28000.0, 32000.0, 32000.0, 28000.0, 28000.0, 0.0, 0.0), # nce_we_pt
     ), # non-local
   )

SCHOOL_FEES = FeeTable(FEES_PARAMS, FEES_VALUES)

class CustomStudentsUtils(NigeriaStudentsUtils):
    """A collection of customized methods.

    """

    def warnCreditsOOR(self, studylevel, course=None):
        """Return message if credits are out of range. 
        """
        if studylevel.student.current_mode == 'nce_ft':
            limit = 56
        elif studylevel.student.current_mode == 'ug_ft':
            limit = 48
            if studylevel.level == 400:
                limit = 51
        else:
            limit = 50
        if course and studylevel.total_credits + course.credits > limit:
            return _('Maximum credits exceeded.')
        elif studylevel.total_credits > limit:
            return _('Maximum credits exceeded.')
        return

    def _isPaymentDisabled(self, p_session, category, student):
        academic_session = self._getSessionConfiguration(p_session)
        if category.startswith('schoolfee'):
            if 'sf_all' in academic_session.payment_disabled:
                return True
            if student.current_mode == 'ug_ft' and \
                'degree' in academic_session.payment_disabled:
                return True
        return False

    def _lsfp_penalty_payment(self, student, p_session):
        if p_session >= 2021:
            return False
        #if p_session == 2020 and student.current_mode not in ('nce_ft', 'nce_pt'):
        #    return False
        if student.current_mode not in ('ug_ft','de_ft', 'nce_ft', 'nce_pt'):
            return False
        if len(student['payments']):
            for ticket in student['payments'].values():
                if ticket.p_state == 'paid' and \
                    ticket.p_category == 'lsfp_penalty' and \
                    ticket.p_session == p_session:
                    return False
        return True

    def setPaymentDetails(self, category, student,
            previous_session=None, previous_level=None, combi=[]):
        """Create a payment ticket and set the payment data of a
        student for the payment category specified.
        """
        p_item = u''
        amount = 0.0
        if previous_session:
            if previous_session < student['studycourse'].entry_session:
                return _('The previous session must not fall below '
                         'your entry session.'), None
            if category == 'schoolfee':
                # School fee is always paid for the following session
                if previous_session > student['studycourse'].current_session:
                    return _('This is not a previous session.'), None
            else:
                if previous_session > student['studycourse'].current_session - 1:
                    return _('This is not a previous session.'), None
            p_session = previous_session
            p_level = previous_level
            p_current = False
        else:
            p_session = student['studycourse'].current_session
            p_level = student['studycourse'].current_level
            p_current = True
        academic_session = self._getSessionConfiguration(p_session)
        if academic_session == None:
            return _(u'Session configuration object is not available.'), None
        # Determine fee.
        if category.startswith('schoolfee'):
            try:
                certificate = student['studycourse'].certificate
                p_item = certificate.code
            except (AttributeError, TypeError):
                return _('Study course data are incomplete.'), None
            if student.state == RETURNING:
                # Override p_session and p_level
                p_session, p_level = self.getReturningData(student)
                academic_session = self._getSessionConfiguration(p_session)
                if academic_session == None:
                    return _(u'Session configuration object '
                              'is not available.'), None
            penalty_set = getattr(academic_session, 'lsfp_penalty_fee')
            if penalty_set and self._lsfp_penalty_payment(student, p_session):
                return _('You have to pay late school fee payment penalty first.'), None
            if p_level in PAYMENT_LEVELS:
                amount = SCHOOL_FEES.get_fee(
                    (
                     local_nonlocal(student),
                     student.current_mode,
                     p_level)
                    )
                if student.entry_mode == 'de_ft' and p_level == 200:
                    if student['studycourse'].entry_session >= 2020:
                        amount += 15000
                    elif student['studycourse'].entry_session >= 2019:
                        amount += 10500
            if amount and category in ('schoolfee_1', 'schoolfee_2'):
                amount /= 2
            if amount:
                amount += GATEWAY_AMT
        elif category == 'clearance':
            try:
                p_item = student['studycourse'].certificate.code
            except (AttributeError, TypeError):
                return _('Study course data are incomplete.'), None
            if student.entry_mode in ('nce_we_pt', 'nce_pt'):
                amount = academic_session.clearance_fee_3
            elif student.entry_mode in ('ug_ft', 'de_ft'):
                amount = academic_session.clearance_fee_2
            else:
                amount = academic_session.clearance_fee_1
            if local_nonlocal(student) == 'non-local'  \
                and student.entry_mode not in ('nce_we_pt', 'nce_pt'):
                amount += 5000.0
        elif category == 'bed_allocation':
            p_item = self.getAccommodationDetails(student)['bt']
            amount = academic_session.booking_fee
        elif category == 'hostel_maintenance':
            amount = 0.0
            bedticket = student['accommodation'].get(
                str(student.current_session), None)
            if bedticket is not None and bedticket.bed is not None:
                p_item = bedticket.bed_coordinates
                if bedticket.bed.__parent__.maint_fee > 0:
                    amount = bedticket.bed.__parent__.maint_fee
                else:
                    # fallback
                    amount = academic_session.maint_fee
            else:
                return _(u'No bed allocated.'), None
        else:
            fee_name = category + '_fee'
            amount = getattr(academic_session, fee_name, 0.0)
        if category == 'lsfp_penalty' and student.state == RETURNING:
            # Override p_session and p_level
            p_session, p_level = self.getReturningData(student)
        if amount in (0.0, None):
            return _('Amount could not be determined.'), None
        if self.samePaymentMade(student, category, p_item, p_session):
            return _('This type of payment has already been made.'), None
        if self._isPaymentDisabled(p_session, category, student):
            return _('This category of payments has been disabled.'), None
        payment = createObject(u'waeup.StudentOnlinePayment')
        timestamp = ("%d" % int(time()*10000))[1:]
        payment.p_id = "p%s" % timestamp
        payment.p_category = category
        payment.p_item = p_item
        payment.p_session = p_session
        payment.p_level = p_level
        payment.p_current = p_current
        payment.amount_auth = amount
        return None, payment

    # prefix
    STUDENT_ID_PREFIX = u'R'

    PORTRAIT_CHANGE_STATES = ()