← Back to team overview

savoirfairelinux-openerp team mailing list archive

lp:~savoirfairelinux-openerp/contract-management/isp_contract_split1 into lp:contract-management

 

Joao Alfredo Gama Batista has proposed merging lp:~savoirfairelinux-openerp/contract-management/isp_contract_split1 into lp:contract-management.

Requested reviews:
  Contract Management Core Editors (contract-management-core-editors)

For more details, see:
https://code.launchpad.net/~savoirfairelinux-openerp/contract-management/isp_contract_split1/+merge/185297

This 3 modules works together to provide analytic line generation and invoicing to service based contracts. Those modules were made with ISP companies in mind but they can be used by other service companies too.

The contract_isp module provides a new contract type (service contract) and the ability to generate analytic lines from services.

The contract_isp_invoice extends the base module with invoicing capabilities.

The contract_isp_automatic_invoicing provides a cron to automatically invoice recurrent services contracts on monthly basis.
-- 
https://code.launchpad.net/~savoirfairelinux-openerp/contract-management/isp_contract_split1/+merge/185297
Your team Savoir-faire Linux' OpenERP is subscribed to branch lp:~savoirfairelinux-openerp/contract-management/isp_contract_split1.
=== added directory 'contract_isp'
=== added file 'contract_isp/__init__.py'
--- contract_isp/__init__.py	1970-01-01 00:00:00 +0000
+++ contract_isp/__init__.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<www.savoirfairelinux.com>).
+#
+#    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 contract
+import report
+import wizard

=== added file 'contract_isp/__openerp__.py'
--- contract_isp/__openerp__.py	1970-01-01 00:00:00 +0000
+++ contract_isp/__openerp__.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<www.savoirfairelinux.com>).
+#
+#    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/>.
+#
+##############################################################################
+
+{
+    'name': 'ISP Contract',
+    'version': '1.0',
+    'category': 'Contract Management',
+    'description': """
+Manage service based contracts
+==============================
+
+This module adds a service based contract category were you can manage diferent services and service types that are included in the contract.
+
+Features:
+---------
+
+* Differents types of services (recurrent, exceptions, one time only),
+* Pro-rata logic,
+* Service activation wizard.
+""",
+    'author': 'Savoir-faire Linux Inc',
+    'website': 'www.savoirfairelinux.com',
+    'license': 'AGPL-3',
+    'depends': ['account_analytic_analysis'],
+    'data': ['security/contract_isp_security.xml',
+             'security/ir.model.access.csv',
+             'wizard/activate_contract_service.xml',
+             'contract_isp_view.xml',
+             'contract_isp_data.xml',
+             'contract_isp_workflow.xml'],
+    'demo': ['contract_isp_demo.xml'],
+    'active': False,
+    'installable': True,
+}

=== added file 'contract_isp/contract.py'
--- contract_isp/contract.py	1970-01-01 00:00:00 +0000
+++ contract_isp/contract.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,369 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
+#
+#    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 logging
+import calendar
+import datetime
+from openerp.osv import orm, fields
+from openerp.report import report_sxw
+from openerp.tools import convert
+
+
+def add_months(sourcedate, months):
+    month = sourcedate.month - 1 + months
+    year = sourcedate.year + month / 12
+    month = month % 12 + 1
+    day = min(sourcedate.day, calendar.monthrange(year, month)[1])
+    return datetime.date(year, month, day)
+
+
+def date_interval(start_date, month_end=True, date_format='%m/%d/%Y'):
+    if month_end:
+        end_date = datetime.date(start_date.year,
+                                 start_date.month,
+                                 calendar.monthrange(start_date.year,
+                                                     start_date.month)[1])
+    else:
+        end_date = add_months(start_date, 1) - datetime.timedelta(days=1)
+
+    interval = '(%s - %s)' % (start_date.strftime(date_format),
+                              end_date.strftime(date_format))
+
+    return interval
+
+
+class res_company(orm.Model):
+    _inherit = 'res.company'
+
+    def _days(self, cr, uid, context=None):
+        return tuple([(str(x), str(x)) for x in range(1, 29)])
+
+    _columns = {
+        'parent_account_id': fields.many2one('account.analytic.account',
+                                             'Parent Analytic Account'),
+        'cutoff_day': fields.selection(_days, 'Cutoff day')
+    }
+
+
+class res_partner(orm.Model):
+    _inherit = 'res.partner'
+
+    _columns = {
+        'partner_analytic_account_id': fields.many2one('account.analytic.account',
+                                                       'Partner Analytic Account')
+    }
+
+    def create(self, cr, uid, values, context=None):
+        account_analytic_account = self.pool.get('account.analytic.account')
+        company_obj = self.pool.get('res.company')
+        company_id = company_obj._company_default_get(cr, uid, context)
+        company = company_obj.browse(cr, uid, company_id, context)
+
+        ret = super(res_partner, self).create(cr, uid, values, context)
+
+        parent_id = company.parent_account_id and company.parent_account_id.id
+        account = {
+            'name': values['name'],
+            'parent_id': parent_id,
+            'type': 'view',
+            'partner_id': ret,
+            'user_id': uid
+        }
+
+        account_id = account_analytic_account.create(cr, uid, account, context)
+        self.write(cr, uid, ret,
+                   {'partner_analytic_account_id': account_id},
+                   context)
+
+        return ret
+
+
+class product_product(orm.Model):
+    _inherit = 'product.product'
+
+    _columns = {
+        'analytic_line_type': fields.selection((('r', 'Recurrent'),
+                                                ('x', 'Exception'),
+                                                ('o', 'One time')),
+                                               'Type in contract'),
+        'require_activation': fields.boolean('Require activation')
+    }
+
+
+class contract_service(orm.Model):
+    _name = 'contract.service'
+
+    def _get_product_price(self, cr, uid, ids, field_name, arg, context=None):
+        product_obj = self.pool.get('product.product')
+        ret = {}
+        for line in self.browse(cr, uid, ids, context):
+            if line.product_id:
+                ret[line.id] = line.product_id.list_price
+            else:
+                ret[line.id] = None
+
+        return ret
+
+    _columns = {
+        'activation_date': fields.datetime('Activation date'),
+        'duration': fields.integer('Duration'),
+        'product_id': fields.many2one('product.product',
+                                      'Product',
+                                      required=True),
+        'analytic_line_type': fields.selection((('r', 'Recurrent'),
+                                                ('x', 'Exception'),
+                                                ('o', 'One time')),
+                                               'Type'),
+        'require_activation': fields.boolean('Require activation'),
+        'account_id': fields.many2one('account.analytic.account', 'Contract'),
+        'price': fields.function(_get_product_price, type='float',
+                                 string='Price'),
+        'activation_line_generated': fields.boolean('Activation Line Generated?'),
+        'state': fields.selection((('draft', 'Waiting for activating'),
+                                   ('active', 'Active'),
+                                   ('inactive', 'Inactive')),
+                                  'State')
+    }
+
+    _defaults = {
+        'state': 'draft',
+        'activation_line_generated': False
+    }
+
+    def on_change_product_id(self, cr, uid, ids, product_id):
+        ret = {'value': {'analytic_line_type': None}}
+        product = self.pool.get('product.product').browse(
+            cr, uid,
+            [product_id],
+            None)[0]
+
+        if product_id:
+            ret['value']['analytic_line_type'] = product.analytic_line_type
+            ret['value']['require_activation'] = product.require_activation
+            ret['value']['price'] = product.list_price
+            if product.analytic_line_type in ('r', 'o'):
+                ret['value']['duration'] = 0
+            else:
+                ret['value']['duration'] = 1
+
+        return ret
+
+    def create_analytic_line(self, cr, uid, ids,
+                             mode='manual',
+                             date=None,
+                             context=None):
+
+        if not date:
+            date = datetime.date.today()
+
+        if type(ids) is int:
+            ids = [ids]
+
+        ret = []
+        record = {}
+
+        account_analytic_line_obj = self.pool.get('account.analytic.line')
+        for line in self.browse(cr, uid, ids, context):
+            account_id = line.account_id.id
+            partner_lang = line.account_id.partner_id.lang
+            res_lang_obj = self.pool.get('res.lang')
+            query = [
+                ('code', '=', partner_lang),
+                ('active', '=', True)
+            ]
+            lang_id = res_lang_obj.search(cr, uid, query, context=context)
+            if lang_id:
+                date_format = res_lang_obj.browse(cr, uid,
+                                                  lang_id[0],
+                                                  context=context).date_format
+
+            else:
+                date_format = '%Y/%m/%d'
+
+            if line.analytic_line_type == 'r':
+                if mode == 'prorata':
+                    activation_date = date
+
+                    month_days = calendar.monthrange(activation_date.year,
+                                                     activation_date.month)[1]
+
+                    used_days = month_days - activation_date.day
+                    ptx = (100 * used_days / month_days) / 100.0
+
+                    amount = line.product_id.list_price * ptx
+                    interval = date_interval(add_months(date, 1),
+                                             True,
+                                             date_format)
+                elif mode == 'cron':
+                    amount = line.product_id.list_price
+                    next_month = add_months(date, 1)
+                    next_month = datetime.date(
+                        next_month.year,
+                        next_month.month,
+                        1)
+                    interval = date_interval(next_month,
+                                             False,
+                                             date_format)
+                    date = next_month
+                elif mode == 'manual':
+                    amount = line.product_id.list_price
+                    interval = date_interval(date, False, date_format)
+            else:
+                interval = ''
+                amount = line.product_id.list_price
+
+            general_account_id = line.product_id.property_account_expense.id \
+                or line.product_id.categ_id.property_account_expense_categ.id
+
+            record = {
+                'name': ' '.join([line.product_id.name, interval]),
+                'amount': amount * (-1),
+                'account_id': line.account_id.id,
+                'user_id': uid,
+                'general_account_id': general_account_id,
+                'product_id': line.product_id.id,
+                'contract_service_id': line.id,
+                'to_invoice': 1,
+                'unit_amount': 1,
+                'is_prorata': mode == 'prorata',
+                'date': date.strftime('%Y-%m-%d')
+            }
+
+            if line.analytic_line_type == 'x':
+                line.write({'duration': line.duration - 1})
+                if line.duration <= 0:
+                    line.unlink()
+                    record['contract_service_id'] = False
+
+            ret.append(account_analytic_line_obj.create(cr, uid, record,
+                                                        context))
+        return ret
+
+    def create(self, cr, uid, values, context=None):
+        if not values["require_activation"]:
+            values["state"] = 'active'
+            values["activation_date"] = fields.datetime.now()
+        ret = super(contract_service, self).create(cr, uid, values, context)
+
+        return ret
+
+    def action_desactivate(self, cr, uid, ids, context):
+        return self.write(cr, uid, ids,
+                          {'state': 'inactive', 'activation_date': None},
+                          context)
+
+
+class account_analytic_account(orm.Model):
+    _name = "account.analytic.account"
+    _inherit = "account.analytic.account"
+
+    _columns = {
+        'contract_service_ids': fields.one2many('contract.service',
+                                                'account_id',
+                                                'Services'),
+        'use_contract_services': fields.boolean('Contract services'),
+        'state': fields.selection([('template', 'Template'),
+                                   ('draft', 'New'),
+                                   ('open', 'In Progress'),
+                                   ('pending', 'Suspended'),
+                                   ('close', 'Closed'),
+                                   ('cancelled', 'Cancelled')],
+                                  'Status', required=True,
+                                  track_visibility='onchange'),
+    }
+
+    _defaults = {
+        'use_contract_services': False
+    }
+
+    def create_analytic_lines(self, cr, uid, ids, context=None):
+        mode = 'manual'
+        if context and context.get('create_analytic_line_mode', False):
+            mode = context.get('create_analytic_line_mode')
+
+        account_analytic_line_obj = self.pool.get('account.analytic.line')
+        contract_service_obj = self.pool.get('contract.service')
+        query = [
+            ('account_id', 'in', ids),
+            ('state', '=', 'active'),
+            ('analytic_line_type', 'in', ('r', 'x'))
+        ]
+        contract_service_ids = contract_service_obj.search(cr, uid,
+                                                           query,
+                                                           order='account_id',
+                                                           context=context)
+
+        if contract_service_ids:
+            contract_service_obj.create_analytic_line(cr, uid,
+                                                      contract_service_ids,
+                                                      mode=mode,
+                                                      context=context)
+
+        return {}
+
+    def create(self, cr, uid, values, context=None):
+        if values['type'] == 'contract' and values['use_contract_services']:
+            values['name'] = values['code']
+            partner_obj = self.pool.get('res.partner')
+            values['parent_id'] = partner_obj.read(
+                cr, uid, values['partner_id'],
+                fields=['partner_analytic_account_id'],
+                context=context)['partner_analytic_account_id'][0]
+
+        ret = super(account_analytic_account, self).create(cr, uid, values,
+                                                           context)
+
+        return ret
+
+    def on_change_partner_id(self, cr, uid, ids,
+                             partner_id, name,
+                             code=None, context=None):
+        res = {}
+        if partner_id:
+            partner = self.pool.get('res.partner').browse(cr, uid, partner_id,
+                                                          context=context)
+            if partner.user_id:
+                res['manager_id'] = partner.user_id.id
+            if not name:
+                if code:
+                    res['name'] = code
+                else:
+                    res['name'] = _('Contract: ') + partner.name
+            # Use pricelist from customer
+            res['pricelist_id'] = partner.property_product_pricelist.id
+
+        return {'value': res}
+
+
+class account_analytic_line(orm.Model):
+    _name = "account.analytic.line"
+    _inherit = "account.analytic.line"
+
+    _columns = {
+        'contract_service_id': fields.many2one('contract.service',
+                                               'Service'),
+        'is_prorata': fields.boolean('Prorata')
+    }
+
+    _defaults = {
+        'is_prorata': False
+    }

=== added file 'contract_isp/contract_isp_data.xml'
--- contract_isp/contract_isp_data.xml	1970-01-01 00:00:00 +0000
+++ contract_isp/contract_isp_data.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data noupdate="1">
+        <record id="analytic_journal_data" model="account.analytic.journal">
+            <field name="code">DT</field>
+            <field name="name">Data Use</field>
+            <field name="type">general</field>
+        </record>
+        <record id="analytic_journal_tel" model="account.analytic.journal">
+            <field name="code">TL</field>
+            <field name="name">Voice Use</field>
+            <field name="type">general</field>
+        </record>
+        <record id="analytic_journal_recurrent" model="account.analytic.journal">
+            <field name="code">RC</field>
+            <field name="name">Recurrent Service</field>
+            <field name="type">general</field>
+        </record>
+    </data>
+</openerp>
\ No newline at end of file

=== added file 'contract_isp/contract_isp_view.xml'
--- contract_isp/contract_isp_view.xml	1970-01-01 00:00:00 +0000
+++ contract_isp/contract_isp_view.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+	<record id="view_company_contract_isp_form" model="ir.ui.view">
+            <field name="name">contract.isp.res.company.form</field>
+            <field name="model">res.company</field>
+	    <field name="inherit_id" ref="base.view_company_form"/>
+            <field name="arch" type="xml">
+		<xpath expr="//page[@string='Configuration']" position="after">
+		    <page string="ISP Contract Management">
+			<group>
+			    <group>
+				<field name="parent_account_id" />
+			    </group>
+
+			    <group>
+				<field name="cutoff_day" />
+			    </group>
+			</group>
+		    </page>
+		</xpath>
+	    </field>
+	</record>
+
+	<record id="view_contract_isp_form" model="ir.ui.view">
+            <field name="name">contract.isp.form</field>
+            <field name="model">account.analytic.account</field>
+	    <field name="inherit_id" ref="account_analytic_analysis.account_analytic_account_form_form"/>
+            <field name="arch" type="xml">
+                <xpath expr='//div[@name="project"]' position='inside'>
+                    <field name="use_contract_services" />
+                    <label for="use_contract_services" />
+                </xpath>
+
+		<xpath expr="//separator[@string='Invoicing']" position="before">
+		    <separator 
+			name="services"
+			string="Services"
+			attrs="{'invisible': [('use_contract_services', '=', False)]}"/>
+		    <field 
+			name="contract_service_ids"
+			mode="tree"
+			select="1"
+			options="{'always_reload': True, 'reload_on_button': True}"
+			attrs="{'invisible': [('use_contract_services', '=', False)]}">
+			<tree editable="botton" colors="green:state=='active'" >
+			    <field name="account_id" invisible="1"/>
+			    <field name="state" readonly="True" />
+			    <field name="activation_date"
+				   attrs="{'readonly': [('state', 'in', ('draft', 'active'))]}" />
+			    <field name="product_id"
+				   on_change="on_change_product_id(product_id)"
+				   domain="[('analytic_line_type', 'in', ('r', 'x', 'o'))]"
+				   attrs="{'readonly': [('state', '=', 'active')]}"/>
+			    <field name="price" readonly="1" sum="Total Price" />
+			    <field name="analytic_line_type" />
+			    <field name="require_activation" invisible="True" />
+			    <field 
+				name="duration"
+				attrs="{'readonly': [('state', 'in', ('draft', 'active')),
+				                     ('analytic_line_type', 'in', ('r', 'o'))],
+                                        'required': [('analytic_line_type', '=', 'x')]}" />
+			    <field name="account_id" invisible="True" />
+			    <button
+				name="%(action_view_contract_service_activate)d"
+				string="Activate"
+				type="action"
+				states="draft,inactive"
+				icon="gtk-yes"
+				groups="contract_isp.group_isp_agent"/>
+			    <button
+				name="action_desactivate"
+				string="Desactivate"
+				type="object"
+				states="active"
+				icon="gtk-no"
+				groups="contract_isp.group_isp_agent"/>
+			</tree>
+		    </field>
+		</xpath>
+	    </field>
+	</record>
+
+	<record id="view_contract_service_form" model="ir.ui.view">
+            <field name="name">contract.service.form</field>
+            <field name="model">contract.service</field>
+            <field name="arch" type="xml">
+		<form string="Contract Services" version="7.0">
+		    <sheet string="Analytic Account">
+			<field name="activation_date" />
+			<field name="analytic_line_type" />
+			<field name="duration" />
+			<field name="product_id" />
+		    </sheet>
+		</form>
+	    </field>
+	</record>
+
+	<record id="view_contract_service_tree" model="ir.ui.view">
+            <field name="name">contract.service.tree</field>
+            <field name="model">contract.service</field>
+            <field name="arch" type="xml">
+		<tree editable="top" string="Contract Services">
+		    <field name="account_id" invisible="1"/>
+		    <field name="state" readonly="True" />
+		    <field name="activation_date"
+			   attrs="{'readonly': [('state', 'in', ('draft', 'active'))]}" />
+		    <field name="product_id"
+			   on_change="on_change_product_id(product_id)"
+			   domain="[('analytic_line_type', 'in', ('r', 'x', 'o'))]" />
+		    <field name="analytic_line_type" />
+		    <field 
+			name="duration"
+			attrs="{'readonly': [('state', 'in', ('draft', 'active')), ('analytic_line_type', 'in', ('r', 'o'))]}" />
+		    <field name="account_id" invisible="True" />
+		    <button
+			name="%(action_view_contract_service_activate)d"
+			string="Activate"
+			type="action"
+			icon="gtk-yes"
+			states="draft"
+			groups="contract_isp.group_isp_agent" />
+		    <button
+			name="action_desactivate"
+			string="Desactivate"
+			icon="gtk-no"
+			states="active"
+			type="object"
+			groups="contract_isp.group_isp_agent" />
+		</tree>
+	    </field>
+	</record>
+
+	<record id="view_contract_isp__product_form" model="ir.ui.view">
+            <field name="name">contract.isp.product.form</field>
+            <field name="model">product.product</field>
+	    <field name="inherit_id" ref="product.product_normal_form_view"/>
+            <field name="arch" type="xml">
+		<field name="list_price" position="after">
+		    <field name="analytic_line_type" />
+		    <field name="require_activation" />
+		</field>
+	    </field>
+	</record>
+
+        <record id="contract_isp_form_suspend" model="ir.ui.view">
+            <field name="name">contract.isp.form.suspend</field>
+            <field name="model">account.analytic.account</field>
+            <field name="inherit_id" ref="hr_timesheet_invoice.account_analytic_account_form_form"/>
+            <field name="arch" type="xml">
+                <xpath expr="//header/button[@name='set_pending']" position='attributes'>
+		    <attribute name="string">Suspend</attribute>
+		</xpath>
+	    </field>
+	</record>
+
+
+        <act_window
+            id="action_contract_service_manage"
+            name="Services"
+            res_model="contract.service"
+            src_model="account.analytic.account"
+            view_type="tree"
+            view_mode="tree" />
+
+
+    </data>
+</openerp>
+

=== added file 'contract_isp/contract_isp_workflow.xml'
--- contract_isp/contract_isp_workflow.xml	1970-01-01 00:00:00 +0000
+++ contract_isp/contract_isp_workflow.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+
+        <!-- Workflow definition -->
+
+        <record id="wkf_contract_service" model="workflow">
+            <field name="name">contract_isp_service.service</field>
+            <field name="osv">contract_isp_service.service</field>
+            <field name="on_create">True</field>
+        </record>
+
+        <record id="act_draft" model="workflow.activity">
+            <field name="wkf_id" ref="wkf_contract_service"/>
+            <field name="name">draft</field>
+            <field name="kind">function</field>
+	    <field name="flow_start">True</field>
+        </record>
+        <record id="act_active" model="workflow.activity">
+            <field name="wkf_id" ref="wkf_contract_service"/>
+            <field name="name">activate</field>
+            <field name="kind">function</field>
+            <field name="action">action_view_contract_service_activate</field>
+        </record>
+        <record id="act_inactive" model="workflow.activity">
+            <field name="wkf_id" ref="wkf_contract_service"/>
+            <field name="name">desactivate</field>
+            <field name="kind">function</field>
+            <field name="action">write({'state':'inactive'})</field>
+            <!-- <field name="flow_stop">True</field> -->
+        </record>
+        <record id="act_reactive" model="workflow.activity">
+            <field name="wkf_id" ref="wkf_contract_service"/>
+            <field name="name">reactivate</field>
+            <field name="kind">function</field>
+            <field name="action">write({'state':'active'})</field>
+            <!-- <field name="flow_stop">True</field> -->
+        </record>
+
+        <record id="t0" model="workflow.transition">
+            <field name="act_from" ref="act_draft"/>
+            <field name="act_to" ref="act_active"/>
+            <field name="signal">activate</field>
+            <field name="group_id" ref="contract_isp.group_isp_agent"/>
+        </record>
+        <record id="t1" model="workflow.transition">
+            <field name="act_from" ref="act_active"/>
+            <field name="act_to" ref="act_inactive"/>
+            <field name="signal">desactivate</field>
+            <field name="group_id" ref="contract_isp.group_isp_agent"/>
+        </record>
+        <record id="t2" model="workflow.transition">
+            <field name="act_from" ref="act_inactive"/>
+            <field name="act_to" ref="act_reactive"/>
+            <field name="signal">reactivate</field>
+            <field name="group_id" ref="contract_isp.group_isp_agent"/>
+        </record>
+
+    </data>
+</openerp>

=== added directory 'contract_isp/i18n'
=== added file 'contract_isp/i18n/contract_isp.pot'
--- contract_isp/i18n/contract_isp.pot	1970-01-01 00:00:00 +0000
+++ contract_isp/i18n/contract_isp.pot	2013-09-12 15:29:09 +0000
@@ -0,0 +1,251 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+#	* contract_isp
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-08-13 12:37+0000\n"
+"PO-Revision-Date: 2013-08-13 12:37+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: contract_isp
+#: field:account.analytic.line,contract_service_id:0
+#: field:contract.service.activate,service_id:0
+msgid "Service"
+msgstr ""
+
+#. module: contract_isp
+#: selection:contract.service,analytic_line_type:0
+#: selection:product.product,analytic_line_type:0
+msgid "Recurrent"
+msgstr ""
+
+#. module: contract_isp
+#: selection:contract.service,analytic_line_type:0
+#: selection:product.product,analytic_line_type:0
+msgid "Exception"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service,state:0
+msgid "State"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service,activation_date:0
+msgid "Activation date"
+msgstr ""
+
+#. module: contract_isp
+#: field:res.partner,account_analytic_account_ids:0
+msgid "Analytic Accounts/Contracts"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service,analytic_line_type:0
+msgid "Type"
+msgstr ""
+
+#. module: contract_isp
+#: model:res.groups,comment:contract_isp.group_isp_agent
+msgid "The user will be able to manage customers and contracts"
+msgstr ""
+
+#. module: contract_isp
+#: view:account.analytic.account:0
+msgid "Total Price"
+msgstr ""
+
+#. module: contract_isp
+#: field:account.analytic.account,use_contract_services:0
+msgid "Contract services"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service,product_id:0
+#: model:ir.model,name:contract_isp.model_product_product
+msgid "Product"
+msgstr ""
+
+#. module: contract_isp
+#: model:ir.model,name:contract_isp.model_account_analytic_line
+msgid "Analytic Line"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service,price:0
+msgid "Price"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service,require_activation:0
+#: field:product.product,require_activation:0
+msgid "Require activation"
+msgstr ""
+
+#. module: contract_isp
+#: field:product.product,analytic_line_type:0
+msgid "Type in contract"
+msgstr ""
+
+#. module: contract_isp
+#: selection:contract.service,state:0
+msgid "Inactive"
+msgstr ""
+
+#. module: contract_isp
+#: field:res.company,parent_account_id:0
+msgid "Parent Analytic Account"
+msgstr ""
+
+#. module: contract_isp
+#: selection:contract.service,state:0
+msgid "Active"
+msgstr ""
+
+#. module: contract_isp
+#: view:res.company:0
+msgid "ISP Contract Management"
+msgstr ""
+
+#. module: contract_isp
+#: field:res.partner,analytic_data_lines_ids:0
+#: field:res.partner,analytic_tel_lines_ids:0
+msgid "Account Lines"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service.activate,account_id:0
+msgid "Account"
+msgstr ""
+
+#. module: contract_isp
+#: selection:contract.service,analytic_line_type:0
+#: selection:product.product,analytic_line_type:0
+msgid "One time"
+msgstr ""
+
+#. module: contract_isp
+#: view:account.analytic.account:0
+#: view:contract.service:0
+msgid "Desactivate"
+msgstr ""
+
+#. module: contract_isp
+#: model:ir.model,name:contract_isp.model_contract_service_activate
+msgid "contract.service.activate"
+msgstr ""
+
+#. module: contract_isp
+#: model:ir.model,name:contract_isp.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service,account_id:0
+msgid "Contract"
+msgstr ""
+
+#. module: contract_isp
+#: view:contract.service.activate:0
+msgid "Cancel"
+msgstr ""
+
+#. module: contract_isp
+#: view:contract.service.activate:0
+#: model:ir.actions.act_window,name:contract_isp.action_view_contract_service_activate
+msgid "Activate Service"
+msgstr ""
+
+#. module: contract_isp
+#: field:res.company,cutoff_day:0
+msgid "Cutoff day"
+msgstr ""
+
+#. module: contract_isp
+#: field:res.partner,payments_ids:0
+msgid "Payments"
+msgstr ""
+
+#. module: contract_isp
+#: selection:contract.service,state:0
+msgid "Waiting for activating"
+msgstr ""
+
+#. module: contract_isp
+#: field:res.partner,partner_analytic_account_id:0
+msgid "Partner Analytic Account"
+msgstr ""
+
+#. module: contract_isp
+#: view:account.analytic.account:0
+#: view:contract.service:0
+#: view:contract.service.activate:0
+msgid "Activate"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service,account_line_id:0
+msgid "Account Entry"
+msgstr ""
+
+#. module: contract_isp
+#: model:ir.model,name:contract_isp.model_contract_service
+msgid "contract.service"
+msgstr ""
+
+#. module: contract_isp
+#: model:res.groups,name:contract_isp.group_isp_agent
+msgid "Agent"
+msgstr ""
+
+#. module: contract_isp
+#: view:account.analytic.account:0
+msgid "Suspend"
+msgstr ""
+
+#. module: contract_isp
+#: view:contract.service:0
+#: model:ir.model,name:contract_isp.model_account_analytic_account
+msgid "Analytic Account"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service.activate,activation_date:0
+msgid "Activation Date"
+msgstr ""
+
+#. module: contract_isp
+#: view:account.analytic.account:0
+#: field:account.analytic.account,contract_service_ids:0
+#: model:ir.actions.act_window,name:contract_isp.action_contract_service_manage
+msgid "Services"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service,duration:0
+msgid "Duration"
+msgstr ""
+
+#. module: contract_isp
+#: model:ir.model,name:contract_isp.model_res_partner
+msgid "Partner"
+msgstr ""
+
+#. module: contract_isp
+#: field:contract.service,activation_line_generated:0
+msgid "Activation Line Generated?"
+msgstr ""
+
+#. module: contract_isp
+#: view:contract.service:0
+msgid "Contract Services"
+msgstr ""
+

=== added directory 'contract_isp/security'
=== added file 'contract_isp/security/contract_isp_security.xml'
--- contract_isp/security/contract_isp_security.xml	1970-01-01 00:00:00 +0000
+++ contract_isp/security/contract_isp_security.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+	<!-- Data goes here -->
+        <record id="group_isp_agent" model="res.groups">
+            <field name="name">Agent</field>
+            <field name="category_id" ref="base.module_category_customer_relationship_management" />
+            <field name="users" eval="[(4, ref('base.user_root'))]" />
+	    <field name="implied_ids" eval="None" />
+            <field name="comment">The users in this group will be able to manage customers and contracts</field>
+        </record>
+
+    </data>
+</openerp>

=== added file 'contract_isp/security/ir.model.access.csv'
--- contract_isp/security/ir.model.access.csv	1970-01-01 00:00:00 +0000
+++ contract_isp/security/ir.model.access.csv	2013-09-12 15:29:09 +0000
@@ -0,0 +1,23 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+"access_contract_service_isp_agent","access_contract_service","model_contract_service","group_isp_agent",1,1,1,0
+"access_account_analytic_account_isp_agent","access_account_analytic_account","model_account_analytic_account","group_isp_agent",1,1,1,0
+"access_account_analytic_line_isp_agent","access_account_analytic_line","model_account_analytic_line","group_isp_agent",1,1,1,1
+"access_res_partner_group_isp_agent","access_res_partner","model_res_partner","group_isp_agent",1,1,1,0
+"access_product_product_group_isp_agent","access_product_product group_isp_agent","product.model_product_product","group_isp_agent",1,0,0,0
+"access_product_category_group_isp_agent","access_product_category group_isp_agent","product.model_product_category","group_isp_agent",1,0,0,0
+"access_product_pricelist_group_isp_agent","access_product_pricelist group_isp_agent","product.model_product_pricelist","group_isp_agent",1,0,0,0
+"access_product_pricelist_versiongroup_isp_agent","access_product_pricelist_version group_isp_agent","product.model_product_pricelist_version","group_isp_agent",1,0,0,0
+"access_product_uom_group_isp_agent","access_product_uom group_isp_agent","product.model_product_uom","group_isp_agent",1,0,0,0
+"access_product_template_group_isp_agent","access_product_template group_isp_agent","product.model_product_template","group_isp_agent",1,0,0,0
+"access_product_supplierinfo_group_isp_agent","access_product_supplierinfo group_isp_agent","product.model_product_supplierinfo","group_isp_agent",1,0,0,0
+"access_account_invoice_group_isp_agent","access_account_invoice group_isp_agent","account.model_account_invoice","group_isp_agent",1,1,1,0
+"access_account_invoice_line_group_isp_agent","access_account_invoice group_isp_agent","account.model_account_invoice_line","group_isp_agent",1,1,1,0
+"access_account_voucher_group_isp_agent","access_account_voucher group_isp_agent","account_voucher.model_account_voucher","group_isp_agent",1,1,1,0
+"access_account_voucher_line_group_isp_agent","access_account_voucher_line group_isp_agent","account_voucher.model_account_voucher_line","group_isp_agent",1,1,1,0
+"access_account_fiscalyear_group_isp_agent","access_account_fiscalyear group_isp_agent","account.model_account_fiscalyear","group_isp_agent",1,0,0,0
+"access_account_sequence_fiscalyear_group_isp_agent","access_account_sequence_fiscalyear group_isp_agent","account.model_account_sequence_fiscalyear","group_isp_agent",1,1,1,0
+"access_account_analytic_journal_group_isp_agent","access_account_analytic_journal group_isp_agent","account.model_account_analytic_journal","group_isp_agent",1,0,0,0
+"access_sale_order_group_isp_agent","access_sale_order group_isp_agent","sale.model_sale_order","group_isp_agent",1,0,0,0
+"access_account_period_group_isp_agent","access_account_period group_isp_agent","account.model_account_period","group_isp_agent",1,0,0,0
+"access_account_journal_group_isp_agent","access_account_journal group_isp_agent","account.model_account_journal","group_isp_agent",1,0,0,0
+"access_account_move_group_isp_agent","access_account_move group_isp_agent","account.model_account_move","group_isp_agent",1,1,1,0

=== added directory 'contract_isp/wizard'
=== added file 'contract_isp/wizard/__init__.py'
--- contract_isp/wizard/__init__.py	1970-01-01 00:00:00 +0000
+++ contract_isp/wizard/__init__.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<www.savoirfairelinux.com>).
+#
+#    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 activate_contract_service

=== added file 'contract_isp/wizard/activate_contract_service.py'
--- contract_isp/wizard/activate_contract_service.py	1970-01-01 00:00:00 +0000
+++ contract_isp/wizard/activate_contract_service.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,119 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<www.savoirfairelinux.com>).
+#
+#    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 datetime
+from openerp.osv import orm, fields
+from openerp.addons.contract_isp.contract import add_months
+
+
+class contract_service_activate(orm.TransientModel):
+    _name = 'contract.service.activate'
+
+    def _get_account_id(self, cr, uid, context=None):
+        if context.get('active_model', '') == 'contract.service':
+            contract_id = context.get('active_id')
+            contract_service = self.pool.get('contract.service').browse(
+                cr, uid, contract_id, context)
+
+            return contract_service.account_id.id
+        return None
+
+    def _get_service_id(self, cr, uid, context=None):
+        if context.get('active_model', '') == 'contract.service':
+            service_id = context.get('active_id')
+            contract_service = self.pool.get('contract.service').browse(
+                cr, uid, service_id, context)
+
+            return contract_service.id
+        return None
+
+    _columns = {
+        'activation_date': fields.datetime('Activation Date'),
+        'account_id': fields.many2one('account.analytic.account', 'Account'),
+        'service_id': fields.many2one('contract.service', 'Service')
+    }
+
+    _defaults = {
+        'activation_date': fields.datetime.now,
+        'account_id': lambda s, cr, uid, ctx: s._get_account_id(cr, uid, ctx),
+        'service_id': lambda s, cr, uid, ctx: s._get_service_id(cr, uid, ctx)
+    }
+
+    def activate(self, cr, uid, ids, context=None):
+        wizard = self.browse(cr, uid, ids[0], context)
+        company_obj = self.pool.get('res.company')
+        company_id = company_obj._company_default_get(cr, uid, context)
+        cutoff = company_obj.read(cr, uid, company_id, 'cutoff_day', context)
+        contract_service_obj = self.pool.get('contract.service')
+        contract_service = contract_service_obj.browse(
+            cr, uid, wizard.service_id.id, context)
+
+        activation_date = datetime.date(
+            int(wizard.activation_date[:4]),
+            int(wizard.activation_date[5:7]),
+            int(wizard.activation_date[8:10]))
+
+        cuttoff_day = company_obj.read(
+            cr, uid,
+            company_id,
+            fields=['cutoff_day'],
+            context=context)['cutoff_day']
+
+        invoice_day = company_obj.read(
+            cr, uid,
+            company_id,
+            fields=['invoice_day'],
+            context=context)['invoice_day']
+
+        cutoff_date = datetime.date(
+            datetime.date.today().year,
+            datetime.date.today().month,
+            int(cuttoff_day))
+
+        invoice_date = datetime.date(
+            datetime.date.today().year,
+            datetime.date.today().month,
+            int(invoice_day))
+
+        contract_service.write({
+            'activation_date': wizard.activation_date,
+            'state': 'active'
+        })
+
+        query = [
+            ('account_id', '=', wizard.account_id.id),
+            ('state', '=', 'draft')
+        ]
+        draft_line_ids = contract_service_obj.search(cr, uid, query,
+                                                     context=context)
+
+        if not draft_line_ids:
+            for line in wizard.account_id.contract_service_ids:
+                if line.activation_line_generated is False:
+                    line.create_analytic_line(mode='manual',
+                                              date=activation_date)
+
+                    if line.analytic_line_type == 'r':
+                        line.create_analytic_line(mode='prorata',
+                                                  date=activation_date)
+
+        return True

=== added file 'contract_isp/wizard/activate_contract_service.xml'
--- contract_isp/wizard/activate_contract_service.xml	1970-01-01 00:00:00 +0000
+++ contract_isp/wizard/activate_contract_service.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_contract_service_activate" model="ir.ui.view">
+            <field name="name">Activate Service</field>
+            <field name="model">contract.service.activate</field>
+            <field name="arch" type="xml">
+                <form string="Activate Service" version="7.0">
+		    <group>
+			<field name="activation_date" />
+			<field name="account_id" invisible="1" />
+			<field name="service_id" invisible="1" />
+		    </group>
+		    <footer>
+			<button 
+			    name="activate"
+			    string="Activate"
+			    type="object"
+			    class="oe_highlight" />
+			<button
+			    string="Cancel"
+			    class="oe_link"
+			    special="cancel" />
+		    </footer>
+		</form>
+	    </field>
+	</record>
+        <record id="action_view_contract_service_activate" model="ir.actions.act_window">
+            <field name="name">Activate Service</field>
+            <field name="type">ir.actions.act_window</field>
+	    <field name="src_model">contract.service</field>
+            <field name="res_model">contract.service.activate</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+	    <field name="context">{'default_service_id': active_id}</field>
+            <field name="target">new</field>
+        </record>
+
+    </data>
+</openerp>

=== added directory 'contract_isp_automatic_invoicing'
=== added file 'contract_isp_automatic_invoicing/__init__.py'
--- contract_isp_automatic_invoicing/__init__.py	1970-01-01 00:00:00 +0000
+++ contract_isp_automatic_invoicing/__init__.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux Inc. (<www.savoirfairelinux.com>).
+#
+#    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 contract

=== added file 'contract_isp_automatic_invoicing/__openerp__.py'
--- contract_isp_automatic_invoicing/__openerp__.py	1970-01-01 00:00:00 +0000
+++ contract_isp_automatic_invoicing/__openerp__.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux Inc. (<www.savoirfairelinux.com>).
+#
+#    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/>.
+#
+##############################################################################
+
+{
+    'name': 'Contract ISP Automatic Invoicing',
+    'version': '1.0',
+    'category': 'Account',
+    'description': """A module to automatically invoice services based contracts""",
+    'author': 'Savoir-faire Linux Inc.',
+    'website': 'www.savoirfairelinux.com',
+    'license': 'AGPL-3',
+    'depends': ['contract_isp_invoice'],
+    'data': ['contract_isp_automatic_invoicing_data.xml'],
+    'active': False,
+    'installable': True,
+}

=== added file 'contract_isp_automatic_invoicing/contract.py'
--- contract_isp_automatic_invoicing/contract.py	1970-01-01 00:00:00 +0000
+++ contract_isp_automatic_invoicing/contract.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
+#
+#    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/>.
+#
+##############################################################################
+from openerp.osv import orm, fields
+
+
+class account_analytic_account(orm.Model):
+    _inherit = 'account.analytic.account'
+
+    def cron_contract_automatic_invoicing(self, cr, uid, ids=None,
+                                          context=None):
+        if context is None:
+            context = {}
+
+        if not context.get('create_analytic_line_mode', False):
+            context['create_analytic_line_mode'] = 'cron'
+
+        query = [
+            ('state', '=', 'open'),
+            ('type', '=', 'contract')
+        ]
+
+        ids_to_invoice = self.search(cr, uid, query, context=context)
+
+        for contract_id in ids_to_invoice:
+            self.create_analytic_lines(cr, uid, [contract_id], context=context)
+            self.create_invoice(cr, uid, contract_id, context=context)
+            
\ No newline at end of file

=== added file 'contract_isp_automatic_invoicing/contract_isp_automatic_invoicing_data.xml'
--- contract_isp_automatic_invoicing/contract_isp_automatic_invoicing_data.xml	1970-01-01 00:00:00 +0000
+++ contract_isp_automatic_invoicing/contract_isp_automatic_invoicing_data.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding='UTF-8'?>
+<openerp>
+    <data>
+        <record model="ir.cron" id="account_analytic_cron">
+            <field name="name">Contract Automatic Invoicing</field>
+            <field name="interval_number">1</field>
+            <field name="interval_type">months</field>
+            <field name="numbercall">-1</field>
+	    <field name="active" eval="False" />
+            <field name="doall" eval="False"/>
+            <field name="model" eval="'account.analytic.account'"/>
+            <field name="function" eval="'cron_contract_automatic_invoicing'"/>
+            <field name="args" eval="'()'" />
+        </record>
+    </data>
+</openerp>

=== added directory 'contract_isp_automatic_invoicing/i18n'
=== added file 'contract_isp_automatic_invoicing/i18n/contract_isp_automatic_invoicing.pot'
=== added directory 'contract_isp_invoice'
=== added file 'contract_isp_invoice/__init__.py'
--- contract_isp_invoice/__init__.py	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/__init__.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<www.savoirfairelinux.com>).
+#
+#    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 contract
+import wizard

=== added file 'contract_isp_invoice/__openerp__.py'
--- contract_isp_invoice/__openerp__.py	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/__openerp__.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<www.savoirfairelinux.com>).
+#
+#    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/>.
+#
+##############################################################################
+
+{
+    'name': 'ISP Contract Invoice',
+    'version': '1.0',
+    'category': 'Contract Management',
+    'description': """
+Invoicing for service based contracts
+=====================================
+
+Generates invoices for service based contracts.
+
+Features:
+---------
+
+* Refund on contract closing
+* Exception services invoice logic
+""",
+    'author': 'Savoir-faire Linux (joao.gama@xxxxxxxxxxxxxxxxxxxx)',
+    'website': 'www.savoirfairelinux.com',
+    'license': 'AGPL-3',
+    'depends': ['contract_isp'],
+    'data': ['contract_isp_invoice_data.xml',
+             'contract_isp_invoice_view.xml',
+             'wizard/contract_isp_invoice_invoice_create.xml',
+             'wizard/close_contract_view.xml'],
+    'active': False,
+    'installable': True,
+}

=== added file 'contract_isp_invoice/contract.py'
--- contract_isp_invoice/contract.py	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/contract.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,354 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
+#
+#    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 logging
+import time
+import datetime
+from openerp.osv import orm, fields
+from openerp.addons.contract_isp.contract import add_months, date_interval
+
+_logger = logging.getLogger(__name__)
+
+
+class res_company(orm.Model):
+    _inherit = "res.company"
+
+    def _days(self, cr, uid, context=None):
+        return tuple([(str(x), str(x)) for x in range(1, 29)])
+
+    _columns = {
+        'invoice_day': fields.selection(_days, 'Invoice day'),
+    }
+
+
+class res_partner(orm.Model):
+    _inherit = "res.partner"
+
+    def _get_default_payment_term(self, cr, uid, context=None):
+        return self.pool.get('ir.model.data').get_object_reference(
+            cr, uid, 'contract_isp_invoice',
+            'account_payment_term_end_of_month')[1]
+
+    _defaults = {
+        'property_payment_term': lambda s, cr, uid, ctx: s._get_default_payment_term(cr, uid, ctx)
+    }
+
+
+class account_analytic_account(orm.Model):
+    _inherit = "account.analytic.account"
+
+    _columns = {
+        'close_date': fields.datetime('Close date'),
+        'close_reason': fields.text('Reasons')
+    }
+
+    _defaults = {
+        'close_date': fields.datetime.now
+    }
+
+    def create_invoice(self, cr, uid, ids, prorata=False, context=None):
+        return_int = False
+        if isinstance(ids, int):
+            return_int = True
+            ids = [ids]
+
+        account_analytic_line = self.pool.get('account.analytic.line')
+        contract_service_obj = self.pool.get('contract.service')
+        res_company_obj = self.pool.get('res.company')
+        account_invoice_obj = self.pool.get('account.invoice')
+
+        cuttoff_day = res_company_obj.read(
+            cr, uid,
+            res_company_obj._company_default_get(cr, uid, context),
+            fields=['cutoff_day'],
+            context=context)['cutoff_day']
+
+        cutoff_date = datetime.date(
+            datetime.date.today().year,
+            datetime.date.today().month,
+            int(cuttoff_day)
+        )
+
+        invoice_day = res_company_obj.read(
+            cr, uid,
+            res_company_obj._company_default_get(cr, uid, context),
+            fields=['invoice_day'],
+            context=context)['invoice_day']
+
+        invoice_date = datetime.date(
+            datetime.date.today().year,
+            datetime.date.today().month,
+            int(invoice_day)
+        )
+
+        ret = []
+        for contract_id in ids:
+            #if context.get('create_line_before_invoice', False):
+            #    contract_service_obj.
+            query = [('account_id', '=', contract_id),
+                     ('to_invoice', '!=', None),
+                     ('invoice_id', '=', None),
+                     ('product_id', '!=', None),
+                     ('is_prorata', '=', prorata)]
+
+            ids_to_invoice = account_analytic_line.search(cr, uid, query,
+                                                          context=context)
+            if ids_to_invoice:
+                data = {
+                    'name': True,
+                }
+                inv = account_analytic_line.invoice_cost_create(
+                    cr, uid, ids_to_invoice, data=data, context=context)
+
+                # jgama - If its a prorata invoice, change the invoice date
+                #         according to the invoice_day variable
+                if prorata:
+                    if datetime.date.today() <= cutoff_date:
+                        date_invoice = invoice_date.strftime('%Y-%m-%d')
+                    else:
+                        date_invoice = add_months(invoice_date, 1).strftime(
+                            '%Y-%m-%d')
+
+                    account_invoice_obj.write(
+                        cr, uid, inv, {'date_invoice': date_invoice},
+                        context=context)
+
+                a = account_invoice_obj._workflow_signal(
+                    cr, uid, inv, 'invoice_open', context)
+                mail_template_obj = self.pool.get('email.template')
+                ir_model_data_obj = self.pool.get('ir.model.data')
+                mail_template_id = ir_model_data_obj.get_object_reference(
+                    cr, uid, 'account', 'email_template_edi_invoice')[1]
+                mail_mail_obj = self.pool.get('mail.mail')
+                if isinstance(inv, list):
+                    for i in inv:
+                        mail_id = mail_template_obj.send_mail(
+                            cr, uid, mail_template_id, i, context=context)
+                        mail_message = mail_mail_obj.browse(
+                            cr, uid, mail_id, context=context).mail_message_id
+                        mail_message.write({'type': 'email'})
+                        ret.append(i)
+                else:
+                    mail_id = mail_template_obj.send_mail(
+                        cr, uid, mail_template_id, inv, context=context)
+                    mail_message = mail_mail_obj.browse(
+                        cr, uid, mail_id, context=context).mail_message_id
+                    mail_message.write({'type': 'email'})
+                    ret.append(inv)
+
+        if return_int:
+            if len(ret) == 0:
+                return None
+            else:
+                return ret[0]
+        else:
+            return ret
+
+    def set_close(self, cr, uid, ids, context=None):
+
+        return {
+            'type': 'ir.actions.act_window',
+            'src_model': 'account.analytic.account',
+            'res_model': 'contract.isp.close',
+            'view_type': 'form',
+            'view_mode': 'form',
+            'target': 'new'
+        }
+
+
+class account_analytic_line(orm.Model):
+    _inherit = 'account.analytic.line'
+
+    def invoice_cost_create(self, cr, uid, ids, data=None, context=None):
+        # jgama - Sligtly modified version. Original from
+        #         hr_timesheet_invoice.py
+
+        analytic_account_obj = self.pool.get('account.analytic.account')
+        account_payment_term_obj = self.pool.get('account.payment.term')
+        invoice_obj = self.pool.get('account.invoice')
+        product_obj = self.pool.get('product.product')
+        invoice_factor_obj = self.pool.get('hr_timesheet_invoice.factor')
+        fiscal_pos_obj = self.pool.get('account.fiscal.position')
+        product_uom_obj = self.pool.get('product.uom')
+        invoice_line_obj = self.pool.get('account.invoice.line')
+        invoices = []
+        if context is None:
+            context = {}
+        if data is None:
+            data = {}
+
+        journal_types = {}
+
+        # prepare for iteration on journal and accounts
+        for line in self.pool.get('account.analytic.line').browse(
+                cr, uid, ids, context=context):
+            if line.journal_id.type not in journal_types:
+                journal_types[line.journal_id.type] = set()
+            journal_types[line.journal_id.type].add(line.account_id.id)
+        for journal_type, account_ids in journal_types.items():
+            for account in analytic_account_obj.browse(
+                    cr, uid, list(account_ids), context=context):
+                partner = account.partner_id
+                if (not partner) or not (account.pricelist_id):
+                    raise osv.except_osv(
+                        _('Analytic Account Incomplete!'),
+                        _('Contract incomplete. Please fill in the Customer and Pricelist fields.'))
+
+                date_due = False
+                if partner.property_payment_term:
+                    pterm_list = account_payment_term_obj.compute(
+                        cr, uid, partner.property_payment_term.id, value=1,
+                        date_ref=time.strftime('%Y-%m-%d'))
+                    if pterm_list:
+                        pterm_list = [line[0] for line in pterm_list]
+                        pterm_list.sort()
+                        date_due = pterm_list[-1]
+
+                curr_invoice = {
+                    'name': time.strftime('%d/%m/%Y') + ' - ' + account.name,
+                    'origin': account.name,
+                    'partner_id': account.partner_id.id,
+                    'company_id': account.company_id.id,
+                    'payment_term': partner.property_payment_term.id or False,
+                    'account_id': partner.property_account_receivable.id,
+                    'currency_id': account.pricelist_id.currency_id.id,
+                    'date_due': date_due,
+                    'fiscal_position': account.partner_id.property_account_position.id
+                }
+                context2 = context.copy()
+                context2['lang'] = partner.lang
+                # set company_id in context, so the correct default journal
+                # will be selected
+                context2['force_company'] = curr_invoice['company_id']
+                # set force_company in context so the correct product
+                # properties are selected (eg. income account)
+                context2['company_id'] = curr_invoice['company_id']
+
+                last_invoice = invoice_obj.create(
+                    cr, uid, curr_invoice, context=context2)
+                invoices.append(last_invoice)
+
+                cr.execute("""SELECT product_id, user_id, to_invoice, sum(amount), sum(unit_amount), product_uom_id
+                        FROM account_analytic_line as line LEFT JOIN account_analytic_journal journal ON (line.journal_id = journal.id)
+                        WHERE account_id = %s
+                            AND line.id IN %s AND journal.type = %s AND to_invoice IS NOT NULL
+                        GROUP BY product_id, user_id, to_invoice, product_uom_id""", (account.id, tuple(ids), journal_type))
+
+                for product_id, user_id, factor_id, total_price, qty, uom in cr.fetchall():
+                    context2.update({'uom': uom})
+
+                    if data.get('product'):
+                        # force product, use its public price
+                        product_id = data['product'][0]
+                        unit_price = self._get_invoice_price(
+                            cr, uid, account, product_id, user_id, qty, context2)
+                    #elif journal_type == 'general' and product_id:
+                    #    # timesheets, use sale price
+                    #    unit_price = self._get_invoice_price(cr, uid, account, product_id, user_id, qty, context2)
+                    else:
+                        # expenses, using price from amount field
+                        unit_price = total_price * -1.0 / qty
+
+                    factor = invoice_factor_obj.browse(
+                        cr, uid, factor_id, context=context2)
+                    # factor_name = factor.customer_name and line_name + ' - ' + factor.customer_name or line_name
+                    factor_name = ''
+                    if data.get('factor_name', False):
+                        factor_name = factor.customer_name
+
+                    curr_line = {
+                        'price_unit': unit_price,
+                        'quantity': qty,
+                        'product_id': product_id or False,
+                        'discount': factor.factor,
+                        'invoice_id': last_invoice,
+                        'name': factor_name,
+                        'uos_id': uom,
+                        'account_analytic_id': account.id,
+                    }
+                    product = product_obj.browse(
+                        cr, uid, product_id, context=context2)
+                    if product:
+                        factor_name = data.get('product_name', '') and \
+                            product_obj.name_get(
+                                cr, uid, [product_id], context=context2)[0][1]
+                        if factor.customer_name and data.get('factor_name',
+                                                             False):
+                            factor_name += ' - ' + factor.customer_name
+
+                        general_account = product.property_account_income or \
+                            product.categ_id.property_account_income_categ
+                        if not general_account:
+                            raise osv.except_osv(
+                                _("Configuration Error!"),
+                                _("Please define income account for product '%s'.") % product.name)
+                        taxes = product.taxes_id or general_account.tax_ids
+                        tax = fiscal_pos_obj.map_tax(
+                            cr, uid,
+                            account.partner_id.property_account_position,
+                            taxes)
+                        curr_line.update({
+                            'invoice_line_tax_id': [(6, 0, tax)],
+                            'name': factor_name,
+                            'invoice_line_tax_id': [(6, 0, tax)],
+                            'account_id': general_account.id,
+                        })
+                    #
+                    # Compute for lines
+                    #
+                    cr.execute("SELECT * FROM account_analytic_line WHERE account_id = %s and id IN %s AND product_id=%s and to_invoice=%s ORDER BY account_analytic_line.date", (account.id, tuple(ids), product_id, factor_id))
+
+                    line_ids = cr.dictfetchall()
+                    note = []
+                    for line in line_ids:
+                        # set invoice_line_note
+                        details = []
+                        if data.get('date', False):
+                            details.append(line['date'])
+                        if data.get('time', False):
+                            if line['product_uom_id']:
+                                details.append("%s %s" % (
+                                    line['unit_amount'],
+                                    product_uom_obj.browse(
+                                        cr, uid, [line['product_uom_id']],
+                                        context2)[0].name))
+
+                            else:
+                                details.append("%s" % (line['unit_amount'], ))
+                        if data.get('name', False):
+                            details.append(line['name'])
+                        note.append(u' - '.join(
+                            map(lambda x: unicode(x) or '', details)))
+                    if note:
+                        if curr_line['name']:
+                            curr_line['name'] += "\n" + ("\n".join(
+                                map(lambda x: unicode(x) or '', note)))
+                        else:
+                            curr_line['name'] = "\n".join(
+                                map(lambda x: unicode(x) or '', note))
+                    invoice_line_obj.create(
+                        cr, uid, curr_line, context=context)
+                    cr.execute("update account_analytic_line set invoice_id=%s WHERE account_id = %s and id IN %s", (last_invoice, account.id, tuple(ids)))
+
+                invoice_obj.button_reset_taxes(
+                    cr, uid, [last_invoice], context)
+        return invoices

=== added file 'contract_isp_invoice/contract_isp_invoice_data.xml'
--- contract_isp_invoice/contract_isp_invoice_data.xml	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/contract_isp_invoice_data.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+        <record id="account_payment_term_end_of_month" model="account.payment.term">
+            <field name="name">End of Month</field>
+            <field name="note">End of current month</field>
+        </record>
+        <record id="account_payment_term_end_of_month_line" model="account.payment.term.line">
+            <field name="value">balance</field>
+            <field eval="0" name="days"/>
+            <field eval="-1" name="days2"/>
+            <field eval="account_payment_term_end_of_month" name="payment_id"/>
+        </record>
+    </data>
+
+    <data noupdate="1">
+        <record id="email_template_contract_isp_invoice_close" model="email.template">
+            <field name="name">Contract close</field>
+            <field name="email_from">${user.email or ''}</field>
+            <field name="subject">Contract n. ${object.name}</field>
+            <field name="email_to">object.manager_id.email or ''</field>
+            <field name="lang">${user.lang}</field>
+            <field name="model_id" ref="analytic.model_account_analytic_account"/>
+            <field name="auto_delete" eval="True"/>
+            <field name="body_html"><![CDATA[
+<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
+
+    <p>Dear Accountant,</p>
+    <p>
+    Please take notice that the following contract is being terminated.
+
+    </p>
+<br/>
+    <table>
+    <tr>
+    <td>Contract:</td><td>${object.name}</td>
+    </tr>
+    <tr>
+    <td>Partner:</td><td>${object.partner_id.name}</td>
+    </tr> 
+    <tr>
+    <td>Close date:</td><td>${object.close_date}</td>
+    </tr>
+    </table>
+    <h3>Reasons/Comments</h3>
+    <p>${object.close_reason}</p>
+<br/>
+Best Regards,
+<br/>
+   <br/>
+${user.name}
+
+<br/>
+
+    <br/>
+
+</div>
+            ]]></field>
+        </record>
+
+    </data>
+</openerp>

=== added file 'contract_isp_invoice/contract_isp_invoice_demo.xml'
=== added file 'contract_isp_invoice/contract_isp_invoice_report.xml'
=== added file 'contract_isp_invoice/contract_isp_invoice_security.xml'
=== added file 'contract_isp_invoice/contract_isp_invoice_view.xml'
--- contract_isp_invoice/contract_isp_invoice_view.xml	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/contract_isp_invoice_view.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+	<record id="view_company_contract_isp_invoice_form" model="ir.ui.view">
+            <field name="name">contract.isp.invoice.res.company.form</field>
+            <field name="model">res.company</field>
+	    <field name="inherit_id" ref="contract_isp.view_company_contract_isp_form"/>
+            <field name="arch" type="xml">
+		<field name="cutoff_day" position="after">
+		    <field name="invoice_day" />
+		</field>
+	    </field>
+	</record>
+
+        <record id="action_view_create_voucher" model="ir.actions.act_window">
+            <field name="name">Create Voucher</field>
+            <field name="type">ir.actions.act_window</field>
+	    <field name="src_model">account.analytic.account</field>
+            <field name="res_model">account.voucher</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+	    <field name="context">{'default_type': 'receipt', 'default_partner_id': default_partner_id}</field>
+	    <field name="view_id" ref='account_voucher.view_vendor_receipt_form' />
+            <field name="target">new</field>
+        </record>
+
+        <record id="contract_isp_form_button1" model="ir.ui.view">
+            <field name="name">contract.isp.form.button1</field>
+            <field name="model">account.analytic.account</field>
+            <field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
+            <field name="arch" type="xml">
+                <xpath expr="//div[@name='buttons']" position='inside'>
+		    <button string="Create Voucher"
+			    name="%(action_view_create_voucher)d"
+			    context="{'default_partner_id': partner_id}"
+			    type="action" />
+		</xpath>
+	    </field>
+	</record>
+
+        <record id="view_voucher_form_analytic_id" model="ir.ui.view">
+            <field name="name">account.voucher.form.analytic</field>
+            <field name="model">account.voucher</field>
+            <field name="inherit_id" ref="account_voucher.view_voucher_form" />
+            <field name="arch" type="xml">
+		<field name="account_id" position="after">
+		    <field name="analytic_id" />
+		</field>
+	    </field>
+	</record>
+
+
+	<!-- <record id="view_partner_contract_isp_invoice_form" model="ir.ui.view"> -->
+        <!--     <field name="name">contract.isp.invoice.res.partner.form</field> -->
+        <!--     <field name="model">res.partner</field> -->
+	<!--     <field name="inherit_id" ref="account.view_partner_property_form"/> -->
+        <!--     <field name="arch" type="xml"> -->
+	<!-- 	<xpath expr="//page[@string='Accounting']" position="after"> -->
+	<!-- 	    <page string="ISP Contract Management"> -->
+	<!-- 		<field name="data_account_id" /> -->
+	<!-- 		<field name="telco_account_id" /> -->
+	<!-- 	    </page> -->
+	<!-- 	</xpath> -->
+	<!--     </field> -->
+	<!-- </record> -->
+
+    </data>
+</openerp>

=== added file 'contract_isp_invoice/contract_isp_invoice_wizard.xml'
=== added directory 'contract_isp_invoice/i18n'
=== added file 'contract_isp_invoice/i18n/contract_isp_invoice.pot'
--- contract_isp_invoice/i18n/contract_isp_invoice.pot	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/i18n/contract_isp_invoice.pot	2013-09-12 15:29:09 +0000
@@ -0,0 +1,58 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+#	* contract_isp_invoice
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-08-13 12:38+0000\n"
+"PO-Revision-Date: 2013-08-13 12:38+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: contract_isp_invoice
+#: view:account.analytic.account:0
+#: model:ir.actions.act_window,name:contract_isp_invoice.action_view_create_voucher
+msgid "Create Voucher"
+msgstr ""
+
+#. module: contract_isp_invoice
+#: model:ir.model,name:contract_isp_invoice.model_contract_service_activate
+msgid "contract.service.activate"
+msgstr ""
+
+#. module: contract_isp_invoice
+#: model:ir.model,name:contract_isp_invoice.model_account_analytic_line
+msgid "Analytic Line"
+msgstr ""
+
+#. module: contract_isp_invoice
+#: model:account.payment.term,name:contract_isp_invoice.account_payment_term_end_of_month
+msgid "End of Month"
+msgstr ""
+
+#. module: contract_isp_invoice
+#: field:res.company,invoice_day:0
+msgid "Invoice day"
+msgstr ""
+
+#. module: contract_isp_invoice
+#: model:ir.model,name:contract_isp_invoice.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: contract_isp_invoice
+#: model:ir.model,name:contract_isp_invoice.model_account_analytic_account
+msgid "Analytic Account"
+msgstr ""
+
+#. module: contract_isp_invoice
+#: model:account.payment.term,note:contract_isp_invoice.account_payment_term_end_of_month
+msgid "End of current month"
+msgstr ""
+

=== added directory 'contract_isp_invoice/report'
=== added file 'contract_isp_invoice/report/__init__.py'
--- contract_isp_invoice/report/__init__.py	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/report/__init__.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<www.savoirfairelinux.com>).
+#
+#    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 report

=== added directory 'contract_isp_invoice/security'
=== added file 'contract_isp_invoice/security/contract_isp_invoice_security.xml'
--- contract_isp_invoice/security/contract_isp_invoice_security.xml	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/security/contract_isp_invoice_security.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+	<!-- Data goes here -->
+    </data>
+</openerp>

=== added directory 'contract_isp_invoice/wizard'
=== added file 'contract_isp_invoice/wizard/__init__.py'
--- contract_isp_invoice/wizard/__init__.py	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/wizard/__init__.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<www.savoirfairelinux.com>).
+#
+#    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 activate_contract_service
+import contract_isp_invoice_invoice_create
+import close_contract

=== added file 'contract_isp_invoice/wizard/activate_contract_service.py'
--- contract_isp_invoice/wizard/activate_contract_service.py	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/wizard/activate_contract_service.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,95 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<www.savoirfairelinux.com>).
+#
+#    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
+import datetime
+from openerp.osv import orm, fields
+from openerp.addons.contract_isp.contract import add_months
+
+
+class contract_service_activate(orm.TransientModel):
+    _inherit = 'contract.service.activate'
+
+    def activate(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+
+        account_invoice_obj = self.pool.get('account.invoice')
+        account_voucher_obj = self.pool.get('account.voucher')
+        account_move_obj = self.pool.get('account.move')
+        res_company_obj = self.pool.get('res.company')
+        wizard = self.browse(cr, uid, ids[0], context)
+
+        ret = super(contract_service_activate, self).activate(cr, uid,
+                                                              ids,
+                                                              context=context)
+
+        contract_service_obj = self.pool.get('contract.service')
+        account_analytic_account_obj = self.pool.get('account.analytic.account')
+        account_move_line_obj = self.pool.get('account.move.line')
+
+        query = [
+            ('account_id', '=', wizard.account_id.id),
+            ('state', '=', 'draft')
+        ]
+        # Check if all services were activated
+        if not contract_service_obj.search(cr, uid, query, context=context):
+            # jgama - Create the activation invoice
+            inv = account_analytic_account_obj.create_invoice(
+                cr, uid, wizard.account_id.id, context=context)
+
+            voucher_id = account_voucher_obj.search(cr, uid,
+                                                    [('partner_id', '=', wizard.account_id.partner_id.id)],
+                                                    context=context)
+            if voucher_id:
+                query = [
+                    ('partner_id', '=', wizard.account_id.partner_id.id),
+                    ('account_id', '=', wizard.account_id.partner_id.property_account_receivable.id),
+                    ('reconcile_id', '=', False)
+                ]
+
+                ids_to_reconcile = account_move_line_obj.search(cr, uid, query,
+                                                                context=context)
+                if ids_to_reconcile:
+                    # Code from account/wizard/account_reconcile.py/\
+                    #    account_move_line_reconcile/trans_rec_reconcile_full
+                    period_obj = self.pool.get('account.period')
+                    date = False
+                    period_id = False
+                    journal_id = False
+                    account_id = False
+
+                    date = time.strftime('%Y-%m-%d')
+                    ctx = dict(context or {}, account_period_prefer_normal=True)
+                    ids = period_obj.find(cr, uid, dt=date, context=ctx)
+                    if ids:
+                        period_id = ids[0]
+                        account_move_line_obj.reconcile(cr, uid, ids_to_reconcile,
+                                                        'manual', account_id,
+                                                        period_id, journal_id,
+                                                        context=context)
+
+            # jgama - Try to create the prorata invoice
+            pro_inv = account_analytic_account_obj.create_invoice(
+                cr, uid, wizard.account_id.id, prorata=True, context=context)
+
+        return ret

=== added file 'contract_isp_invoice/wizard/close_contract.py'
--- contract_isp_invoice/wizard/close_contract.py	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/wizard/close_contract.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
+#
+#    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 logging
+import calendar
+import datetime
+from openerp.osv import orm, fields
+from openerp.report import report_sxw
+from openerp.tools import convert
+from openerp.tools.translate import _
+from openerp.addons.contract_isp.contract import date_interval
+
+
+class contract_isp_close(orm.TransientModel):
+    _name = 'contract.isp.close'
+
+    def _get_account_id(self, cr, uid, context=None):
+        if context.get('active_model', '') == 'account.analytic.account':
+            contract_id = context.get('active_id')
+            return contract_id
+        return None
+
+    _columns = {
+        'account_id': fields.many2one('account.analytic.account', 'Contract'),
+        'close_date': fields.datetime('Close date', required=True),
+        'close_reason': fields.text('Reason')
+    }
+
+    _defaults = {
+        'account_id': lambda s, cr, uid, ctx: s._get_account_id(cr, uid, ctx),
+        'close_date': fields.datetime.now
+    }
+
+    def do_close(self, cr, uid, ids, context=None):
+        wizard = self.browse(cr, uid, ids[0], context=context)
+        mail_mail_obj = self.pool.get('mail.mail')
+        account_analytic_line_obj = self.pool.get('account.analytic.line')
+        account_invoice_obj = self.pool.get('account.invoice')
+        contract = self.browse(cr, uid, ids, context=context)[0].account_id
+
+        today = datetime.date.today()
+
+        query = [
+            ('partner_id', '=', contract.partner_id.id),
+            ('origin', '=', contract.name)
+        ]
+
+        last_invoice_id = account_invoice_obj.search(cr, uid, query,
+                                                     context=context)
+        if last_invoice_id:
+            last_invoice = account_invoice_obj.browse(cr, uid,
+                                                      last_invoice_id[-1],
+                                                      context=context)
+            if last_invoice.date_invoice > wizard.close_date:
+                raise orm.except_orm(_('Error!'), _('Close date before last invoice date!'))
+
+            amount_untaxed = last_invoice.amount_untaxed
+
+            month_days = calendar.monthrange(int(wizard.close_date[:4]),
+                                             int(wizard.close_date[5:7]))[1]
+
+            used_days = month_days - int(wizard.close_date[8:10])
+            ptx = (100 * used_days / month_days) / 100.0
+            amount = amount_untaxed * ptx
+            interval = date_interval(datetime.date(int(wizard.close_date[:4]),
+                                                   int(wizard.close_date[5:7]),
+                                                   int(wizard.close_date[8:10])),
+                                     True)
+
+            line = {
+                'name': ' '.join([_('Credit refund'), interval]),
+                'amount': amount,
+                'account_id': contract.id,
+                'user_id': uid,
+                'general_account_id': contract.partner_id.property_account_receivable.id,
+                'to_invoice': 1,
+                'unit_amount': 1,
+                'is_prorata': True,
+                'date': wizard.close_date
+            }
+            account_analytic_line_obj.create(cr, uid, line, context=context)
+
+        contract.write({'close_date': wizard.close_date,
+                        'close_reason': wizard.close_reason})
+
+        mail_template_obj = self.pool.get('email.template')
+        mail_template_id = self.pool.get('ir.model.data').get_object_reference(
+            cr, uid, 'contract_isp_invoice',
+            'email_template_contract_isp_invoice_close')
+        mail_id = mail_template_obj.send_mail(cr, uid, mail_template_id[1], contract.id, context=context)
+        mail_message = mail_mail_obj.browse(cr, uid, mail_id, context=context).mail_message_id
+        mail_message.write({'type': 'email'})
+        contract.write({'state': 'close'})
+        return {}
+        
\ No newline at end of file

=== added file 'contract_isp_invoice/wizard/close_contract_view.py'
--- contract_isp_invoice/wizard/close_contract_view.py	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/wizard/close_contract_view.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_close_contract" model="ir.ui.view">
+            <field name="name">A</field>
+            <field name="model">contract.service.activate</field>
+            <field name="arch" type="xml">
+                <form string="Activate Service" version="7.0">
+		    <group>
+			<field name="activation_date" />
+			<field name="account_id" invisible="1" />
+			<field name="service_id" invisible="1" />
+		    </group>
+		    <footer>
+			<button 
+			    name="activate"
+			    string="Activate"
+			    type="object"
+			    class="oe_highlight" />
+			<button
+			    string="Cancel"
+			    class="oe_link"
+			    special="cancel" />
+		    </footer>
+		</form>
+	    </field>
+	</record>
+        <record id="action_view_contract_service_activate" model="ir.actions.act_window">
+            <field name="name">Activate Service</field>
+            <field name="type">ir.actions.act_window</field>
+	    <field name="src_model">contract.service</field>
+            <field name="res_model">contract.service.activate</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+	    <field name="context">{'default_service_id': active_id}</field>
+            <field name="target">new</field>
+        </record>
+
+    </data>
+</openerp>

=== added file 'contract_isp_invoice/wizard/close_contract_view.xml'
--- contract_isp_invoice/wizard/close_contract_view.xml	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/wizard/close_contract_view.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_contract_isp_close" model="ir.ui.view">
+            <field name="name">Close contract</field>
+            <field name="model">contract.isp.close</field>
+            <field name="arch" type="xml">
+                <form string="Close Contract" version="7.0">
+		    <field name="account_id" invisible="1" />
+		    <p>Confirm the termination of this contract?</p>
+		    <group>
+			<field name="close_date" />
+		    </group>
+		    <group colspan="4" string="Reason">
+			<field name="close_reason" nolabel="1" />
+		    </group>
+		    <footer>
+			<button 
+			    name="do_close"
+			    string="Confirm"
+			    type="object"
+			    class="oe_highlight" />
+			<button
+			    string="Cancel"
+			    class="oe_link"
+			    special="cancel" />
+		    </footer>
+		</form>
+	    </field>
+	</record>
+        <record id="action_view_contract_isp_close" model="ir.actions.act_window">
+            <field name="name">Close contract</field>
+            <field name="type">ir.actions.act_window</field>
+	    <field name="src_model">account.analytic.account</field>
+            <field name="res_model">contract.isp.close</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+    </data>
+</openerp>

=== added file 'contract_isp_invoice/wizard/contract_isp_invoice_invoice_create.py'
--- contract_isp_invoice/wizard/contract_isp_invoice_invoice_create.py	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/wizard/contract_isp_invoice_invoice_create.py	2013-09-12 15:29:09 +0000
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2013 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
+#
+#    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/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+
+
+class contract_isp_invoice_invoice_create(orm.TransientModel):
+    _inherit = 'hr.timesheet.invoice.create'
+
+    _columns = {
+        'factor_name': fields.boolean('Invoice Factor',
+                                      help='Show the invoice factor'),
+        'product_name': fields.boolean('Product Name',
+                                       help='Show the product name')
+    }
+
+    _defaults = {
+        'factor_name': False,
+        'product_name': False,
+        'name': True
+    }
\ No newline at end of file

=== added file 'contract_isp_invoice/wizard/contract_isp_invoice_invoice_create.xml'
--- contract_isp_invoice/wizard/contract_isp_invoice_invoice_create.xml	1970-01-01 00:00:00 +0000
+++ contract_isp_invoice/wizard/contract_isp_invoice_invoice_create.xml	2013-09-12 15:29:09 +0000
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_contract_isp_invoice_create" model="ir.ui.view">
+            <field name="name">contract.isp.invoice.create.form</field>
+            <field name="model">hr.timesheet.invoice.create</field>
+	    <field name="inherit_id" ref="hr_timesheet_invoice.view_hr_timesheet_invoice_create" />
+            <field name="arch" type="xml">
+		<field name="price" position="after">
+		    <field name="factor_name" />
+		    <field name="product_name" />
+		</field>
+	    </field>
+	</record>
+    </data>
+</openerp>


Follow ups