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

import time
from datetime import datetime
from dateutil.relativedelta import relativedelta
from calendar import isleap

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

DATETIME_FORMAT = "%Y-%m-%d"

class hr_contract(osv.osv):
    """
    Employee contract allows to add different values in fields.
    Fields are used in salary rule computation.
    """

    _inherit = 'hr.contract'
    _description = 'HR Contract'

    _columns = {
        'tds': fields.float('TDS', digits_compute=dp.get_precision('Payroll'), help="Amount for Tax Deduction at Source"),
        'driver_salay': fields.boolean('Driver Salary', help="Check this box if you provide allowance for driver"),
        'medical_insurance': fields.float('Medical Insurance', digits_compute=dp.get_precision('Payroll'), help="Deduction towards company provided medical insurance"),
        'voluntary_provident_fund': fields.float('Voluntary Provident Fund (%)', digits_compute=dp.get_precision('Payroll'), help="VPF is a safe option wherein you can contribute more than the PF ceiling of 12% that has been mandated by the government and VPF computed as percentage(%)"),
        'house_rent_allowance_metro_nonmetro': fields.float('House Rent Allowance (%)', digits_compute=dp.get_precision('Payroll'), help="HRA is an allowance given by the employer to the employee for taking care of his rental or accommodation expenses for metro city it is 50% and for non metro 40%. \nHRA computed as percentage(%)"),
        'supplementary_allowance': fields.float('Supplementary Allowance', digits_compute=dp.get_precision('Payroll')),
    }


class payroll_advice(osv.osv):
    '''
    Bank Advice
    '''
    _name = 'hr.payroll.advice'
    _description = 'Bank Advice'
    _columns = {
        'name':fields.char('Name', size=32, readonly=True, required=True, states={'draft': [('readonly', False)]},),
        'note': fields.text('Description'),
        'date': fields.date('Date', readonly=True, required=True, states={'draft': [('readonly', False)]}, help="Advice Date is used to search Payslips"),
        'state':fields.selection([
            ('draft', 'Draft'),
            ('confirm', 'Confirmed'),
            ('cancel', 'Cancelled'),
        ], 'Status', select=True, readonly=True),
        'number':fields.char('Reference', size=16, readonly=True),
        'line_ids':fields.one2many('hr.payroll.advice.line', 'advice_id', 'Employee Salary', states={'draft': [('readonly', False)]}, readonly=True),
        'chaque_nos':fields.char('Cheque Numbers', size=256),
        'neft': fields.boolean('NEFT Transaction', help="Check this box if your company use online transfer for salary"),
        'company_id':fields.many2one('res.company', 'Company', required=True, readonly=True, states={'draft': [('readonly', False)]}),
        'bank_id':fields.many2one('res.bank', 'Bank', readonly=True, states={'draft': [('readonly', False)]}, help="Select the Bank from which the salary is going to be paid"),
        'batch_id': fields.many2one('hr.payslip.run', 'Batch', readonly=True)
    }

    _defaults = {
        'date': lambda * a: time.strftime('%Y-%m-%d'),
        'state': lambda * a: 'draft',
        'company_id': lambda self, cr, uid, context: \
                self.pool.get('res.users').browse(cr, uid, uid,
                    context=context).company_id.id,
        'note': "Please make the payroll transfer from above account number to the below mentioned account numbers towards employee salaries:"
    }

    def compute_advice(self, cr, uid, ids, context=None):
        """
        Advice - Create Advice lines in Payment Advice and
        compute Advice lines.
        @param cr: the current row, from the database cursor,
        @param uid: the current user’s ID for security checks,
        @param ids: List of Advice’s IDs
        @return: Advice lines
        @param context: A standard dictionary for contextual values
        """
        payslip_pool = self.pool.get('hr.payslip')
        advice_line_pool = self.pool.get('hr.payroll.advice.line')
        payslip_line_pool = self.pool.get('hr.payslip.line')

        for advice in self.browse(cr, uid, ids, context=context):
            old_line_ids = advice_line_pool.search(cr, uid, [('advice_id', '=', advice.id)], context=context)
            if old_line_ids:
                advice_line_pool.unlink(cr, uid, old_line_ids, context=context)
            slip_ids = payslip_pool.search(cr, uid, [('date_from', '<=', advice.date), ('date_to', '>=', advice.date), ('state', '=', 'done')], context=context)
            for slip in payslip_pool.browse(cr, uid, slip_ids, context=context):
                if not slip.employee_id.bank_account_id and not slip.employee_id.bank_account_id.acc_number:
                    raise osv.except_osv(_('Error!'), _('Please define bank account for the %s employee') % (slip.employee_id.name))
                line_ids = payslip_line_pool.search(cr, uid, [ ('slip_id', '=', slip.id), ('code', '=', 'NET')], context=context)
                if line_ids:
                    line = payslip_line_pool.browse(cr, uid, line_ids, context=context)[0]
                    advice_line = {
                            'advice_id': advice.id,
                            'name': slip.employee_id.bank_account_id.acc_number,
                            'employee_id': slip.employee_id.id,
                            'bysal': line.total
                            }
                    advice_line_pool.create(cr, uid, advice_line, context=context)
                payslip_pool.write(cr, uid, slip_ids, {'advice_id': advice.id}, context=context)
        return True

    def confirm_sheet(self, cr, uid, ids, context=None):
        """
        confirm Advice - confirmed Advice after computing Advice Lines..
        @param cr: the current row, from the database cursor,
        @param uid: the current user’s ID for security checks,
        @param ids: List of confirm Advice’s IDs
        @return: confirmed Advice lines and set sequence of Advice.
        @param context: A standard dictionary for contextual values
        """
        seq_obj = self.pool.get('ir.sequence')
        for advice in self.browse(cr, uid, ids, context=context):
            if not advice.line_ids:
                raise osv.except_osv(_('Error!'), _('You can not confirm Payment advice without advice lines.'))
            advice_date = datetime.strptime(advice.date, DATETIME_FORMAT)
            advice_year = advice_date.strftime('%m') + '-' + advice_date.strftime('%Y')
            number = seq_obj.get(cr, uid, 'payment.advice')
            sequence_num = 'PAY' + '/' + advice_year + '/' + number
            self.write(cr, uid, [advice.id], {'number': sequence_num, 'state': 'confirm'}, context=context)
        return True

    def set_to_draft(self, cr, uid, ids, context=None):
        """Resets Advice as draft.
        """
        return self.write(cr, uid, ids, {'state':'draft'}, context=context)

    def cancel_sheet(self, cr, uid, ids, context=None):
        """Marks Advice as cancelled.
        """
        return self.write(cr, uid, ids, {'state':'cancel'}, context=context)

    def onchange_company_id(self, cr, uid, ids, company_id=False, context=None):
        res = {}
        if company_id:
            company = self.pool.get('res.company').browse(cr, uid, [company_id], context=context)[0]
            if company.partner_id.bank_ids:
                res.update({'bank_id': company.partner_id.bank_ids[0].bank.id})
        return {
            'value':res
        }

class hr_payslip_run(osv.osv):

    _inherit = 'hr.payslip.run'
    _description = 'Payslip Batches'
    _columns = {
        'available_advice': fields.boolean('Made Payment Advice?', help="If this box is checked which means that Payment Advice exists for current batch", readonly=False),
    }
    def copy(self, cr, uid, id, default={}, context=None):
        if not default:
            default = {}
        default.update({'available_advice': False})
        return super(hr_payslip_run, self).copy(cr, uid, id, default, context=context)    

    def draft_payslip_run(self, cr, uid, ids, context=None):
        res = super(hr_payslip_run, self).draft_payslip_run(cr, uid, ids, context=context)
        self.write(cr, uid, ids, {'available_advice': False}, context=context)
        return res
    
    def create_advice(self, cr, uid, ids, context=None):
        payslip_pool = self.pool.get('hr.payslip')
        payslip_line_pool = self.pool.get('hr.payslip.line')
        advice_pool = self.pool.get('hr.payroll.advice')
        advice_line_pool = self.pool.get('hr.payroll.advice.line')
        users = self.pool.get('res.users').browse(cr, uid, [uid], context=context)
        for run in self.browse(cr, uid, ids, context=context):
            if run.available_advice:
                raise osv.except_osv(_('Error!'), _("Payment advice already exists for %s, 'Set to Draft' to create a new advice.") %(run.name))
            advice_data = {
                        'batch_id': run.id,
                        'company_id': users[0].company_id.id,
                        'name': run.name,
                        'date': run.date_end,
                        'bank_id': users[0].company_id.bank_ids and users[0].company_id.bank_ids[0].id or False
                    }
            advice_id = advice_pool.create(cr, uid, advice_data, context=context)
            slip_ids = []
            for slip_id in run.slip_ids:
                # TODO is it necessary to interleave the calls ?
                payslip_pool.signal_hr_verify_sheet(cr, uid, [slip_id.id])
                payslip_pool.signal_process_sheet(cr, uid, [slip_id.id])
                slip_ids.append(slip_id.id)

            for slip in payslip_pool.browse(cr, uid, slip_ids, context=context):
                if not slip.employee_id.bank_account_id or not slip.employee_id.bank_account_id.acc_number:
                    raise osv.except_osv(_('Error!'), _('Please define bank account for the %s employee') % (slip.employee_id.name))
                line_ids = payslip_line_pool.search(cr, uid, [('slip_id', '=', slip.id), ('code', '=', 'NET')], context=context)
                if line_ids:
                    line = payslip_line_pool.browse(cr, uid, line_ids, context=context)[0]
                    advice_line = {
                            'advice_id': advice_id,
                            'name': slip.employee_id.bank_account_id.acc_number,
                            'employee_id': slip.employee_id.id,
                            'bysal': line.total
                    }
                    advice_line_pool.create(cr, uid, advice_line, context=context)
        return self.write(cr, uid, ids, {'available_advice' : True})


class payroll_advice_line(osv.osv):
    '''
    Bank Advice Lines
    '''
    def onchange_employee_id(self, cr, uid, ids, employee_id=False, context=None):
        res = {}
        hr_obj = self.pool.get('hr.employee')
        if not employee_id:
            return {'value': res}
        employee = hr_obj.browse(cr, uid, [employee_id], context=context)[0]
        res.update({'name': employee.bank_account_id.acc_number , 'ifsc_code': employee.bank_account_id.bank_bic or ''})
        return {'value': res}

    _name = 'hr.payroll.advice.line'
    _description = 'Bank Advice Lines'
    _columns = {
        'advice_id': fields.many2one('hr.payroll.advice', 'Bank Advice'),
        'name': fields.char('Bank Account No.', size=25, required=True),
        'ifsc_code': fields.char('IFSC Code', size=16),
        'employee_id': fields.many2one('hr.employee', 'Employee', required=True),
        'bysal': fields.float('By Salary', digits_compute=dp.get_precision('Payroll')),
        'debit_credit': fields.char('C/D', size=3, required=False),
        'company_id': fields.related('advice_id', 'company_id', type='many2one', required=False, relation='res.company', string='Company', store=True),
        'ifsc': fields.related('advice_id', 'neft', type='boolean', string='IFSC'),
    }
    _defaults = {
        'debit_credit': 'C',
    }


class hr_payslip(osv.osv):
    '''
    Employee Pay Slip
    '''
    _inherit = 'hr.payslip'
    _description = 'Pay Slips'
    _columns = {
        'advice_id': fields.many2one('hr.payroll.advice', 'Bank Advice')
    }

    def copy(self, cr, uid, id, default={}, context=None):
        if not default:
            default = {}
        default.update({'advice_id' : False})
        return super(hr_payslip, self).copy(cr, uid, id, default, context=context)


class res_company(osv.osv):

    _inherit = 'res.company'
    _columns = {
        'dearness_allowance': fields.boolean('Dearness Allowance', help="Check this box if your company provide Dearness Allowance to employee")
    }
    _defaults = {
        'dearness_allowance': True,
    }


# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
