[MERGE] branch merged with lp:~openerp-dev/openobject-addons/trunk-dev-addons1
bzr revid: mso@mso-20100406052452-ufpxq49ut7ovje1y
This commit is contained in:
commit
6f6276df3d
|
@ -46,7 +46,17 @@ module named account_voucherss
|
|||
'security/account_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'account_menuitem.xml',
|
||||
'wizard/account_invoice_refund_view.xml',
|
||||
'wizard/account_period_close_view.xml',
|
||||
'wizard/account_fiscalyear_close_state.xml',
|
||||
'wizard/account_chart_view.xml',
|
||||
'wizard/account_move_bank_reconcile_view.xml',
|
||||
'wizard/account_move_line_reconcile_select_view.xml',
|
||||
'wizard/account_move_journal_view.xml',
|
||||
'account_wizard.xml',
|
||||
'wizard/account_move_line_unreconcile_select_view.xml',
|
||||
'wizard/account_subscription_generate_view.xml',
|
||||
'project/wizard/project_account_analytic_line_view.xml',
|
||||
'account_view.xml',
|
||||
'account_end_fy.xml',
|
||||
'account_invoice_view.xml',
|
||||
|
|
|
@ -153,7 +153,7 @@
|
|||
<field name="period_id" groups="base.group_user"/>
|
||||
<group colspan="2" col="1" groups="base.group_user">
|
||||
<label align="0.0" string="(keep empty to use the current period)"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Invoice">
|
||||
|
|
|
@ -24,3 +24,4 @@
|
|||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
|
|
|
@ -668,9 +668,9 @@
|
|||
<field eval="True" name="object"/>
|
||||
</record>
|
||||
|
||||
<wizard id="action_move_journal_line_form" menu="False" model="account.move.line" name="account.move.journal" string="Entries by Line"/>
|
||||
<!-- <wizard id="action_move_journal_line_form" menu="False" model="account.move.line" name="account.move.journal" string="Entries by Line"/>
|
||||
<menuitem icon="STOCK_JUSTIFY_FILL" action="action_move_journal_line_form" id="menu_action_move_journal_line_form" parent="account.menu_finance_entries" type="wizard" sequence="5"/>
|
||||
|
||||
-->
|
||||
<!--
|
||||
Entries lines
|
||||
-->
|
||||
|
@ -1007,9 +1007,9 @@
|
|||
<menuitem action="action_move_line_search" id="menu_action_move_line_search" parent="account.next_id_29"/>
|
||||
|
||||
<menuitem id="menu_finance_charts" name="Charts" parent="account.menu_finance" sequence="4"/>
|
||||
<wizard id="wizard_account_chart" menu="False" model="account.account" name="account.chart" string="Chart of Accounts"/>
|
||||
<!-- <wizard id="wizard_account_chart" menu="False" model="account.account" name="account.chart" string="Chart of Accounts"/>
|
||||
<menuitem icon="STOCK_INDENT" action="wizard_account_chart" id="menu_action_account_tree2" parent="account.menu_finance_charts" type="wizard"/>
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<record id="view_bank_statement_reconcile_form" model="ir.ui.view">
|
||||
|
@ -1079,8 +1079,14 @@
|
|||
groups="group_account_user"/>
|
||||
|
||||
<menuitem action="action_bank_statement_reconciliation_form" id="menu_action_account_bank_reconcile_tree" parent="next_id_30"/>
|
||||
<wizard id="action_account_bank_reconcile_tree" menu="False" model="account.move.line" name="account.move.bank.reconcile" string="Bank reconciliation"/>
|
||||
<menuitem action="action_account_bank_reconcile_tree" id="menu_action_account_bank_reconcile_check_tree" parent="account.next_id_30" type="wizard"/>
|
||||
<!-- <wizard id="action_account_bank_reconcile_tree" menu="False" model="account.move.line" name="account.move.bank.reconcile" string="Bank reconciliation"/> -->
|
||||
<!-- <menuitem action="action_account_bank_reconcile_tree" id="menu_action_account_bank_reconcile_check_tree" parent="account.next_id_30" type="wizard"/> -->
|
||||
|
||||
<!-- bank reconsilation -->
|
||||
<menuitem action="action_account_bank_reconcile_tree"
|
||||
id="menu_action_account_bank_reconcile_check_tree"
|
||||
parent="account.next_id_30" />
|
||||
|
||||
|
||||
<act_window
|
||||
domain="[('account_id', '=', active_id)]"
|
||||
|
|
|
@ -7,7 +7,14 @@
|
|||
name="account.balance.account.balance.report"
|
||||
keyword="client_print_multi"
|
||||
id="wizard_account_balance_compare_report"/>
|
||||
<wizard id="wizard_invoice_refund" model="account.invoice" name="account.invoice.refund" string="Credit Note" groups="base.group_user"/>
|
||||
|
||||
<!-- <wizard id="wizard_invoice_refund" model="account.invoice" name="account.invoice.refund" string="Credit Note" groups="base.group_user"/> -->
|
||||
|
||||
<!-- <wizard id="wizard_invoice_refund" model="account.invoice" name="account.invoice.refund" string="Credit Note" groups="base.group_user"/>-->
|
||||
|
||||
<!-- for test only -->
|
||||
|
||||
|
||||
|
||||
<wizard id="wizard_invoice_pay" model="account.invoice" name="account.invoice.pay" string="Pay invoice" groups="base.group_user"/>
|
||||
|
||||
|
@ -21,8 +28,9 @@
|
|||
type="wizard"
|
||||
sequence="1"/>
|
||||
|
||||
<wizard id="wizard_fiscalyear_close_state" menu="False" model="account.fiscalyear" name="account.fiscalyear.close.state" string="Close a Fiscal Year"/>
|
||||
<!-- <wizard id="wizard_fiscalyear_close_state" menu="False" model="account.fiscalyear" name="account.fiscalyear.close.state" string="Close a Fiscal Year"/>
|
||||
<menuitem action="wizard_fiscalyear_close_state" id="menu_wizard_fy_close_state" parent="menu_account_end_year_treatments" type="wizard"/>
|
||||
-->
|
||||
|
||||
<wizard
|
||||
id="wizard_open_closed_fiscalyear"
|
||||
|
@ -35,12 +43,19 @@
|
|||
id="menu_wizard_open_closed_fy"
|
||||
sequence="2"
|
||||
parent="account.menu_account_end_year_treatments" type="wizard"/>
|
||||
<!-- period close
|
||||
|
||||
<wizard id="wizard_period_close" model="account.period" name="account.period.close" string="Close a Period"/>
|
||||
|
||||
<wizard id="wizard_period_close" model="account.period" name="account.period.close" string="Close a Period"/>
|
||||
|
||||
<wizard id="action_account_period_close" model="account.period" name="account.period.close" string="Close a Period"/>
|
||||
|
||||
|
||||
-->
|
||||
<!-- automatic reconcile -->
|
||||
<wizard id="wizard_automatic_reconcile" menu="False" model="account.account" name="account.automatic.reconcile" string="Automatic reconciliation"/>
|
||||
<menuitem id="next_id_20" name="Reconciliation" parent="menu_finance_periodical_processing"/><menuitem action="wizard_automatic_reconcile" id="menu_automatic_reconcile" parent="next_id_20" type="wizard"/>
|
||||
<menuitem id="next_id_20" name="Reconciliation" parent="menu_finance_periodical_processing"/>
|
||||
<menuitem action="wizard_automatic_reconcile" id="menu_automatic_reconcile" parent="next_id_20" type="wizard"/>
|
||||
|
||||
<!-- Import entry in statement -->
|
||||
|
||||
|
@ -57,19 +72,24 @@
|
|||
<wizard id="wizard_reconcile_unreconcile" model="account.move.reconcile" name="account.reconcile.unreconcile" string="Unreconcile Entries"/>
|
||||
|
||||
|
||||
<wizard id="wizard_reconcile_select" menu="False" model="account.move.line" name="account.move.line.reconcile.select" string="Reconcile entries"/>
|
||||
<!-- <wizard id="wizard_reconcile_select" menu="False" model="account.move.line" name="account.move.line.reconcile.select" string="Reconcile entries"/>
|
||||
<menuitem action="wizard_reconcile_select" id="menu_reconcile_select" parent="account.next_id_20" type="wizard"/>
|
||||
-->
|
||||
|
||||
<!-- unreconcile -->
|
||||
<wizard id="wizard_unreconcile" model="account.move.line" name="account.move.line.unreconcile" string="Unreconcile Entries"/>
|
||||
|
||||
<!-- unreconcile
|
||||
|
||||
<wizard id="wizard_unreconcile_select" menu="False" model="account.move.line" name="account.move.line.unreconcile.select" string="Unreconcile entries"/>
|
||||
<menuitem action="wizard_unreconcile_select" id="menu_unreconcile_select" parent="account.next_id_20" type="wizard"/>
|
||||
-->
|
||||
|
||||
<!-- subscriptions -->
|
||||
<!--
|
||||
<wizard id="wizard_generate_subscription" menu="False" model="account.subscription" name="account.subscription.generate" string="Create subscription entries"/>
|
||||
<menuitem action="wizard_generate_subscription" id="menu_generate_subscription" parent="account.menu_finance_periodical_processing" type="wizard"/>
|
||||
|
||||
-->
|
||||
<!-- Aged partner balance -->
|
||||
<wizard id="wizard_aged_trial_balance" menu="False" model="res.partner" name="account.aged.trial.balance" string="Aged Partner Balance"/>
|
||||
<menuitem id="next_id_22" name="Partner Accounts" parent="menu_finance_generic_reporting" sequence="1"/>
|
||||
|
|
|
@ -204,10 +204,14 @@
|
|||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="view_account_analytic_line_tree"/>
|
||||
</record>
|
||||
<wizard id="action_account_analytic_line" menu="False" model="account.analytic.line" name="account.analytic.line" string="Entries by Line"/>
|
||||
<wizard id="action_account_analytic_line" menu="False" model="account.analytic.line" name="account.analytic.line" string="Entries by Line"/>
|
||||
<menuitem id="next_id_41" name="Analytic Entries" parent="account.menu_finance_entries"/>
|
||||
<menuitem type="wizard" icon="STOCK_JUSTIFY_FILL" action="action_account_analytic_line" id="account_entries_analytic_entries" parent="next_id_41"/>
|
||||
<!-- Entries by Line -->
|
||||
|
||||
<menuitem icon="STOCK_JUSTIFY_FILL"
|
||||
action="action_project_account_analytic_line_form"
|
||||
id="account_entries_analytic_entries"
|
||||
parent="next_id_41"/>
|
||||
|
||||
<record id="action_account_tree1" model="ir.actions.act_window">
|
||||
<field name="name">Analytic Entries</field>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
|
@ -15,7 +15,7 @@
|
|||
# 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/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
@ -25,7 +25,7 @@ import wizard_account_analytic_inverted_balance_report
|
|||
import wizard_account_analytic_cost_ledger_report
|
||||
import wizard_account_analytic_cost_ledger_for_journal_report
|
||||
import wizard_account_analytic_analytic_check
|
||||
import wizard_account_analytic_line
|
||||
import project_account_analytic_line
|
||||
import wizard_analytic_account_chart
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
from tools.translate import _
|
||||
|
||||
class project_account_analytic_line(osv.osv_memory):
|
||||
_name = "project.account.analytic.line"
|
||||
_description = "Analytic Entries by line"
|
||||
_columns = {
|
||||
'from_date': fields.date('From'),
|
||||
'to_date': fields.date('To'),
|
||||
}
|
||||
|
||||
def action_open_window(self, cr, uid, ids, context={}):
|
||||
mod_obj =self.pool.get('ir.model.data')
|
||||
domain = []
|
||||
for data in self.read(cr, uid, ids, context=context):
|
||||
from_date = data['from_date']
|
||||
to_date = data['to_date']
|
||||
if from_date and to_date:
|
||||
domain = [('date','>=',from_date), ('date','<=',to_date)]
|
||||
elif from_date:
|
||||
domain = [('date','>=',from_date)]
|
||||
elif to_date:
|
||||
domain = [('date','<=',to_date)]
|
||||
result = mod_obj._get_id(cr, uid, 'account', 'view_account_analytic_line_filter')
|
||||
id = mod_obj.read(cr, uid, result, ['res_id'], context=context)
|
||||
return {
|
||||
'name': _('Analytic Entries by line'),
|
||||
'view_type': 'form',
|
||||
"view_mode": 'tree,form',
|
||||
'res_model': 'account.analytic.line',
|
||||
'type': 'ir.actions.act_window',
|
||||
'domain': domain,
|
||||
'search_view_id': id['res_id'],
|
||||
}
|
||||
|
||||
project_account_analytic_line()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_project_account_analytic_line_form" model="ir.ui.view">
|
||||
<field name="name">project.account.analytic.line.form</field>
|
||||
<field name="model">project.account.analytic.line</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="View Account Analytic Lines">
|
||||
<group colspan="4" >
|
||||
<field name="from_date"/>
|
||||
<newline/>
|
||||
<field name="to_date" />
|
||||
</group>
|
||||
<label string ="(Keep empty to open the current situation)" />
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
|
||||
<button icon="gtk-execute" string="Open Entries" name="action_open_window" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_project_account_analytic_line_form" model="ir.actions.act_window">
|
||||
<field name="name">Entries By Line</field>
|
||||
<field name="res_model">project.account.analytic.line</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_project_account_analytic_line_form"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,84 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
import pooler
|
||||
import time
|
||||
from tools.translate import _
|
||||
|
||||
def _action_open_window(self, cr, uid, data, context):
|
||||
domain = []
|
||||
from_date = data['form']['from_date']
|
||||
to_date = data['form']['to_date']
|
||||
if from_date and to_date:
|
||||
domain = [('date','>=',from_date),('date','<=',to_date)]
|
||||
elif from_date:
|
||||
domain = [('date','>=',from_date)]
|
||||
elif to_date:
|
||||
domain = [('date','<=',to_date)]
|
||||
mod_obj = pooler.get_pool(cr.dbname).get('ir.model.data')
|
||||
result = mod_obj._get_id(cr, uid, 'account', 'view_account_analytic_line_filter')
|
||||
id = mod_obj.read(cr, uid, result, ['res_id'])
|
||||
|
||||
return {
|
||||
'name': _('Analytic Entries by line'),
|
||||
'view_type': 'form',
|
||||
"view_mode": 'tree,form',
|
||||
'res_model': 'account.analytic.line',
|
||||
'type': 'ir.actions.act_window',
|
||||
'domain': domain,
|
||||
'search_view_id': id['res_id'],}
|
||||
|
||||
|
||||
class account_analytic_line(wizard.interface):
|
||||
form1 = '''<?xml version="1.0"?>
|
||||
<form string="View Account Analytic Lines">
|
||||
<separator string="Account Analytic Lines Analysis" colspan="4"/>
|
||||
<field name="from_date"/>
|
||||
<newline/>
|
||||
<field name="to_date"/>
|
||||
<newline/>
|
||||
<label string=""/>
|
||||
<label string="(Keep empty to open the current situation)" align="0.0" colspan="3"/>
|
||||
</form>'''
|
||||
form1_fields = {
|
||||
'from_date': {
|
||||
'string': 'From',
|
||||
'type': 'date',
|
||||
},
|
||||
'to_date': {
|
||||
'string': 'To',
|
||||
'type': 'date',
|
||||
},
|
||||
}
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type': 'form', 'arch':form1, 'fields':form1_fields, 'state': [('end', 'Cancel','gtk-cancel'),('open', 'Open Entries','gtk-ok')]}
|
||||
},
|
||||
'open': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action': _action_open_window, 'state':'end'}
|
||||
}
|
||||
}
|
||||
account_analytic_line('account.analytic.line')
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
|
@ -15,40 +15,36 @@
|
|||
# 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/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import wizard_automatic_reconcile
|
||||
import wizard_reconcile_select
|
||||
import wizard_unreconcile_select
|
||||
import account_move_line_reconcile_select
|
||||
import account_move_line_unreconcile_select
|
||||
import wizard_reconcile
|
||||
import wizard_unreconcile
|
||||
import wizard_refund
|
||||
import account_invoice_refund
|
||||
import wizard_pay_invoice
|
||||
|
||||
import wizard_journal
|
||||
import account_move_journal
|
||||
import wizard_journal_select
|
||||
import wizard_bank_reconcile
|
||||
import wizard_subscription_generate
|
||||
|
||||
import account_move_bank_reconcile
|
||||
import account_subscription_generate
|
||||
import wizard_aged_trial_balance
|
||||
import wizard_general_ledger_report
|
||||
import wizard_third_party_ledger
|
||||
import wizard_account_balance_report
|
||||
import wizard_partner_balance_report
|
||||
|
||||
import wizard_period_close
|
||||
import account_period_close
|
||||
import wizard_fiscalyear_close
|
||||
import wizard_fiscalyear_close_state
|
||||
import account_fiscalyear_close_state
|
||||
import wizard_open_closed_fiscalyear
|
||||
|
||||
import wizard_vat
|
||||
import wizard_compare_account_balance_report
|
||||
|
||||
import wizard_invoice_state
|
||||
import wizard_account_duplicate
|
||||
import wizard_account_chart
|
||||
import account_chart
|
||||
import wizard_move_line_select
|
||||
|
||||
import wizard_validate_account_move
|
||||
|
@ -64,5 +60,4 @@ import wizard_change_currency
|
|||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
from tools.translate import _
|
||||
import tools
|
||||
|
||||
class account_chart(osv.osv_memory):
|
||||
"""
|
||||
For Chart of Accounrs
|
||||
"""
|
||||
_name = "account.chart"
|
||||
_description = "chart"
|
||||
_columns = {
|
||||
'fiscalyear': fields.many2one('account.fiscalyear', \
|
||||
'Fiscal year', \
|
||||
help = 'Keep empty for all open fiscal years'),
|
||||
'target_move': fields.selection([
|
||||
('all', 'All Entries'),
|
||||
('posted', 'All Posted Entries'),
|
||||
], 'Target Moves', required = True),
|
||||
|
||||
}
|
||||
def _get_defaults(self, cr, uid, context={}):
|
||||
"""Return default Fiscalyear value"""
|
||||
fiscalyear_obj = self.pool.get('account.fiscalyear')
|
||||
fiscalyear = fiscalyear_obj.find(cr, uid)
|
||||
return fiscalyear
|
||||
|
||||
def account_chart_open_window(self, cr, uid, ids, context={}):
|
||||
"""
|
||||
Opens chart of Accounts
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of account chart’s IDs
|
||||
@return: dictionary of Open account chart window on given fiscalyear and all Entries or posted entries
|
||||
"""
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
act_obj = self.pool.get('ir.actions.act_window')
|
||||
for data in self.read(cr, uid, ids,context=context):
|
||||
result = mod_obj._get_id(cr, uid, 'account', 'action_account_tree')
|
||||
id = mod_obj.read(cr, uid, [result], ['res_id'],context=context)[0]['res_id']
|
||||
result = act_obj.read(cr, uid, [id], context=context)[0]
|
||||
result['context'] = str({'fiscalyear': data['fiscalyear'], \
|
||||
'state': data['target_move']})
|
||||
if data['fiscalyear']:
|
||||
result['name'] += ':' + self.pool.get('account.fiscalyear').read(cr, uid, [data['fiscalyear']],context=context)[0]['code']
|
||||
return result
|
||||
|
||||
|
||||
_defaults = {
|
||||
'fiscalyear': _get_defaults,
|
||||
'target_move': lambda * a: 'all'
|
||||
}
|
||||
account_chart()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_account_chart" model="ir.ui.view">
|
||||
<field name="name">account.chart.form</field>
|
||||
<field name="model">account.chart</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Account charts">
|
||||
<group colspan="4" >
|
||||
<field name="fiscalyear"/>
|
||||
<label align="0.7" colspan="6" string="(If you do not select Fiscal year it will take all open fiscal years)"/>
|
||||
<field name="target_move"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<label string ="" colspan="2"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel" />
|
||||
<button icon="gtk-open" string="Open Charts"
|
||||
name="account_chart_open_window" type="object" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_chart" model="ir.actions.act_window">
|
||||
<field name="name">Chart of Accounts</field>
|
||||
<field name="res_model">account.chart</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_account_chart"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem icon="STOCK_INDENT" action="action_account_chart"
|
||||
id="menu_action_account_tree2"
|
||||
parent="account.menu_finance_charts" />
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,65 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
from tools.translate import _
|
||||
import tools
|
||||
|
||||
class account_fiscalyear_close_state(osv.osv_memory):
|
||||
"""
|
||||
Closes Account Fiscalyear
|
||||
"""
|
||||
_name = "account.fiscalyear.close.state"
|
||||
_description = "Fiscalyear Close state"
|
||||
_columns = {
|
||||
'fy_id': fields.many2one('account.fiscalyear', \
|
||||
'Fiscal Year to close', required=True),
|
||||
'sure': fields.boolean('Check this box', required=False)
|
||||
}
|
||||
|
||||
def data_save(self, cr, uid, ids, context={}):
|
||||
"""
|
||||
This function close account fiscalyear
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Account fiscalyear close state’s IDs
|
||||
|
||||
"""
|
||||
for data in self.read(cr, uid, ids,context=context):
|
||||
if not data['sure']:
|
||||
raise osv.except_osv(_('UserError'), _('Closing of states \
|
||||
cancelled, please check the box !'))
|
||||
fy_id = data['fy_id']
|
||||
|
||||
cr.execute('UPDATE account_journal_period ' \
|
||||
'SET state = %s ' \
|
||||
'WHERE period_id IN (SELECT id FROM account_period \
|
||||
WHERE fiscalyear_id = %s)',
|
||||
('done', fy_id))
|
||||
cr.execute('UPDATE account_period SET state = %s ' \
|
||||
'WHERE fiscalyear_id = %s', ('done', fy_id))
|
||||
cr.execute('UPDATE account_fiscalyear ' \
|
||||
'SET state = %s WHERE id = %s', ('done', fy_id))
|
||||
return {}
|
||||
|
||||
account_fiscalyear_close_state()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_account_fiscalyear_close_state" model="ir.ui.view">
|
||||
<field name="name">account.fiscalyear.close.state.form</field>
|
||||
<field name="model">account.fiscalyear.close.state</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Close states of Fiscal year and periods">
|
||||
<group colspan="4" >
|
||||
<field name="fy_id" domain = "[('state','=','draft')]"/>
|
||||
<separator string="Are you sure you want to close the fiscal year ?" colspan="4"/>
|
||||
<field name="sure"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<label string ="" colspan="2"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
|
||||
<button icon="gtk-close" string="Close states" name="data_save" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_fiscalyear_close_state" model="ir.actions.act_window">
|
||||
<field name="name">Close a Fiscal Year</field>
|
||||
<field name="res_model">account.fiscalyear.close.state</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_account_fiscalyear_close_state"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_account_fiscalyear_close_state"
|
||||
id="menu_wizard_fy_close_state"
|
||||
parent="menu_account_end_year_treatments" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,191 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
from tools.translate import _
|
||||
import tools
|
||||
import netsvc
|
||||
|
||||
|
||||
class account_invoice_refund(osv.osv_memory):
|
||||
|
||||
"""Refunds invoice."""
|
||||
|
||||
_name = "account.invoice.refund"
|
||||
_description = "Invoice Refund"
|
||||
_columns = {
|
||||
'date': fields.date('Operation date', required=False),
|
||||
'period': fields.many2one('account.period', 'Force period', required=False),
|
||||
'description': fields.char('Description', size=150, required=True),
|
||||
}
|
||||
|
||||
def compute_refund(self, cr, uid, ids, mode, context={}):
|
||||
"""
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: the account invoice refund’s ID or list of IDs
|
||||
|
||||
"""
|
||||
inv_obj = self.pool.get('account.invoice')
|
||||
reconcile_obj = self.pool.get('account.move.reconcile')
|
||||
account_m_line_obj = self.pool.get('account.move.line')
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
act_obj = self.pool.get('ir.actions.act_window')
|
||||
for form in self.read(cr, uid, ids,context=context):
|
||||
created_inv = []
|
||||
date = False
|
||||
period = False
|
||||
description = False
|
||||
for inv in inv_obj.browse(cr, uid, context['active_ids'],context=context):
|
||||
if inv.state in ['draft', 'proforma2', 'cancel']:
|
||||
raise osv.except_osv(_('Error !'), _('Can not %s draft/proforma/cancel invoice.') % (mode))
|
||||
if form['period'] :
|
||||
period = form['period']
|
||||
else:
|
||||
period = inv.period_id and inv.period_id.id or False
|
||||
|
||||
if form['date'] :
|
||||
date = form['date']
|
||||
if not form['period'] :
|
||||
cr.execute("select name from ir_model_fields \
|
||||
where model = 'account.period' \
|
||||
and name = 'company_id'")
|
||||
result_query = cr.fetchone()
|
||||
if result_query:
|
||||
cr.execute("""SELECT id
|
||||
from account_period where date('%s')
|
||||
between date_start AND date_stop \
|
||||
and company_id = %s limit 1 """,
|
||||
(form['date'], self.pool.get('res.users').browse(cr, uid, uid,context=context).company_id.id,))
|
||||
else:
|
||||
cr.execute("""SELECT id
|
||||
from account_period where date('%s')
|
||||
between date_start AND date_stop \
|
||||
limit 1 """, (form['date'],))
|
||||
res = cr.fetchone()
|
||||
if res:
|
||||
period = res[0]
|
||||
else:
|
||||
date = inv.date_invoice
|
||||
|
||||
if form['description'] :
|
||||
description = form['description']
|
||||
else:
|
||||
description = inv.name
|
||||
|
||||
if not period:
|
||||
raise osv.except_osv(_('Data Insufficient !'), \
|
||||
_('No Period found on Invoice!'))
|
||||
|
||||
refund_id = inv_obj.refund(cr, uid, [inv.id], date, period, description)
|
||||
refund = inv_obj.browse(cr, uid, refund_id[0],context=context)
|
||||
inv_obj.write(cr, uid, [refund.id], {'date_due': date,
|
||||
'check_total': inv.check_total})
|
||||
inv_obj.button_compute(cr, uid, refund_id)
|
||||
|
||||
created_inv.append(refund_id[0])
|
||||
if mode in ('cancel', 'modify'):
|
||||
movelines = inv.move_id.line_id
|
||||
to_reconcile_ids = {}
|
||||
for line in movelines :
|
||||
if line.account_id.id == inv.account_id.id :
|
||||
to_reconcile_ids[line.account_id.id] = [line.id]
|
||||
if type(line.reconcile_id) != osv.orm.browse_null :
|
||||
reconcile_obj.unlink(cr, uid, line.reconcile_id.id)
|
||||
wf_service = netsvc.LocalService('workflow')
|
||||
wf_service.trg_validate(uid, 'account.invoice', \
|
||||
refund.id, 'invoice_open', cr)
|
||||
refund = inv_obj.browse(cr, uid, refund_id[0],context=context)
|
||||
for tmpline in refund.move_id.line_id :
|
||||
if tmpline.account_id.id == inv.account_id.id :
|
||||
to_reconcile_ids[tmpline.account_id.id].append(tmpline.id)
|
||||
for account in to_reconcile_ids :
|
||||
account_m_line_obj.reconcile(cr, uid, to_reconcile_ids[account],
|
||||
writeoff_period_id=period,
|
||||
writeoff_journal_id=inv.journal_id.id,
|
||||
writeoff_acc_id=inv.account_id.id
|
||||
)
|
||||
if mode == 'modify' :
|
||||
invoice = inv_obj.read(cr, uid, [inv.id],
|
||||
['name', 'type', 'number', 'reference',
|
||||
'comment', 'date_due', 'partner_id',
|
||||
'address_contact_id', 'address_invoice_id',
|
||||
'partner_insite', 'partner_contact',
|
||||
'partner_ref', 'payment_term', 'account_id',
|
||||
'currency_id', 'invoice_line', 'tax_line',
|
||||
'journal_id', 'period_id'],context=context)
|
||||
invoice = invoice[0]
|
||||
del invoice['id']
|
||||
invoice_lines = self.pool.get('account.invoice.line').read(cr, uid, invoice['invoice_line'],context=context)
|
||||
invoice_lines = inv_obj._refund_cleanup_lines(cr, uid, invoice_lines)
|
||||
tax_lines = self.pool.get('account.invoice.tax').read(
|
||||
cr, uid, invoice['tax_line'],context=context)
|
||||
tax_lines = inv_obj._refund_cleanup_lines(cr, uid, tax_lines)
|
||||
|
||||
invoice.update({
|
||||
'type': inv.type,
|
||||
'date_invoice': date,
|
||||
'state': 'draft',
|
||||
'number': False,
|
||||
'invoice_line': invoice_lines,
|
||||
'tax_line': tax_lines,
|
||||
'period_id': period,
|
||||
'name': description
|
||||
})
|
||||
|
||||
for field in ('address_contact_id', 'address_invoice_id', 'partner_id',
|
||||
'account_id', 'currency_id', 'payment_term', 'journal_id'):
|
||||
invoice[field] = invoice[field] and invoice[field][0]
|
||||
|
||||
inv_id = inv_obj.create(cr, uid, invoice, {})
|
||||
if inv.payment_term.id:
|
||||
data = inv_obj.onchange_payment_term_date_invoice(cr, uid, [inv_id], inv.payment_term.id, date)
|
||||
if 'value' in data and data['value']:
|
||||
inv_obj.write(cr, uid, [inv_id], data['value'])
|
||||
created_inv.append(inv_id)
|
||||
|
||||
if inv.type == 'out_invoice':
|
||||
xml_id = 'action_invoice_tree1'
|
||||
elif inv.type == 'in_invoice':
|
||||
xml_id = 'action_invoice_tree2'
|
||||
elif type == 'out_refund':
|
||||
xml_id = 'action_invoice_tree3'
|
||||
else:
|
||||
xml_id = 'action_invoice_tree4'
|
||||
result = mod_obj._get_id(cr, uid, 'account', xml_id)
|
||||
id = mod_obj.read(cr, uid, result, ['res_id'],context=context)['res_id']
|
||||
result = act_obj.read(cr, uid, id,context=context)
|
||||
result['res_id'] = created_inv
|
||||
|
||||
return result
|
||||
|
||||
def invoice_refund(self, cr, uid, ids, context={}):
|
||||
return self.compute_refund(cr, uid, ids, 'refund', context=context)
|
||||
|
||||
def invoice_cancel(self, cr, uid, ids, context={}):
|
||||
return self.compute_refund(cr, uid, ids, 'cancel', context=context)
|
||||
|
||||
def invoice_modify(self, cr, uid, ids, context={}):
|
||||
return self.compute_refund(cr, uid, ids, 'modify', context=context)
|
||||
|
||||
account_invoice_refund()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_account_invoice_refund" model="ir.ui.view">
|
||||
<field name="name">account.invoice.refund.form</field>
|
||||
<field name="model">account.invoice.refund</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Credit Note">
|
||||
<group colspan="4" >
|
||||
<label string="Are you sure you want to refund this invoice ?" colspan="2"/>
|
||||
<newline/>
|
||||
<field name="date"/>
|
||||
<field name="period"/>
|
||||
<field name="description"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<label string ="" colspan="2"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
|
||||
<button icon="gtk-redo" string="Refund Invoice" name="invoice_refund" type="object"/>
|
||||
<button icon="gtk-ok" string="Cancel Invoice" name="invoice_cancel" type="object"/>
|
||||
<button icon="gtk-undo" string="Modify Invoice" name="invoice_modify" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_invoice_refund" model="ir.actions.act_window">
|
||||
<field name="name">Credit Note</field>
|
||||
<field name="res_model">account.invoice.refund</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_account_invoice_refund"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<act_window id="action_account_invoice_refund"
|
||||
key2 = "client_action_multi" name="Credit Note"
|
||||
res_model="account.invoice.refund" src_model="account.invoice"
|
||||
view_mode="form" target="new" view_type="form" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,63 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 tools
|
||||
from osv import fields, osv
|
||||
from tools.translate import _
|
||||
|
||||
|
||||
class account_move_bank_reconcile(osv.osv_memory):
|
||||
"""
|
||||
Bank Reconciliation
|
||||
"""
|
||||
_name = "account.move.bank.reconcile"
|
||||
_description = "Move bank reconcile"
|
||||
_columns = {
|
||||
'journal_id': fields.many2one('account.journal', 'Journal', required=True),
|
||||
}
|
||||
|
||||
def action_open_window(self, cr, uid, ids, context={}):
|
||||
"""
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: account move bank reconcile’s ID or list of IDs
|
||||
@return: dictionary of Open account move line on given journal_id.
|
||||
"""
|
||||
for data in self.read(cr, uid, ids,context=context):
|
||||
cr.execute('select default_credit_account_id \
|
||||
from account_journal where id=%s', (data['journal_id'],))
|
||||
account_id = cr.fetchone()[0]
|
||||
if not account_id:
|
||||
raise osv.except_osv(_('Error'), _('You have to define \
|
||||
the bank account\nin the journal definition for reconciliation.'))
|
||||
return {
|
||||
'domain': "[('journal_id','=',%d), ('account_id','=',%d), ('state','<>','draft')]" % (data['journal_id'], account_id),
|
||||
'name': _('Standard Encoding'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'account.move.line',
|
||||
'view_id': False,
|
||||
'context': "{'journal_id': %d}" % (data['journal_id'],),
|
||||
'type': 'ir.actions.act_window'
|
||||
}
|
||||
|
||||
account_move_bank_reconcile()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_account_move_bank_reconcile" model="ir.ui.view">
|
||||
<field name="name">account.move.bank.reconcile.form</field>
|
||||
<field name="model">account.move.bank.reconcile</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Bank reconciliation">
|
||||
<group colspan="4" >
|
||||
<field name="journal_id"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<label string ="" colspan="2"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
|
||||
<button icon="gtk-open" string="Open for bank reconciliation" name="action_open_window" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_bank_reconcile_tree" model="ir.actions.act_window">
|
||||
<field name="name">Bank reconciliation</field>
|
||||
<field name="res_model">account.move.bank.reconcile</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_account_move_bank_reconcile"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,98 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
from tools.translate import _
|
||||
import tools
|
||||
|
||||
class account_move_journal(osv.osv_memory):
|
||||
_name = "account.move.journal"
|
||||
_description = "Move journal"
|
||||
|
||||
_columns = {
|
||||
'journal_id': fields.many2one('account.journal', 'Journal', required=True),
|
||||
'period_id': fields.many2one('account.period', 'Period', required=True),
|
||||
}
|
||||
|
||||
|
||||
def _get_period(self, cr, uid, context={}):
|
||||
"""Return default account period value"""
|
||||
ids = self.pool.get('account.period').find(cr, uid, context=context)
|
||||
period_id = False
|
||||
if len(ids):
|
||||
period_id = ids[0]
|
||||
return period_id
|
||||
|
||||
def action_open_window(self, cr, uid, ids, context={}):
|
||||
"""
|
||||
This function Open action move line window on given period and Journal/Payment Mode
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: account move journal’s ID or list of IDs
|
||||
@return: dictionary of Open action move line window on given period and Journal/Payment Mode
|
||||
|
||||
"""
|
||||
jp = self.pool.get('account.journal.period')
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
for data in self.read(cr, uid, ids, ['journal_id', 'period_id'],context=context):
|
||||
cr.execute('select id,name from ir_ui_view where model=%s and type=%s', ('account.move.line', 'form'))
|
||||
view_res = cr.fetchone()
|
||||
journal_id = data['journal_id']
|
||||
period_id = data['period_id']
|
||||
|
||||
ids = jp.search(cr, uid, [('journal_id', '=', journal_id), \
|
||||
('period_id', '=', period_id)],context=context)
|
||||
|
||||
if not len(ids):
|
||||
name = self.pool.get('account.journal').read(cr, uid, [journal_id])[0]['name']
|
||||
state = self.pool.get('account.period').read(cr, uid, [period_id])[0]['state']
|
||||
if state == 'done':
|
||||
raise osv.except_osv(_('UserError'), _('This period is already closed !'))
|
||||
company = self.pool.get('account.period').read(cr, uid, [period_id])[0]['company_id'][0]
|
||||
jp.create(cr, uid, {'name': name, 'period_id': period_id, 'journal_id': journal_id, 'company_id': company},context=context)
|
||||
|
||||
ids = jp.search(cr, uid, [('journal_id', '=', journal_id), ('period_id', '=', period_id)],context=context)
|
||||
jp = jp.browse(cr, uid, ids, context=context)[0]
|
||||
name = (jp.journal_id.code or '') + ':' + (jp.period_id.code or '')
|
||||
|
||||
result = mod_obj._get_id(cr, uid, 'account', 'view_account_move_line_filter')
|
||||
res = mod_obj.read(cr, uid, result, ['res_id'],context=context)
|
||||
|
||||
return {
|
||||
'domain': "[('journal_id','=',%d), ('period_id','=',%d)]" % (journal_id, period_id),
|
||||
'name': name,
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'account.move.line',
|
||||
'view_id': view_res,
|
||||
'context': "{'journal_id': %d, 'period_id': %d}" % (journal_id, period_id),
|
||||
'type': 'ir.actions.act_window',
|
||||
'search_view_id': res['res_id']
|
||||
}
|
||||
|
||||
|
||||
_defaults = {
|
||||
'period_id': _get_period
|
||||
}
|
||||
|
||||
account_move_journal()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_account_move_journal_form" model="ir.ui.view">
|
||||
<field name="name">account.move.journal.form</field>
|
||||
<field name="model">account.move.journal</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Standard entries">
|
||||
<group colspan="4" >
|
||||
<field name="journal_id"/>
|
||||
<newline/>
|
||||
<field name="period_id" />
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<label string ="" colspan="2"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
|
||||
<button icon="gtk-open" string="Open Journal" name="action_open_window" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_move_journal_line_form" model="ir.actions.act_window">
|
||||
<field name="name">Entries by Line</field>
|
||||
<field name="res_model">account.move.journal</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_account_move_journal_form"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem icon="STOCK_JUSTIFY_FILL"
|
||||
action="action_account_move_journal_line_form"
|
||||
id="menu_action_move_journal_line_form"
|
||||
parent="account.menu_finance_entries" sequence="5" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,58 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
from tools.translate import _
|
||||
import tools
|
||||
|
||||
|
||||
class account_move_line_reconcile_select(osv.osv_memory):
|
||||
_name = "account.move.line.reconcile.select"
|
||||
_description = "Move line reconcile select"
|
||||
_columns = {
|
||||
'account_id': fields.many2one('account.account', 'Account', \
|
||||
domain = [('reconcile', '=', 1)], required=True),
|
||||
}
|
||||
|
||||
def action_open_window(self, cr, uid, ids, context={}):
|
||||
"""
|
||||
This function Open account move line window for reconcile on given account id
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: account move line reconcile select’s ID or list of IDs
|
||||
@return: dictionary of Open account move line window for reconcile on given account id
|
||||
|
||||
"""
|
||||
for data in self.read(cr, uid, ids,context=context):
|
||||
|
||||
return {
|
||||
'domain': "[('account_id','=',%d),('reconcile_id','=',False),('state','<>','draft')]" % data['account_id'],
|
||||
'name': _('Reconciliation'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'view_id': False,
|
||||
'res_model': 'account.move.line',
|
||||
'type': 'ir.actions.act_window'
|
||||
}
|
||||
|
||||
account_move_line_reconcile_select()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_account_move_line_reconcile_select" model="ir.ui.view">
|
||||
<field name="name">account.move.line.reconcile.select.form</field>
|
||||
<field name="model">account.move.line.reconcile.select</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Reconciliation">
|
||||
<group colspan="4" >
|
||||
<field name="account_id"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<label string ="" colspan="2"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel" />
|
||||
<button icon="gtk-open"
|
||||
string="Open for reconciliation" name="action_open_window"
|
||||
type="object" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_reconcile_select" model="ir.actions.act_window">
|
||||
<field name="name">Reconcile entries</field>
|
||||
<field name="res_model">account.move.line.reconcile.select</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_account_move_line_reconcile_select"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="next_id_20" name="Reconciliation"
|
||||
parent="menu_finance_periodical_processing" />
|
||||
|
||||
<menuitem action="action_account_reconcile_select"
|
||||
id="menu_reconcile_select" parent="account.next_id_20" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,52 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
from tools.translate import _
|
||||
import tools
|
||||
|
||||
|
||||
class account_move_line_unreconcile_select(osv.osv_memory):
|
||||
|
||||
_name = "account.move.line.unreconcile.select"
|
||||
_description = "Unreconciliation"
|
||||
_columns ={
|
||||
'account_id': fields.many2one('account.account','Account',required=True),
|
||||
|
||||
}
|
||||
|
||||
def action_open_window(self, cr, uid, ids, context={}):
|
||||
for data in self.read(cr, uid, ids):
|
||||
return {
|
||||
'domain': "[('account_id','=',%d),('reconcile_id','<>',False),('state','<>','draft')]" % data['account_id'],
|
||||
'name': 'Unreconciliation',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'view_id': False,
|
||||
'res_model': 'account.move.line',
|
||||
'type': 'ir.actions.act_window'
|
||||
}
|
||||
|
||||
account_move_line_unreconcile_select()
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_account_move_line_unreconcile_select" model="ir.ui.view">
|
||||
<field name="name">account.move.line.unreconcile.select.form</field>
|
||||
<field name="model">account.move.line.unreconcile.select</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Unreconciliation">
|
||||
<group colspan="4" >
|
||||
<field name="account_id"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<label string ="" colspan="2"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel" />
|
||||
<button icon="gtk-open"
|
||||
string="Open for Unreconciliation" name="action_open_window"
|
||||
type="object" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_unreconcile_select" model="ir.actions.act_window">
|
||||
<field name="name">Unreconcile entries</field>
|
||||
<field name="res_model">account.move.line.unreconcile.select</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_account_move_line_unreconcile_select"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_account_unreconcile_select"
|
||||
id="menu_unreconcile_select" parent="account.next_id_20" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,54 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
from tools.translate import _
|
||||
import tools
|
||||
|
||||
class account_period_close(osv.osv_memory):
|
||||
"""
|
||||
close period
|
||||
"""
|
||||
_name = "account.period.close"
|
||||
_description = "period close"
|
||||
_columns = {
|
||||
'sure': fields.boolean('Check this box', required=False),
|
||||
}
|
||||
|
||||
def data_save(self, cr, uid, ids, context={}):
|
||||
"""
|
||||
This function close period
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: account period close’s ID or list of IDs
|
||||
"""
|
||||
|
||||
mode = 'done'
|
||||
for form in self.read(cr, uid, ids,context=context):
|
||||
if form['sure']:
|
||||
for id in context['active_ids']:
|
||||
cr.execute('update account_journal_period set state=%s where period_id=%s', (mode, id))
|
||||
cr.execute('update account_period set state=%s where id=%s', (mode, id))
|
||||
return {}
|
||||
|
||||
account_period_close()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_account_period_close" model="ir.ui.view">
|
||||
<field name="name">account.period.close.form</field>
|
||||
<field name="model">account.period.close</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Close Period">
|
||||
<group colspan="4" >
|
||||
<separator string="Are you sure ?" colspan="4"/>
|
||||
<field name="sure"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<label string ="" colspan="2"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
|
||||
<button icon="gtk-close" string="Close Period" name="data_save" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_period_close" model="ir.actions.act_window">
|
||||
<field name="name">Close a Period</field>
|
||||
<field name="res_model">account.period.close</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_account_period_close"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<record id="action_idea_post_vote_values" model="ir.values">
|
||||
<field name="model_id" ref="model_account_period" />
|
||||
<field name="object" eval="1" />
|
||||
<field name="name"></field>
|
||||
<field name="key2">client_action_multi</field>
|
||||
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_account_period_close'))"/>
|
||||
<field name="key">action</field>
|
||||
<field name="model">account.period</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,43 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import time
|
||||
|
||||
from osv import fields, osv
|
||||
|
||||
class account_subscription_generate(osv.osv_memory):
|
||||
|
||||
_name = "account.subscription.generate"
|
||||
_description = "Subscription Compute"
|
||||
_columns = {
|
||||
'date': fields.date('Date', required=True),
|
||||
}
|
||||
_defaults = {
|
||||
'date': lambda *a: time.strftime('%Y-%m-%d'),
|
||||
}
|
||||
def action_generate(self, cr, uid, ids, context={}):
|
||||
for data in self.read(cr, uid, ids, context=context):
|
||||
cr.execute('select id from account_subscription_line where date<%s and move_id is null', (data['date'],))
|
||||
ids = map(lambda x: x[0], cr.fetchall())
|
||||
self.pool.get('account.subscription.line').move_create(cr, uid, ids, context=context)
|
||||
return {}
|
||||
|
||||
account_subscription_generate()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_account_subscription_generate" model="ir.ui.view">
|
||||
<field name="name">account.subscription.generate.form</field>
|
||||
<field name="model">account.subscription.generate</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Subscription Compute">
|
||||
<group colspan="4" >
|
||||
<separator string="Generate entries before:" colspan="4"/>
|
||||
<field name="date"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<label string ="" colspan="2"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel" />
|
||||
<button icon="gtk-execute" string="Compute Entry Dates"
|
||||
name="action_generate" type="object" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_subscription_generate" model="ir.actions.act_window">
|
||||
<field name="name">Create Subscription Entries</field>
|
||||
<field name="res_model">account.subscription.generate</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_account_subscription_generate"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_account_subscription_generate" id="menu_generate_subscription" parent="account.menu_finance_periodical_processing" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,80 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
import pooler
|
||||
|
||||
class wizard_account_chart(wizard.interface):
|
||||
_account_chart_arch = '''<?xml version="1.0"?>
|
||||
<form string="Open account charts">
|
||||
<field name="fiscalyear"/>
|
||||
<label align="0.7" colspan="6" string="(If you do not select Fiscal year it will take all open fiscal years)"/>
|
||||
<field name="target_move"/>
|
||||
</form>'''
|
||||
|
||||
_account_chart_fields = {
|
||||
'fiscalyear': {
|
||||
'string': 'Fiscal year',
|
||||
'type': 'many2one',
|
||||
'relation': 'account.fiscalyear',
|
||||
'help': 'Keep empty for all open fiscal years',
|
||||
},
|
||||
'target_move': {
|
||||
'string': 'Target Moves',
|
||||
'type': 'selection',
|
||||
'selection': [('all','All Entries'),('posted','All Posted Entries')],
|
||||
'required': True,
|
||||
'default': lambda *a:"all",
|
||||
},
|
||||
}
|
||||
|
||||
def _get_defaults(self, cr, uid, data, context):
|
||||
fiscalyear_obj = pooler.get_pool(cr.dbname).get('account.fiscalyear')
|
||||
data['form']['fiscalyear'] = fiscalyear_obj.find(cr, uid)
|
||||
return data['form']
|
||||
|
||||
|
||||
def _account_chart_open_window(self, cr, uid, data, context):
|
||||
mod_obj = pooler.get_pool(cr.dbname).get('ir.model.data')
|
||||
act_obj = pooler.get_pool(cr.dbname).get('ir.actions.act_window')
|
||||
|
||||
result = mod_obj._get_id(cr, uid, 'account', 'action_account_tree')
|
||||
id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
|
||||
result = act_obj.read(cr, uid, [id], context=context)[0]
|
||||
result['context'] = str({'fiscalyear': data['form']['fiscalyear'],'state':data['form']['target_move']})
|
||||
if data['form']['fiscalyear']:
|
||||
result['name']+=':'+pooler.get_pool(cr.dbname).get('account.fiscalyear').read(cr,uid,[data['form']['fiscalyear']])[0]['code']
|
||||
return result
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [_get_defaults],
|
||||
'result': {'type': 'form', 'arch':_account_chart_arch, 'fields':_account_chart_fields, 'state': [('end', 'Cancel', 'gtk-cancel'), ('open', 'Open', 'gtk-ok')]}
|
||||
},
|
||||
'open': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action':_account_chart_open_window, 'state':'end'}
|
||||
}
|
||||
}
|
||||
wizard_account_chart('account.chart')
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
from tools.translate import _
|
||||
|
||||
_journal_form = '''<?xml version="1.0"?>
|
||||
<form string="%s">
|
||||
<field name="journal_id"/>
|
||||
</form>''' % ('Open Bank reconciliation',)
|
||||
|
||||
_journal_fields = {
|
||||
'journal_id': {'string':'Journal', 'type':'many2one', 'relation':'account.journal', 'required':True},
|
||||
}
|
||||
|
||||
def _action_open_window(self, cr, uid, data, context):
|
||||
form = data['form']
|
||||
cr.execute('select default_credit_account_id from account_journal where id=%s', (form['journal_id'],))
|
||||
account_id = cr.fetchone()[0]
|
||||
if not account_id:
|
||||
raise wizard.except_wizard(_('Error'), _('You have to define the bank account\nin the journal definition for reconciliation.'))
|
||||
return {
|
||||
'domain': "[('journal_id','=',%d), ('account_id','=',%d), ('state','<>','draft')]" % (form['journal_id'],account_id),
|
||||
'name': _('Standard Encoding'),
|
||||
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'account.move.line',
|
||||
'view_id': False,
|
||||
'context': "{'journal_id':%d}" % (form['journal_id'],),
|
||||
'type': 'ir.actions.act_window'
|
||||
}
|
||||
|
||||
class wiz_journal(wizard.interface):
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type': 'form', 'arch':_journal_form, 'fields':_journal_fields, 'state':[('end','Cancel', 'gtk-cancel'),('open','Open', 'gtk-ok')]}
|
||||
},
|
||||
'open': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action': _action_open_window, 'state':'end'}
|
||||
}
|
||||
}
|
||||
wiz_journal('account.move.bank.reconcile')
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
import osv
|
||||
import pooler
|
||||
from tools.translate import _
|
||||
|
||||
_transaction_form = '''<?xml version="1.0"?>
|
||||
<form string=" Close states of Fiscal year and periods">
|
||||
<field name="fy_id"/>
|
||||
<separator string="Are you sure you want to close the fiscal year ?" colspan="4"/>
|
||||
<field name="sure"/>
|
||||
</form>'''
|
||||
|
||||
_transaction_fields = {
|
||||
'fy_id': {'string':'Fiscal Year to close', 'type':'many2one', 'relation': 'account.fiscalyear','required':True, 'domain':[('state','=','draft')]},
|
||||
'sure': {'string':'Check this box', 'type':'boolean'},
|
||||
}
|
||||
|
||||
def _data_save(self, cr, uid, data, context):
|
||||
if not data['form']['sure']:
|
||||
raise wizard.except_wizard(_('UserError'), _('Closing of states cancelled, please check the box !'))
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
|
||||
fy_id = data['form']['fy_id']
|
||||
|
||||
cr.execute('UPDATE account_journal_period ' \
|
||||
'SET state = %s ' \
|
||||
'WHERE period_id IN (SELECT id FROM account_period WHERE fiscalyear_id = %s)',
|
||||
('done',fy_id))
|
||||
cr.execute('UPDATE account_period SET state = %s ' \
|
||||
'WHERE fiscalyear_id = %s', ('done',fy_id))
|
||||
cr.execute('UPDATE account_fiscalyear ' \
|
||||
'SET state = %s WHERE id = %s', ('done', fy_id))
|
||||
return {}
|
||||
|
||||
class wiz_journal_close_state(wizard.interface):
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type': 'form', 'arch':_transaction_form, 'fields':_transaction_fields, 'state':[('end','Cancel', 'gtk-cancel'),('close','Close states', 'gtk-ok')]}
|
||||
},
|
||||
'close': {
|
||||
'actions': [_data_save],
|
||||
'result': {'type': 'state', 'state':'end'}
|
||||
}
|
||||
}
|
||||
wiz_journal_close_state('account.fiscalyear.close.state')
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
from osv import osv
|
||||
import pooler
|
||||
from tools.translate import _
|
||||
|
||||
_journal_form = '''<?xml version="1.0"?>
|
||||
<form string="Standard entries">
|
||||
<field name="journal_id"/>
|
||||
<newline/>
|
||||
<field name="period_id"/>
|
||||
</form>'''
|
||||
|
||||
def _period_get(self, cr, uid, datas, ctx={}):
|
||||
try:
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
ids = pool.get('account.period').find(cr, uid, context=ctx)
|
||||
return {'period_id': ids[0]}
|
||||
except:
|
||||
return {}
|
||||
|
||||
_journal_fields = {
|
||||
'journal_id': {'string':'Journal', 'type':'many2one', 'relation':'account.journal', 'required':True},
|
||||
'period_id': {
|
||||
'string':'Period',
|
||||
'type':'many2one',
|
||||
'relation':'account.period',
|
||||
'required':True,
|
||||
}
|
||||
}
|
||||
|
||||
def _action_open_window(self, cr, uid, data, context):
|
||||
form = data['form']
|
||||
cr.execute('select id,name from ir_ui_view where model=%s and type=%s', ('account.move.line', 'form'))
|
||||
view_res = cr.fetchone()
|
||||
jp = pooler.get_pool(cr.dbname).get('account.journal.period')
|
||||
ids = jp.search(cr, uid, [('journal_id','=',form['journal_id']), ('period_id','=',form['period_id'])])
|
||||
if not len(ids):
|
||||
name = pooler.get_pool(cr.dbname).get('account.journal').read(cr, uid, [form['journal_id']])[0]['name']
|
||||
state = pooler.get_pool(cr.dbname).get('account.period').read(cr, uid, [form['period_id']])[0]['state']
|
||||
if state == 'done':
|
||||
raise wizard.except_wizard(_('UserError'), _('This period is already closed !'))
|
||||
company = pooler.get_pool(cr.dbname).get('account.period').read(cr, uid, [form['period_id']])[0]['company_id'][0]
|
||||
jp.create(cr, uid, {'name':name, 'period_id': form['period_id'], 'journal_id':form['journal_id'], 'company_id':company})
|
||||
ids = jp.search(cr, uid, [('journal_id','=',form['journal_id']), ('period_id','=',form['period_id'])])
|
||||
jp = jp.browse(cr, uid, ids, context=context)[0]
|
||||
name = (jp.journal_id.code or '') + ':' + (jp.period_id.code or '')
|
||||
|
||||
mod_obj = pooler.get_pool(cr.dbname).get('ir.model.data')
|
||||
result = mod_obj._get_id(cr, uid, 'account', 'view_account_move_line_filter')
|
||||
id = mod_obj.read(cr, uid, result, ['res_id'])
|
||||
return {
|
||||
'domain': "[('journal_id','=',%d), ('period_id','=',%d)]" % (form['journal_id'],form['period_id']),
|
||||
'name': name,
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'account.move.line',
|
||||
'view_id': view_res,
|
||||
'context': "{'journal_id':%d, 'period_id':%d}" % (form['journal_id'],form['period_id']),
|
||||
'type': 'ir.actions.act_window',
|
||||
'search_view_id': id['res_id']
|
||||
}
|
||||
|
||||
class wiz_journal(wizard.interface):
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [_period_get],
|
||||
'result': {'type': 'form', 'arch':_journal_form, 'fields':_journal_fields, 'state':[('end','Cancel', 'gtk-cancel'),('open','Open Journal', 'gtk-ok')]}
|
||||
},
|
||||
'open': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action': _action_open_window, 'state':'end'}
|
||||
}
|
||||
}
|
||||
wiz_journal('account.move.journal')
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
from tools.translate import _
|
||||
|
||||
|
||||
_journal_form = '''<?xml version="1.0"?>
|
||||
<form string="%s">
|
||||
<field name="account_id"/>
|
||||
</form>''' % ('Reconciliation',)
|
||||
|
||||
_journal_fields = {
|
||||
'account_id': {'string':'Account', 'type':'many2one', 'relation':'account.account','domain': [('reconcile','=',1)], 'required':True},
|
||||
}
|
||||
|
||||
def _action_open_window(self, cr, uid, data, context):
|
||||
return {
|
||||
'domain': "[('account_id','=',%d),('reconcile_id','=',False),('state','<>','draft')]" % data['form']['account_id'],
|
||||
'name': _('Reconciliation'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'view_id': False,
|
||||
'res_model': 'account.move.line',
|
||||
'type': 'ir.actions.act_window'
|
||||
}
|
||||
|
||||
class wiz_rec_select(wizard.interface):
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type': 'form', 'arch':_journal_form, 'fields':_journal_fields, 'state':[('end','Cancel'),('open','Open for reconciliation')]}
|
||||
},
|
||||
'open': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action': _action_open_window, 'state':'end'}
|
||||
}
|
||||
}
|
||||
wiz_rec_select('account.move.line.reconcile.select')
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -1,226 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
import pooler
|
||||
import osv
|
||||
import netsvc
|
||||
import time
|
||||
from tools.translate import _
|
||||
|
||||
sur_form = '''<?xml version="1.0"?>
|
||||
<form string="Credit Note">
|
||||
<label string="Are you sure you want to refund this invoice ?" colspan="2"/>
|
||||
<newline />
|
||||
<field name="date" />
|
||||
<field name="period" />
|
||||
<field name="description" width="150" />
|
||||
</form>'''
|
||||
|
||||
sur_fields = {
|
||||
'date': {'string':'Operation date','type':'date', 'required':'False'},
|
||||
'period':{'string': 'Force period', 'type': 'many2one',
|
||||
'relation': 'account.period', 'required': False},
|
||||
'description':{'string':'Description', 'type':'char', 'required':'True'},
|
||||
}
|
||||
|
||||
|
||||
class wiz_refund(wizard.interface):
|
||||
|
||||
def _invoice_refund(self, cr, uid, data, context):
|
||||
return self._compute_refund(cr, uid, data, 'refund', context)
|
||||
|
||||
def _invoice_cancel(self, cr, uid, data, context):
|
||||
return self._compute_refund(cr, uid, data, 'cancel', context)
|
||||
|
||||
def _invoice_modify(self, cr, uid, data, context):
|
||||
return self._compute_refund(cr, uid, data, 'modify', context)
|
||||
|
||||
def _compute_refund(self, cr, uid, data, mode, context):
|
||||
form = data['form']
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
reconcile_obj = pool.get('account.move.reconcile')
|
||||
account_m_line_obj = pool.get('account.move.line')
|
||||
created_inv = []
|
||||
date = False
|
||||
period = False
|
||||
description = False
|
||||
for inv in pool.get('account.invoice').browse(cr, uid, data['ids']):
|
||||
if inv.state in ['draft', 'proforma2', 'cancel']:
|
||||
raise wizard.except_wizard(_('Error !'), _('Can not %s draft/proforma/cancel invoice.') % (mode))
|
||||
if form['period'] :
|
||||
period = form['period']
|
||||
else:
|
||||
period = inv.period_id and inv.period_id.id or False
|
||||
|
||||
if form['date'] :
|
||||
date = form['date']
|
||||
if not form['period'] :
|
||||
cr.execute("select name from ir_model_fields where model='account.period' and name='company_id'")
|
||||
result_query = cr.fetchone()
|
||||
if result_query:
|
||||
#in multi company mode
|
||||
cr.execute("""SELECT id
|
||||
from account_period where date('%s')
|
||||
between date_start AND date_stop and company_id = %s limit 1 """,
|
||||
(form['date'],pool.get('res.users').browse(cr,uid,uid).company_id.id,))
|
||||
else:
|
||||
#in mono company mode
|
||||
cr.execute("""SELECT id
|
||||
from account_period where date('%s')
|
||||
between date_start AND date_stop limit 1 """,
|
||||
(form['date'],))
|
||||
res = cr.fetchone()
|
||||
if res:
|
||||
period = res[0]
|
||||
else:
|
||||
date = inv.date_invoice
|
||||
|
||||
if form['description'] :
|
||||
description = form['description']
|
||||
else:
|
||||
description = inv.name
|
||||
|
||||
if not period:
|
||||
raise wizard.except_wizard(_('Data Insufficient !'), _('No Period found on Invoice!'))
|
||||
|
||||
refund_id = pool.get('account.invoice').refund(cr, uid, [inv.id],date, period, description)
|
||||
refund = pool.get('account.invoice').browse(cr, uid, refund_id[0])
|
||||
# we compute due date
|
||||
#!!!due date = date inv date on formdate
|
||||
pool.get('account.invoice').write(cr, uid, [refund.id],{'date_due':date,'check_total':inv.check_total})
|
||||
# to make the taxes calculated
|
||||
pool.get('account.invoice').button_compute(cr, uid, refund_id)
|
||||
|
||||
created_inv.append(refund_id[0])
|
||||
#if inv is paid we unreconcile
|
||||
if mode in ('cancel','modify'):
|
||||
movelines = inv.move_id.line_id
|
||||
#we unreconcile the lines
|
||||
to_reconcile_ids = {}
|
||||
for line in movelines :
|
||||
#if the account of the line is the as the one in the invoice
|
||||
#we reconcile
|
||||
if line.account_id.id == inv.account_id.id :
|
||||
to_reconcile_ids[line.account_id.id] =[line.id]
|
||||
if type(line.reconcile_id) != osv.orm.browse_null :
|
||||
reconcile_obj.unlink(cr,uid, line.reconcile_id.id)
|
||||
#we advance the workflow of the refund to open
|
||||
wf_service = netsvc.LocalService('workflow')
|
||||
wf_service.trg_validate(uid, 'account.invoice', refund.id, 'invoice_open', cr)
|
||||
#we reload the browse record
|
||||
refund = pool.get('account.invoice').browse(cr, uid, refund_id[0])
|
||||
#we match the line to reconcile
|
||||
for tmpline in refund.move_id.line_id :
|
||||
if tmpline.account_id.id == inv.account_id.id :
|
||||
to_reconcile_ids[tmpline.account_id.id].append(tmpline.id)
|
||||
for account in to_reconcile_ids :
|
||||
account_m_line_obj.reconcile(cr, uid, to_reconcile_ids[account],
|
||||
writeoff_period_id=period,
|
||||
writeoff_journal_id=inv.journal_id.id,
|
||||
writeoff_acc_id=inv.account_id.id
|
||||
)
|
||||
#we create a new invoice that is the copy of the original
|
||||
if mode == 'modify' :
|
||||
invoice = pool.get('account.invoice').read(cr, uid, [inv.id],
|
||||
['name', 'type', 'number', 'reference',
|
||||
'comment', 'date_due', 'partner_id', 'address_contact_id',
|
||||
'address_invoice_id', 'partner_insite','partner_contact',
|
||||
'partner_ref', 'payment_term', 'account_id', 'currency_id',
|
||||
'invoice_line', 'tax_line', 'journal_id','period_id'
|
||||
]
|
||||
)
|
||||
invoice = invoice[0]
|
||||
del invoice['id']
|
||||
invoice_lines = pool.get('account.invoice.line').read(cr, uid, invoice['invoice_line'])
|
||||
invoice_lines = pool.get('account.invoice')._refund_cleanup_lines(cr, uid, invoice_lines)
|
||||
tax_lines = pool.get('account.invoice.tax').read(
|
||||
cr, uid, invoice['tax_line'])
|
||||
tax_lines = pool.get('account.invoice')._refund_cleanup_lines(cr, uid, tax_lines)
|
||||
|
||||
invoice.update({
|
||||
'type': inv.type,
|
||||
'date_invoice': date,
|
||||
'state': 'draft',
|
||||
'number': False,
|
||||
'invoice_line': invoice_lines,
|
||||
'tax_line': tax_lines,
|
||||
'period_id': period,
|
||||
'name':description
|
||||
})
|
||||
|
||||
#take the id part of the tuple returned for many2one fields
|
||||
for field in ('address_contact_id', 'address_invoice_id', 'partner_id',
|
||||
'account_id', 'currency_id', 'payment_term', 'journal_id'):
|
||||
invoice[field] = invoice[field] and invoice[field][0]
|
||||
|
||||
# create the new invoice
|
||||
inv_id = pool.get('account.invoice').create(cr, uid, invoice,{})
|
||||
# we compute due date
|
||||
if inv.payment_term.id:
|
||||
data = pool.get('account.invoice').onchange_payment_term_date_invoice(cr, uid, [inv_id],inv.payment_term.id,date)
|
||||
if 'value' in data and data['value']:
|
||||
pool.get('account.invoice').write(cr, uid, [inv_id],data['value'])
|
||||
created_inv.append(inv_id)
|
||||
|
||||
#we get the view id
|
||||
mod_obj = pool.get('ir.model.data')
|
||||
act_obj = pool.get('ir.actions.act_window')
|
||||
if inv.type == 'out_invoice':
|
||||
xml_id = 'action_invoice_tree5'
|
||||
elif inv.type == 'in_invoice':
|
||||
xml_id = 'action_invoice_tree8'
|
||||
elif type == 'out_refund':
|
||||
xml_id = 'action_invoice_tree10'
|
||||
else:
|
||||
xml_id = 'action_invoice_tree12'
|
||||
#we get the model
|
||||
result = mod_obj._get_id(cr, uid, 'account', xml_id)
|
||||
id = mod_obj.read(cr, uid, result, ['res_id'])['res_id']
|
||||
# we read the act window
|
||||
result = act_obj.read(cr, uid, id)
|
||||
result['res_id'] = created_inv
|
||||
|
||||
return result
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type':'form', 'arch':sur_form, 'fields':sur_fields, 'state':[('end','Cancel'),('refund','Refund Invoice'),('cancel_invoice','Cancel Invoice'),('modify_invoice','Modify Invoice')]}
|
||||
},
|
||||
'refund': {
|
||||
'actions': [],
|
||||
'result': {'type':'action', 'action':_invoice_refund, 'state':'end'},
|
||||
},
|
||||
'cancel_invoice': {
|
||||
'actions': [],
|
||||
'result': {'type':'action', 'action':_invoice_cancel, 'state':'end'},
|
||||
},
|
||||
'modify_invoice': {
|
||||
'actions': [],
|
||||
'result': {'type':'action', 'action':_invoice_modify, 'state':'end'},
|
||||
},
|
||||
|
||||
}
|
||||
wiz_refund('account.invoice.refund')
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
import pooler
|
||||
|
||||
#
|
||||
# TODO: add an intermediate screen for checks
|
||||
#
|
||||
|
||||
_subscription_form = '''<?xml version="1.0"?>
|
||||
<form string="%s">
|
||||
<separator string="Generate entries before:" colspan="4"/>
|
||||
<field name="date"/>
|
||||
</form>''' % ('Subscription Compute',)
|
||||
|
||||
_subscription_fields = {
|
||||
'date': {'string':'Date', 'type':'date', 'default':lambda *a: time.strftime('%Y-%m-%d'), 'required':True},
|
||||
}
|
||||
|
||||
class wiz_subscription(wizard.interface):
|
||||
def _action_generate(self, cr, uid, data, context={}):
|
||||
cr.execute('select id from account_subscription_line where date<%s and move_id is null', (data['form']['date'],))
|
||||
ids = map(lambda x: x[0], cr.fetchall())
|
||||
pooler.get_pool(cr.dbname).get('account.subscription.line').move_create(cr, uid, ids)
|
||||
return {}
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type': 'form', 'arch':_subscription_form, 'fields':_subscription_fields, 'state':[('end','Cancel', 'gtk-cancel'),('generate','Compute', 'gtk-ok')]}
|
||||
},
|
||||
'generate': {
|
||||
'actions': [_action_generate],
|
||||
'result': {'type': 'state', 'state':'end'}
|
||||
}
|
||||
}
|
||||
wiz_subscription('account.subscription.generate')
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
|
||||
_journal_form = '''<?xml version="1.0"?>
|
||||
<form string="%s">
|
||||
<field name="account_id"/>
|
||||
</form>''' % ('Unreconciliation',)
|
||||
|
||||
_journal_fields = {
|
||||
'account_id': {'string':'Account', 'type':'many2one', 'relation':'account.account', 'required':True},
|
||||
}
|
||||
|
||||
def _action_open_window(self, cr, uid, data, context):
|
||||
return {
|
||||
'domain': "[('account_id','=',%d),('reconcile_id','<>',False),('state','<>','draft')]" % data['form']['account_id'],
|
||||
'name': 'Unreconciliation',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'view_id': False,
|
||||
'res_model': 'account.move.line',
|
||||
'type': 'ir.actions.act_window'
|
||||
}
|
||||
|
||||
class wiz_unrec_select(wizard.interface):
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type': 'form', 'arch':_journal_form, 'fields':_journal_fields, 'state':[('end','Cancel', 'gtk-cancel'),('open','Open for unreconciliation', 'gtk-ok')]}
|
||||
},
|
||||
'open': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action': _action_open_window, 'state':'end'}
|
||||
}
|
||||
}
|
||||
wiz_unrec_select('account.move.line.unreconcile.select')
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
'depends': ['base'],
|
||||
'init_xml': [],
|
||||
'update_xml': [
|
||||
'wizard/audittrail_view_log_view.xml',
|
||||
'audittrail_view.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/audittrail_security.xml'
|
||||
|
|
|
@ -19,35 +19,39 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
from osv import fields, osv
|
||||
from osv.osv import osv_pool
|
||||
from tools.translate import _
|
||||
import ir
|
||||
import netsvc
|
||||
import pooler
|
||||
import string
|
||||
import time, copy
|
||||
import time
|
||||
|
||||
class audittrail_rule(osv.osv):
|
||||
"""
|
||||
For Auddittrail Rule
|
||||
"""
|
||||
_name = 'audittrail.rule'
|
||||
_description = "Audittrail Rule"
|
||||
_columns = {
|
||||
"name": fields.char("Rule Name", size=32, required=True),
|
||||
"object_id": fields.many2one('ir.model', 'Object', required=True),
|
||||
"user_id": fields.many2many('res.users', 'audittail_rules_users', 'user_id', 'rule_id', 'Users'),
|
||||
"log_read": fields.boolean("Log reads"),
|
||||
"log_write": fields.boolean("Log writes"),
|
||||
"log_unlink": fields.boolean("Log deletes"),
|
||||
"log_create": fields.boolean("Log creates"),
|
||||
"state": fields.selection((("draft", "Draft"), ("subscribed", "Subscribed")), "State", required=True),
|
||||
"action_id":fields.many2one('ir.actions.act_window', "Action ID"),
|
||||
"name": fields.char("Rule Name", size=32, required=True),
|
||||
"object_id": fields.many2one('ir.model', 'Object', required=True),
|
||||
"user_id": fields.many2many('res.users', 'audittail_rules_users',
|
||||
'user_id', 'rule_id', 'Users'),
|
||||
"log_read": fields.boolean("Log reads"),
|
||||
"log_write": fields.boolean("Log writes"),
|
||||
"log_unlink": fields.boolean("Log deletes"),
|
||||
"log_create": fields.boolean("Log creates"),
|
||||
"state": fields.selection((("draft", "Draft"),
|
||||
("subscribed", "Subscribed")),
|
||||
"State", required=True),
|
||||
"action_id": fields.many2one('ir.actions.act_window', "Action ID"),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'state': lambda *a: 'draft',
|
||||
'log_create': lambda *a: 1,
|
||||
'log_unlink': lambda *a: 1,
|
||||
'log_write': lambda *a: 1,
|
||||
'state': lambda *a: 'draft',
|
||||
'log_create': lambda *a: 1,
|
||||
'log_unlink': lambda *a: 1,
|
||||
'log_write': lambda *a: 1,
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
|
@ -56,59 +60,86 @@ class audittrail_rule(osv.osv):
|
|||
__functions = {}
|
||||
|
||||
def subscribe(self, cr, uid, ids, *args):
|
||||
"""
|
||||
Subscribe Rule for auditing changes on object and apply shortcut for logs on that object.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Auddittrail Rule’s IDs.
|
||||
@return: True
|
||||
"""
|
||||
obj_action = self.pool.get('ir.actions.act_window')
|
||||
obj_model = self.pool.get('ir.model.data')
|
||||
#start Loop
|
||||
for thisrule in self.browse(cr, uid, ids):
|
||||
obj = self.pool.get(thisrule.object_id.model)
|
||||
if not obj:
|
||||
raise osv.except_osv(
|
||||
_('WARNING:audittrail is not part of the pool'),
|
||||
_('WARNING: audittrail is not part of the pool'),
|
||||
_('Change audittrail depends -- Setting rule as DRAFT'))
|
||||
self.write(cr, uid, [thisrule.id], {"state": "draft"})
|
||||
val={
|
||||
"name":'View Log',
|
||||
"res_model":'audittrail.log',
|
||||
"src_model":thisrule.object_id.model,
|
||||
"domain":"[('object_id','=',"+str(thisrule.object_id.id)+"),('res_id', '=', active_id)]"
|
||||
val = {
|
||||
"name": 'View Log',
|
||||
"res_model": 'audittrail.log',
|
||||
"src_model": thisrule.object_id.model,
|
||||
"domain": "[('object_id','=', " + str(thisrule.object_id.id) + "), ('res_id', '=', active_id)]"
|
||||
|
||||
}
|
||||
id=self.pool.get('ir.actions.act_window').create(cr, uid, val)
|
||||
self.write(cr, uid, [thisrule.id], {"state": "subscribed", "action_id":id})
|
||||
id = obj_action.create(cr, uid, val)
|
||||
self.write(cr, uid, [thisrule.id], {"state": "subscribed", "action_id": id})
|
||||
keyword = 'client_action_relate'
|
||||
value = 'ir.actions.act_window,'+str(id)
|
||||
res=self.pool.get('ir.model.data').ir_set(cr, uid, 'action', keyword, 'View_log_'+thisrule.object_id.model, [thisrule.object_id.model], value, replace=True, isobject=True, xml_id=False)
|
||||
value = 'ir.actions.act_window,' + str(id)
|
||||
res = obj_model.ir_set(cr, uid, 'action', keyword, 'View_log_' + thisrule.object_id.model, [thisrule.object_id.model], value, replace=True, isobject=True, xml_id=False)
|
||||
#End Loop
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def unsubscribe(self, cr, uid, ids, *args):
|
||||
"""
|
||||
Unsubscribe Auditing Rule on object
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Auddittrail Rule’s IDs.
|
||||
@return: True
|
||||
"""
|
||||
obj_action = self.pool.get('ir.actions.act_window')
|
||||
val_obj = self.pool.get('ir.values')
|
||||
#start Loop
|
||||
for thisrule in self.browse(cr, uid, ids):
|
||||
if thisrule.id in self.__functions :
|
||||
if thisrule.id in self.__functions:
|
||||
for function in self.__functions[thisrule.id]:
|
||||
setattr(function[0], function[1], function[2])
|
||||
w_id=self.pool.get('ir.actions.act_window').search(cr, uid, [('name', '=', 'View Log'), ('res_model', '=', 'audittrail.log'), ('src_model', '=', thisrule.object_id.model)])
|
||||
self.pool.get('ir.actions.act_window').unlink(cr, uid, w_id)
|
||||
val_obj=self.pool.get('ir.values')
|
||||
value="ir.actions.act_window"+','+str(w_id[0])
|
||||
val_id=val_obj.search(cr, uid, [('model', '=', thisrule.object_id.model), ('value', '=', value)])
|
||||
w_id = obj_action.search(cr, uid, [('name', '=', 'View Log'), ('res_model', '=', 'audittrail.log'), ('src_model', '=', thisrule.object_id.model)])
|
||||
obj_action.unlink(cr, uid, w_id)
|
||||
value = "ir.actions.act_window" + ',' + str(w_id[0])
|
||||
val_id = val_obj.search(cr, uid, [('model', '=', thisrule.object_id.model), ('value', '=', value)])
|
||||
if val_id:
|
||||
res = ir.ir_del(cr, uid, val_id[0])
|
||||
self.write(cr, uid, [thisrule.id], {"state": "draft"})
|
||||
#End Loop
|
||||
return True
|
||||
|
||||
audittrail_rule()
|
||||
|
||||
|
||||
class audittrail_log(osv.osv):
|
||||
"""
|
||||
For Audittrail Log
|
||||
"""
|
||||
_name = 'audittrail.log'
|
||||
_description = "Audittrail Log"
|
||||
|
||||
_columns = {
|
||||
"name": fields.char("Name", size=32),
|
||||
"object_id": fields.many2one('ir.model', 'Object'),
|
||||
"user_id": fields.many2one('res.users', 'User'),
|
||||
"method": fields.selection((('read', 'Read'), ('write', 'Write'), ('unlink', 'Delete'), ('create', 'Create')), "Method"),
|
||||
"timestamp": fields.datetime("Date"),
|
||||
"res_id":fields.integer('Resource Id'),
|
||||
"line_ids":fields.one2many('audittrail.log.line', 'log_id', 'Log lines'),
|
||||
"name": fields.char("Name", size=32),
|
||||
"object_id": fields.many2one('ir.model', 'Object'),
|
||||
"user_id": fields.many2one('res.users', 'User'),
|
||||
"method": fields.selection((('read', 'Read'),
|
||||
('write', 'Write'),
|
||||
('unlink', 'Delete'),
|
||||
('create', 'Create')), "Method"),
|
||||
"timestamp": fields.datetime("Date"),
|
||||
"res_id": fields.integer('Resource Id'),
|
||||
"line_ids": fields.one2many('audittrail.log.line', 'log_id', 'Log lines'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
"timestamp": lambda *a: time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
}
|
||||
|
@ -116,235 +147,293 @@ class audittrail_log(osv.osv):
|
|||
|
||||
audittrail_log()
|
||||
|
||||
|
||||
class audittrail_log_line(osv.osv):
|
||||
_name='audittrail.log.line'
|
||||
_columns={
|
||||
'field_id': fields.many2one('ir.model.fields', 'Fields', required=True),
|
||||
'log_id':fields.many2one('audittrail.log', 'Log'),
|
||||
'log':fields.integer("Log ID"),
|
||||
'old_value':fields.text("Old Value"),
|
||||
'new_value':fields.text("New Value"),
|
||||
'old_value_text':fields.text('Old value Text'),
|
||||
'new_value_text':fields.text('New value Text'),
|
||||
'field_description':fields.char('Field Description' , size=64),
|
||||
}
|
||||
"""
|
||||
Audittrail Log Line.
|
||||
"""
|
||||
_name = 'audittrail.log.line'
|
||||
_description = "Log Line"
|
||||
_columns = {
|
||||
'field_id': fields.many2one('ir.model.fields', 'Fields', required=True),
|
||||
'log_id': fields.many2one('audittrail.log', 'Log'),
|
||||
'log': fields.integer("Log ID"),
|
||||
'old_value': fields.text("Old Value"),
|
||||
'new_value': fields.text("New Value"),
|
||||
'old_value_text': fields.text('Old value Text'),
|
||||
'new_value_text': fields.text('New value Text'),
|
||||
'field_description': fields.char('Field Description', size=64),
|
||||
}
|
||||
|
||||
audittrail_log_line()
|
||||
|
||||
|
||||
class audittrail_objects_proxy(osv_pool):
|
||||
def get_value_text(self, cr, uid, field_name, values, object, context={}):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
obj=pool.get(object.model)
|
||||
obj_ids= pool.get('ir.model').search(cr, uid, [('model', '=', object.model)])
|
||||
model_object=pool.get('ir.model').browse(cr, uid, obj_ids)[0]
|
||||
f_id= pool.get('ir.model.fields').search(cr, uid, [('name', '=', field_name), ('model_id', '=', object.id)])
|
||||
if f_id:
|
||||
field=pool.get('ir.model.fields').read(cr, uid, f_id)[0]
|
||||
model=field['relation']
|
||||
""" Uses Object proxy for auditing changes on object of subscribed Rules"""
|
||||
|
||||
def get_value_text(self, cr, uid, field_name, values, object, context=None):
|
||||
"""
|
||||
Gets textual values for the fields
|
||||
e.g.: For field of type many2one it gives its name value instead of id
|
||||
|
||||
if field['ttype']=='many2one':
|
||||
if values:
|
||||
if type(values)==tuple:
|
||||
values=values[0]
|
||||
val=pool.get(model).read(cr, uid, [values], [pool.get(model)._rec_name])
|
||||
if len(val):
|
||||
return val[0][pool.get(model)._rec_name]
|
||||
elif field['ttype'] == 'many2many':
|
||||
value=[]
|
||||
if values:
|
||||
for id in values:
|
||||
val=pool.get(model).read(cr, uid, [id], [pool.get(model)._rec_name])
|
||||
if len(val):
|
||||
value.append(val[0][pool.get(model)._rec_name])
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param field_name: List of fields for text values
|
||||
@param values: Values for field to be converted into textual values
|
||||
@return: values: List of textual values for given fields
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
f_id = pool.get('ir.model.fields').search(cr, uid, [('name', '=', field_name), ('model_id', '=', object.id)])
|
||||
if f_id:
|
||||
field = pool.get('ir.model.fields').read(cr, uid, f_id)[0]
|
||||
model = field['relation']
|
||||
|
||||
if field['ttype'] == 'many2one':
|
||||
if values:
|
||||
if type(values) == tuple:
|
||||
values = values[0]
|
||||
val = pool.get(model).read(cr, uid, [values], [pool.get(model)._rec_name])
|
||||
if val:
|
||||
return val[0][pool.get(model)._rec_name]
|
||||
elif field['ttype'] == 'many2many':
|
||||
value = []
|
||||
if values:
|
||||
for id in values:
|
||||
val = pool.get(model).read(cr, uid, [id], [pool.get(model)._rec_name])
|
||||
if val:
|
||||
value.append(val[0][pool.get(model)._rec_name])
|
||||
return value
|
||||
|
||||
elif field['ttype'] == 'one2many':
|
||||
if values:
|
||||
value = []
|
||||
for id in values:
|
||||
val = pool.get(model).read(cr, uid, [id], [pool.get(model)._rec_name])
|
||||
|
||||
if val:
|
||||
value.append(val[0][pool.get(model)._rec_name])
|
||||
return value
|
||||
|
||||
elif field['ttype'] == 'one2many':
|
||||
if values:
|
||||
value=[]
|
||||
for id in values:
|
||||
val=pool.get(model).read(cr, uid, [id], [pool.get(model)._rec_name])
|
||||
|
||||
if len(val):
|
||||
value.append(val[0][pool.get(model)._rec_name])
|
||||
return value
|
||||
return values
|
||||
|
||||
def create_log_line(self, cr, uid, id, object, lines=[]):
|
||||
"""
|
||||
Creates lines for changed fields with its old and new values
|
||||
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param object: Object who's values are being changed
|
||||
@param lines: List of values for line is to be created
|
||||
"""
|
||||
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
obj=pool.get(object.model)
|
||||
obj_ids= pool.get('ir.model').search(cr, uid, [('model', '=', object.model)])
|
||||
model_object=pool.get('ir.model').browse(cr, uid, obj_ids)[0]
|
||||
obj = pool.get(object.model)
|
||||
#start Loop
|
||||
for line in lines:
|
||||
if obj._inherits:
|
||||
inherits_ids= pool.get('ir.model').search(cr, uid, [('model', '=', obj._inherits.keys()[0])])
|
||||
f_id= pool.get('ir.model.fields').search(cr, uid, [('name', '=', line['name']), ('model_id', 'in', (object.id, inherits_ids[0]))])
|
||||
inherits_ids = pool.get('ir.model').search(cr, uid, [('model', '=', obj._inherits.keys()[0])])
|
||||
f_id = pool.get('ir.model.fields').search(cr, uid, [('name', '=', line['name']), ('model_id', 'in', (object.id, inherits_ids[0]))])
|
||||
else:
|
||||
f_id= pool.get('ir.model.fields').search(cr, uid, [('name', '=', line['name']), ('model_id', '=', object.id)])
|
||||
if len(f_id):
|
||||
fields=pool.get('ir.model.fields').read(cr, uid, f_id)
|
||||
old_value='old_value' in line and line['old_value'] or ''
|
||||
new_value='new_value' in line and line['new_value'] or ''
|
||||
old_value_text='old_value_text' in line and line['old_value_text'] or ''
|
||||
new_value_text='new_value_text' in line and line['new_value_text'] or ''
|
||||
f_id = pool.get('ir.model.fields').search(cr, uid, [('name', '=', line['name']), ('model_id', '=', object.id)])
|
||||
if f_id:
|
||||
fields = pool.get('ir.model.fields').read(cr, uid, f_id)
|
||||
old_value = 'old_value' in line and line['old_value'] or ''
|
||||
new_value = 'new_value' in line and line['new_value'] or ''
|
||||
old_value_text = 'old_value_text' in line and line['old_value_text'] or ''
|
||||
new_value_text = 'new_value_text' in line and line['new_value_text'] or ''
|
||||
|
||||
if old_value_text == new_value_text:
|
||||
continue
|
||||
if fields[0]['ttype']== 'many2one':
|
||||
if type(old_value)==tuple:
|
||||
old_value=old_value[0]
|
||||
if type(new_value)==tuple:
|
||||
new_value=new_value[0]
|
||||
log_line_id = pool.get('audittrail.log.line').create(cr, uid, {"log_id": id, "field_id": f_id[0] , "old_value":old_value , "new_value":new_value, "old_value_text":old_value_text , "new_value_text":new_value_text, "field_description":fields[0]['field_description']})
|
||||
if fields[0]['ttype'] == 'many2one':
|
||||
if type(old_value) == tuple:
|
||||
old_value = old_value[0]
|
||||
if type(new_value) == tuple:
|
||||
new_value = new_value[0]
|
||||
vals = {
|
||||
"log_id": id,
|
||||
"field_id": f_id[0],
|
||||
"old_value": old_value,
|
||||
"new_value": new_value,
|
||||
"old_value_text": old_value_text,
|
||||
"new_value_text": new_value_text,
|
||||
"field_description": fields[0]['field_description']
|
||||
}
|
||||
line_id = pool.get('audittrail.log.line').create(cr, uid, vals)
|
||||
cr.commit()
|
||||
#End Loop
|
||||
return True
|
||||
|
||||
def log_fct(self, db, uid, object, method, fct_src, *args):
|
||||
logged_uids = []
|
||||
pool = pooler.get_pool(db)
|
||||
cr = pooler.get_db(db).cursor()
|
||||
obj=pool.get(object)
|
||||
obj_ids= pool.get('ir.model').search(cr, uid, [('model', '=', object)])
|
||||
model_object=pool.get('ir.model').browse(cr, uid, obj_ids)[0]
|
||||
if method in ('create'):
|
||||
res_id = fct_src(db, uid, object, method, *args)
|
||||
"""
|
||||
Logging function: This function is performs logging oprations according to method
|
||||
@param db: the current database
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param object: Object who's values are being changed
|
||||
@param method: method to log: create, read, write, unlink
|
||||
@param fct_src: execute method of Object proxy
|
||||
|
||||
@return: Returns result as per method of Object proxy
|
||||
"""
|
||||
logged_uids = []
|
||||
pool = pooler.get_pool(db)
|
||||
cr = pooler.get_db(db).cursor()
|
||||
obj_ids = pool.get('ir.model').search(cr, uid, [('model', '=', object)])
|
||||
model_object = pool.get('ir.model').browse(cr, uid, obj_ids)[0]
|
||||
if method in ('create'):
|
||||
res_id = fct_src(db, uid, object, method, *args)
|
||||
cr.commit()
|
||||
new_value = pool.get(model_object.model).read(cr, uid, [res_id], args[0].keys())[0]
|
||||
if 'id' in new_value:
|
||||
del new_value['id']
|
||||
if not logged_uids or uid in logged_uids:
|
||||
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
|
||||
resource_name = resource_name and resource_name[0][1] or ''
|
||||
vals = {
|
||||
"method": method,
|
||||
"object_id": model_object.id,
|
||||
"user_id": uid, "res_id": res_id,
|
||||
"name": resource_name
|
||||
}
|
||||
id = pool.get('audittrail.log').create(cr, uid, vals)
|
||||
lines = []
|
||||
for field in new_value:
|
||||
if new_value[field]:
|
||||
line = {
|
||||
'name': field,
|
||||
'new_value': new_value[field],
|
||||
'new_value_text': self.get_value_text(cr, uid, field, new_value[field], model_object)
|
||||
}
|
||||
lines.append(line)
|
||||
self.create_log_line(cr, uid, id, model_object, lines)
|
||||
cr.commit()
|
||||
cr.close()
|
||||
return res_id
|
||||
|
||||
if method in ('write'):
|
||||
res_ids = args[0]
|
||||
for res_id in res_ids:
|
||||
old_values = pool.get(model_object.model).read(cr, uid, res_id, args[1].keys())
|
||||
old_values_text = {}
|
||||
for field in args[1].keys():
|
||||
old_values_text[field] = self.get_value_text(cr, uid, field, old_values[field], model_object)
|
||||
res = fct_src(db, uid, object, method, *args)
|
||||
cr.commit()
|
||||
new_value=pool.get(model_object.model).read(cr, uid, [res_id], args[0].keys())[0]
|
||||
if 'id' in new_value:
|
||||
del new_value['id']
|
||||
if not len(logged_uids) or uid in logged_uids:
|
||||
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
|
||||
resource_name = resource_name and resource_name[0][1] or ''
|
||||
id=pool.get('audittrail.log').create(cr, uid, {"method": method , "object_id": model_object.id, "user_id": uid, "res_id": res_id, "name": resource_name})
|
||||
lines=[]
|
||||
for field in new_value:
|
||||
if new_value[field]:
|
||||
line={
|
||||
'name':field,
|
||||
'new_value':new_value[field],
|
||||
'new_value_text': self.get_value_text(cr, uid, field, new_value[field], model_object)
|
||||
}
|
||||
lines.append(line)
|
||||
self.create_log_line(cr, uid, id, model_object, lines)
|
||||
cr.commit()
|
||||
cr.close()
|
||||
return res_id
|
||||
|
||||
if method in ('write'):
|
||||
res_ids=args[0]
|
||||
for res_id in res_ids:
|
||||
old_values=pool.get(model_object.model).read(cr, uid, res_id, args[1].keys())
|
||||
old_values_text={}
|
||||
for field in args[1].keys():
|
||||
old_values_text[field] = self.get_value_text(cr, uid, field, old_values[field], model_object)
|
||||
res =fct_src(db, uid, object, method, *args)
|
||||
cr.commit()
|
||||
if res:
|
||||
new_values=pool.get(model_object.model).read(cr, uid, res_ids, args[1].keys())[0]
|
||||
if not len(logged_uids) or uid in logged_uids:
|
||||
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
|
||||
resource_name = resource_name and resource_name[0][1] or ''
|
||||
id=pool.get('audittrail.log').create(cr, uid, {"method": method, "object_id": model_object.id, "user_id": uid, "res_id": res_id, "name": resource_name})
|
||||
lines=[]
|
||||
for field in args[1].keys():
|
||||
if args[1].keys():
|
||||
line={
|
||||
'name':field,
|
||||
'new_value':field in new_values and new_values[field] or '',
|
||||
'old_value':field in old_values and old_values[field] or '',
|
||||
'new_value_text': self.get_value_text(cr, uid, field, new_values[field], model_object),
|
||||
'old_value_text':old_values_text[field]
|
||||
}
|
||||
lines.append(line)
|
||||
cr.commit()
|
||||
self.create_log_line(cr, uid, id, model_object, lines)
|
||||
cr.close()
|
||||
return res
|
||||
|
||||
if method in ('read'):
|
||||
res_ids=args[0]
|
||||
old_values={}
|
||||
res =fct_src(db, uid, object, method, *args)
|
||||
if type(res)==list:
|
||||
|
||||
for v in res:
|
||||
old_values[v['id']]=v
|
||||
else:
|
||||
old_values[res['id']]=res
|
||||
for res_id in old_values:
|
||||
if not len(logged_uids) or uid in logged_uids:
|
||||
if res:
|
||||
new_values = pool.get(model_object.model).read(cr, uid, res_ids, args[1].keys())[0]
|
||||
if not logged_uids or uid in logged_uids:
|
||||
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
|
||||
resource_name = resource_name and resource_name[0][1] or ''
|
||||
id=pool.get('audittrail.log').create(cr, uid, {"method": method , "object_id": model_object.id, "user_id": uid, "res_id": res_id, "name": resource_name})
|
||||
lines=[]
|
||||
for field in old_values[res_id]:
|
||||
if old_values[res_id][field]:
|
||||
line={
|
||||
'name':field,
|
||||
'old_value':old_values[res_id][field],
|
||||
'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model_object)
|
||||
}
|
||||
lines.append(line)
|
||||
cr.commit()
|
||||
self.create_log_line(cr, uid, id, model_object, lines)
|
||||
cr.close()
|
||||
return res
|
||||
|
||||
if method in ('unlink'):
|
||||
res_ids=args[0]
|
||||
old_values={}
|
||||
for res_id in res_ids:
|
||||
old_values[res_id]=pool.get(model_object.model).read(cr, uid, res_id, [])
|
||||
|
||||
for res_id in res_ids:
|
||||
if not len(logged_uids) or uid in logged_uids:
|
||||
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
|
||||
resource_name = resource_name and resource_name[0][1] or ''
|
||||
id=pool.get('audittrail.log').create(cr, uid, {"method": method , "object_id": model_object.id, "user_id": uid, "res_id": res_id, "name": resource_name})
|
||||
lines=[]
|
||||
for field in old_values[res_id]:
|
||||
if old_values[res_id][field]:
|
||||
line={
|
||||
'name':field,
|
||||
'old_value':old_values[res_id][field],
|
||||
'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model_object)
|
||||
id = pool.get('audittrail.log').create(cr, uid, {"method": method, "object_id": model_object.id, "user_id": uid, "res_id": res_id, "name": resource_name})
|
||||
lines = []
|
||||
for field in args[1].keys():
|
||||
if args[1].keys():
|
||||
line = {
|
||||
'name': field,
|
||||
'new_value': field in new_values and new_values[field] or '',
|
||||
'old_value': field in old_values and old_values[field] or '',
|
||||
'new_value_text': self.get_value_text(cr, uid, field, new_values[field], model_object),
|
||||
'old_value_text': old_values_text[field]
|
||||
}
|
||||
lines.append(line)
|
||||
cr.commit()
|
||||
self.create_log_line(cr, uid, id, model_object, lines)
|
||||
res =fct_src(db, uid, object, method, *args)
|
||||
cr.close()
|
||||
return res
|
||||
|
||||
if method in ('read'):
|
||||
res_ids = args[0]
|
||||
old_values = {}
|
||||
res = fct_src(db, uid, object, method, *args)
|
||||
if type(res) == list:
|
||||
|
||||
for v in res:
|
||||
old_values[v['id']] = v
|
||||
else:
|
||||
old_values[res['id']] = res
|
||||
for res_id in old_values:
|
||||
if not logged_uids or uid in logged_uids:
|
||||
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
|
||||
resource_name = resource_name and resource_name[0][1] or ''
|
||||
id = pool.get('audittrail.log').create(cr, uid, {"method": method, "object_id": model_object.id, "user_id": uid, "res_id": res_id, "name": resource_name})
|
||||
lines = []
|
||||
for field in old_values[res_id]:
|
||||
if old_values[res_id][field]:
|
||||
line = {
|
||||
'name': field,
|
||||
'old_value': old_values[res_id][field],
|
||||
'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model_object)
|
||||
}
|
||||
lines.append(line)
|
||||
cr.commit()
|
||||
self.create_log_line(cr, uid, id, model_object, lines)
|
||||
cr.close()
|
||||
return res
|
||||
|
||||
if method in ('unlink'):
|
||||
res_ids = args[0]
|
||||
old_values = {}
|
||||
for res_id in res_ids:
|
||||
old_values[res_id] = pool.get(model_object.model).read(cr, uid, res_id, [])
|
||||
|
||||
for res_id in res_ids:
|
||||
if not logged_uids or uid in logged_uids:
|
||||
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
|
||||
resource_name = resource_name and resource_name[0][1] or ''
|
||||
id = pool.get('audittrail.log').create(cr, uid, {"method": method, "object_id": model_object.id, "user_id": uid, "res_id": res_id, "name": resource_name})
|
||||
lines = []
|
||||
for field in old_values[res_id]:
|
||||
if old_values[res_id][field]:
|
||||
line = {
|
||||
'name': field,
|
||||
'old_value': old_values[res_id][field],
|
||||
'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model_object)
|
||||
}
|
||||
lines.append(line)
|
||||
cr.commit()
|
||||
self.create_log_line(cr, uid, id, model_object, lines)
|
||||
res = fct_src(db, uid, object, method, *args)
|
||||
cr.close()
|
||||
return res
|
||||
cr.close()
|
||||
|
||||
def execute(self, db, uid, object, method, *args, **kw):
|
||||
"""
|
||||
Overrides Object Proxy execute method
|
||||
@param db: the current database
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param object: Object who's values are being changed
|
||||
@param method: method to log: create, read, write, unlink
|
||||
|
||||
@return: Returns result as per method of Object proxy
|
||||
"""
|
||||
pool = pooler.get_pool(db)
|
||||
cr = pooler.get_db(db).cursor()
|
||||
cr.autocommit(True)
|
||||
obj=pool.get(object)
|
||||
logged_uids = []
|
||||
fct_src = super(audittrail_objects_proxy, self).execute
|
||||
|
||||
def my_fct(db, uid, object, method, *args):
|
||||
field = method
|
||||
rule = False
|
||||
obj_ids= pool.get('ir.model').search(cr, uid, [('model', '=', object)])
|
||||
obj_ids = pool.get('ir.model').search(cr, uid, [('model', '=', object)])
|
||||
for obj_name in pool.obj_list():
|
||||
if obj_name == 'audittrail.rule':
|
||||
rule = True
|
||||
if not rule:
|
||||
return fct_src(db, uid, object, method, *args)
|
||||
if not len(obj_ids):
|
||||
if not obj_ids:
|
||||
return fct_src(db, uid, object, method, *args)
|
||||
rule_ids=pool.get('audittrail.rule').search(cr, uid, [('object_id', '=', obj_ids[0]), ('state', '=', 'subscribed')])
|
||||
if not len(rule_ids):
|
||||
rule_ids = pool.get('audittrail.rule').search(cr, uid, [('object_id', '=', obj_ids[0]), ('state', '=', 'subscribed')])
|
||||
if not rule_ids:
|
||||
return fct_src(db, uid, object, method, *args)
|
||||
|
||||
for thisrule in pool.get('audittrail.rule').browse(cr, uid, rule_ids):
|
||||
for user in thisrule.user_id:
|
||||
logged_uids.append(user.id)
|
||||
if not len(logged_uids) or uid in logged_uids:
|
||||
if not logged_uids or uid in logged_uids:
|
||||
if field in ('read', 'write', 'create', 'unlink'):
|
||||
if getattr(thisrule, 'log_'+field):
|
||||
if getattr(thisrule, 'log_' + field):
|
||||
return self.log_fct(db, uid, object, method, fct_src, *args)
|
||||
return fct_src(db, uid, object, method, *args)
|
||||
res = my_fct(db, uid, object, method, *args)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Audittrail Rule form -->
|
||||
|
||||
<record model="ir.ui.view" id="view_audittrail_rule_form">
|
||||
<field name="name">audittrail.rule.form</field>
|
||||
<field name="model">audittrail.rule</field>
|
||||
|
@ -17,12 +20,15 @@
|
|||
<field name="user_id" select="1" colspan="4"/>
|
||||
<field name="state" select="1" readonly="1" />
|
||||
<group colspan="2" col="2">
|
||||
<button string="Subscribe" name="subscribe" type="object" states="draft"/>
|
||||
<button string="UnSubscribe" name="unsubscribe" type="object" states="subscribed"/>
|
||||
<button string="Subscribe" name="subscribe"
|
||||
type="object" states="draft" />
|
||||
<button string="UnSubscribe" name="unsubscribe"
|
||||
type="object" states="subscribed" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_audittrail_rule_tree">
|
||||
<field name="name">audittrail.rule.tree</field>
|
||||
<field name="model">audittrail.rule</field>
|
||||
|
@ -40,6 +46,9 @@
|
|||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action for audittrail rule -->
|
||||
|
||||
<record model="ir.actions.act_window" id="action_audittrail_rule_tree">
|
||||
<field name="name">Rules</field>
|
||||
<field name="res_model">audittrail.rule</field>
|
||||
|
@ -48,8 +57,11 @@
|
|||
<field name="view_mode">tree,form</field>
|
||||
<!--<field name="view_id" ref="view_audittrail_rule_form" />-->
|
||||
</record>
|
||||
<menuitem name="Audittrails" id="menu_action_audittrail" parent="base.menu_administration"/>
|
||||
<menuitem name="Rules" id="menu_action_audittrail_rule_tree" action="action_audittrail_rule_tree" parent="menu_action_audittrail"/>
|
||||
|
||||
<menuitem name="Audittrails" id="menu_action_audittrail"
|
||||
parent="base.menu_administration" />
|
||||
<menuitem name="Rules" id="menu_action_audittrail_rule_tree"
|
||||
action="action_audittrail_rule_tree" parent="menu_action_audittrail" />
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_audittrail_rule_tree_sub">
|
||||
|
@ -60,6 +72,8 @@
|
|||
<field name="domain">[('state','=','subscribed')]</field>
|
||||
<field name="filter" eval="True"/>
|
||||
</record>
|
||||
|
||||
<!-- AuditTrail Log form -->
|
||||
|
||||
<record model="ir.ui.view" id="view_audittrail_log_form">
|
||||
<field name="name">audittrail.log.form</field>
|
||||
|
@ -73,23 +87,34 @@
|
|||
<field name="user_id" select="1" readonly="1"/>
|
||||
<field name="res_id" readonly="1"/>
|
||||
<field name="name" readonly="1" select="1"/>
|
||||
<field name="line_ids" colspan="4" mode="tree,form" widget="one2many_list" readonly="1">
|
||||
<field name="line_ids" colspan="4" mode="tree,form"
|
||||
widget="one2many_list" readonly="1">
|
||||
<form string="Log Lines">
|
||||
<field name="field_id" colspan="4" readonly="1"/>
|
||||
<newline/>
|
||||
<field name="field_description" colspan="4" readonly="1"/>
|
||||
<newline/>
|
||||
<separator string="Old Value : " colspan="2"/>
|
||||
<separator string="New Value : " colspan="2"/>
|
||||
<newline/>
|
||||
<field name="old_value" nolabel="1" colspan="2" readonly="1"/>
|
||||
<field name="new_value" nolabel="1" colspan="2" readonly="1"/>
|
||||
<newline/>
|
||||
<separator string="Old Value Text : " colspan="2"/>
|
||||
<separator string="New Value Text: " colspan="2"/>
|
||||
<newline/>
|
||||
<field name="old_value_text" nolabel="1" colspan="2" readonly="1"/>
|
||||
<field name="new_value_text" nolabel="1" colspan="2" readonly="1"/>
|
||||
<field name="field_id" colspan="4"
|
||||
readonly="1" />
|
||||
<newline />
|
||||
<field name="field_description" colspan="4"
|
||||
readonly="1" />
|
||||
<newline />
|
||||
<separator string="Old Value : "
|
||||
colspan="2" />
|
||||
<separator string="New Value : "
|
||||
colspan="2" />
|
||||
<newline />
|
||||
<field name="old_value" nolabel="1"
|
||||
colspan="2" readonly="1" />
|
||||
<field name="new_value" nolabel="1"
|
||||
colspan="2" readonly="1" />
|
||||
<newline />
|
||||
<separator string="Old Value Text : "
|
||||
colspan="2" />
|
||||
<separator string="New Value Text: "
|
||||
colspan="2" />
|
||||
<newline />
|
||||
<field name="old_value_text" nolabel="1"
|
||||
colspan="2" readonly="1" />
|
||||
<field name="new_value_text" nolabel="1"
|
||||
colspan="2" readonly="1" />
|
||||
</form>
|
||||
|
||||
<tree string="Log Lines">
|
||||
|
@ -117,15 +142,19 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action for Audittrail Log -->
|
||||
|
||||
<record model="ir.actions.act_window" id="action_audittrail_log_tree">
|
||||
<field name="name">Logs</field>
|
||||
<field name="res_model">audittrail.log</field>
|
||||
<field name="view_type">form</field>
|
||||
</record>
|
||||
<menuitem name="Logs" id="menu_action_audittrail_log_tree" action="action_audittrail_log_tree" parent="menu_action_audittrail"/>
|
||||
<menuitem name="Logs" id="menu_action_audittrail_log_tree"
|
||||
action="action_audittrail_log_tree" parent="menu_action_audittrail" />
|
||||
|
||||
<wizard string="View log" menu="False" model="audittrail.log" name="audittrail.view.log" id="wizard_audittrail_log"/>
|
||||
<menuitem name="View Logs" id="menu_action_log_tree2" action="wizard_audittrail_log" type="wizard" parent="menu_action_audittrail"/>
|
||||
<!-- <wizard string="View log" menu="False" model="audittrail.log" name="audittrail.view.log" id="wizard_audittrail_log"/>-->
|
||||
<menuitem name="View Logs" id="menu_action_log_tree2"
|
||||
action="action_audittrail_view_log" parent="menu_action_audittrail" />
|
||||
|
||||
</data>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -5,3 +5,4 @@
|
|||
"access_audittrail_rule_all_users","audittrail rule all","model_audittrail_rule","base.group_user",1,0,0,0
|
||||
"access_audittrail_log_all_users","audittrail log all","model_audittrail_log","base.group_user",1,0,1,0
|
||||
"access_audittrail_log_line_all_users","audittrail log line all","model_audittrail_log_line","base.group_user",1,0,1,0
|
||||
"access_audittrail_view_log","audittrail.view.log","model_audittrail_view_log","base.group_user",1,1,1,1
|
||||
|
|
|
|
@ -19,6 +19,6 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import wizard_view_log
|
||||
import audittrail_view_log
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
import time
|
||||
|
||||
class audittrail_view_log(osv.osv_memory):
|
||||
|
||||
_name = "audittrail.view.log"
|
||||
_description = "View Log"
|
||||
_columns = {
|
||||
'from':fields.datetime('Log From'),
|
||||
'to':fields.datetime('Log To', required = True)
|
||||
}
|
||||
_defaults = {
|
||||
'to': lambda *a: time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
|
||||
def log_open_window(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Open Log form from given date range..
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of audittrail view log’s IDs.
|
||||
@return: Dictionary of audittrail log form on given date range.
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
act_obj = self.pool.get('ir.actions.act_window')
|
||||
result = mod_obj._get_id(cr, uid, 'audittrail', 'action_audittrail_log_tree')
|
||||
id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
|
||||
result = act_obj.read(cr, uid, [id])[0]
|
||||
#log_obj = self.pool.get(result['res_model'])
|
||||
#log_id = log_obj.search(cr, uid, [])
|
||||
#log_model = log_obj.read(cr, uid, log_id, ['object_id'])
|
||||
|
||||
#start Loop
|
||||
for datas in self.read(cr, uid, ids):
|
||||
if not datas.get('from', None):
|
||||
if datas.get('to') <> time.strftime("%Y-%m-%d %H:%M:%S"):
|
||||
result['domain'] = str([('timestamp', '<', datas.get('to'))])
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
result['domain'] = str([('timestamp', '>', datas.get('from', None)), ('timestamp', '<', datas.get('to'))])
|
||||
#End Loop
|
||||
return result
|
||||
|
||||
audittrail_view_log()
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Audittrail View Log wizard-->
|
||||
|
||||
<record id="view_audittrail_view_log" model="ir.ui.view">
|
||||
<field name="name">audittrail.view.log.form</field>
|
||||
<field name="model">audittrail.view.log</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Audit Logs">
|
||||
<group colspan="4" >
|
||||
<field name="from" colspan="4"/>
|
||||
<newline/>
|
||||
<field name="to" colspan="4"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<button icon="gtk-cancel" special="cancel"
|
||||
string="Cancel" />
|
||||
<button icon="gtk-open" string="Open Logs"
|
||||
name="log_open_window" type="object" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- action for audittrail view log wizard -->
|
||||
|
||||
<record id="action_audittrail_view_log" model="ir.actions.act_window">
|
||||
<field name="name">View log</field>
|
||||
<field name="res_model">audittrail.view.log</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_audittrail_view_log"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,81 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
import pooler
|
||||
import time
|
||||
|
||||
class wizard_view_log(wizard.interface):
|
||||
|
||||
form1 = '''<?xml version="1.0"?>
|
||||
<form string="Audit Logs">
|
||||
<field name="from" colspan="4"/>
|
||||
<newline/>
|
||||
<field name="to" colspan="4"/>
|
||||
</form>'''
|
||||
|
||||
form1_fields = {
|
||||
'from': {
|
||||
'string': 'Log From',
|
||||
'type': 'datetime',
|
||||
|
||||
},
|
||||
'to': {
|
||||
'string': 'Log To',
|
||||
'type': 'datetime',
|
||||
'default': lambda *a: time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
'required':True
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _log_open_window(self, cr, uid, data, context):
|
||||
mod_obj = pooler.get_pool(cr.dbname).get('ir.model.data')
|
||||
act_obj = pooler.get_pool(cr.dbname).get('ir.actions.act_window')
|
||||
result = mod_obj._get_id(cr, uid, 'audittrail', 'action_audittrail_log_tree')
|
||||
id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
|
||||
result = act_obj.read(cr, uid, [id])[0]
|
||||
log_obj= pooler.get_pool(cr.dbname).get(result['res_model'])
|
||||
log_id = log_obj.search(cr, uid, [])
|
||||
log_model=log_obj.read(cr, uid,log_id,['object_id'])
|
||||
if not data['form']['from']:
|
||||
if data['form']['to'] <> time.strftime("%Y-%m-%d %H:%M:%S"):
|
||||
result['domain'] = str([('timestamp', '<',data['form']['to'])])
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
result['domain'] = str([('timestamp', '>',data['form']['from']),('timestamp', '<',data['form']['to'])])
|
||||
|
||||
return result
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type': 'form', 'arch':form1, 'fields':form1_fields, 'state': [('end', 'Cancel'), ('open', 'Open Logs')]}
|
||||
},
|
||||
'open': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action':_log_open_window, 'state':'end'}
|
||||
}
|
||||
}
|
||||
wizard_view_log('audittrail.view.log')
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -29,61 +29,86 @@ from osv.orm import except_orm
|
|||
from tools.translate import _
|
||||
|
||||
class base_action_rule(osv.osv):
|
||||
""" Base Action Rules """
|
||||
|
||||
_name = 'base.action.rule'
|
||||
_description = 'Action Rules'
|
||||
|
||||
|
||||
_description = 'Action Rules'
|
||||
|
||||
_columns = {
|
||||
'name': fields.many2one('ir.model', 'Model', required=True),
|
||||
'max_level': fields.integer('Max Level', help='Specifies maximum level.'),
|
||||
'max_level': fields.integer('Max Level', help='Specifies maximum level.'),
|
||||
'rule_lines': fields.one2many('base.action.rule.line','rule_id','Rule Lines'),
|
||||
'create_date': fields.datetime('Create Date', readonly=1),
|
||||
'active': fields.boolean('Active')
|
||||
}
|
||||
|
||||
|
||||
_defaults = {
|
||||
'active': lambda *a: True,
|
||||
'max_level': lambda *a: 15,
|
||||
}
|
||||
|
||||
def format_body(self, body):
|
||||
""" Foramat Action rule's body
|
||||
@param self: The object pointer """
|
||||
|
||||
return body and tools.ustr(body) or ''
|
||||
|
||||
def format_mail(self, obj, body):
|
||||
""" Foramat Mail
|
||||
@param self: The object pointer """
|
||||
|
||||
data = {
|
||||
'object_id': obj.id,
|
||||
'object_subject': hasattr(obj, 'name') and obj.name or False,
|
||||
'object_date': hasattr(obj, 'date') and obj.date or False,
|
||||
'object_description': hasattr(obj, 'description') and obj.description or False,
|
||||
'object_user': hasattr(obj, 'user_id') and (obj.user_id and obj.user_id.name) or '/',
|
||||
'object_user_email': hasattr(obj, 'user_id') and (obj.user_id and obj.user_id.address_id and obj.user_id.address_id.email) or '/',
|
||||
'object_user_phone': hasattr(obj, 'user_id') and (obj.user_id and obj.user_id.address_id and obj.user_id.address_id.phone) or '/',
|
||||
'object_user_email': hasattr(obj, 'user_id') and (obj.user_id and \
|
||||
obj.user_id.address_id and obj.user_id.address_id.email) or '/',
|
||||
'object_user_phone': hasattr(obj, 'user_id') and (obj.user_id and\
|
||||
obj.user_id.address_id and obj.user_id.address_id.phone) or '/',
|
||||
'partner': hasattr(obj, 'partner_id') and (obj.partner_id and obj.partner_id.name) or '/',
|
||||
'partner_email': hasattr(obj, 'partner_address_id') and (obj.partner_address_id and obj.partner_address_id.email) or '/',
|
||||
'partner_email': hasattr(obj, 'partner_address_id') and (obj.partner_address_id and\
|
||||
obj.partner_address_id.email) or '/',
|
||||
}
|
||||
return self.format_body(body % data)
|
||||
|
||||
def email_send(self, cr, uid, obj, emails, body, emailfrom=tools.config.get('email_from',False), context={}):
|
||||
""" send email
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param email: pass the emails
|
||||
@param emailfrom: Pass name the email From else False
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
body = self.format_mail(obj, body)
|
||||
if not emailfrom:
|
||||
if hasattr(obj, 'user_id') and obj.user_id and obj.user_id.address_id and obj.user_id.address_id.email:
|
||||
if hasattr(obj, 'user_id') and obj.user_id and obj.user_id.address_id and\
|
||||
obj.user_id.address_id.email:
|
||||
emailfrom = obj.user_id.address_id.email
|
||||
|
||||
|
||||
name = '[%d] %s' % (obj.id, tools.ustr(obj.name))
|
||||
emailfrom = tools.ustr(emailfrom)
|
||||
reply_to = emailfrom
|
||||
reply_to = emailfrom
|
||||
if not emailfrom:
|
||||
raise osv.except_osv(_('Error!'),
|
||||
_("No E-Mail ID Found for your Company address!"))
|
||||
return tools.email_send(emailfrom, emails, name, body, reply_to=reply_to, openobject_id=str(obj.id))
|
||||
|
||||
|
||||
|
||||
def do_check(self, cr, uid, action, obj, context={}):
|
||||
ok = True
|
||||
if hasattr(obj, 'user_id'):
|
||||
""" check Action
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
ok = True
|
||||
if hasattr(obj, 'user_id'):
|
||||
ok = ok and (not action.trg_user_id.id or action.trg_user_id.id==obj.user_id.id)
|
||||
if hasattr(obj, 'partner_id'):
|
||||
ok = ok and (not action.trg_partner_id.id or action.trg_partner_id.id==obj.partner_id.id)
|
||||
ok = ok and (not action.trg_partner_id.id or action.trg_partner_id.id==obj.partner_id.id)
|
||||
ok = ok and (
|
||||
not action.trg_partner_categ_id.id or
|
||||
(
|
||||
|
@ -113,14 +138,22 @@ class base_action_rule(osv.osv):
|
|||
return ok
|
||||
|
||||
def do_action(self, cr, uid, action, model_obj, obj, context={}):
|
||||
""" Do Action
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param action: pass action
|
||||
@param model_obj: pass Model object
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
if action.server_action_id:
|
||||
context.update({'active_id':obj.id,'active_ids':[obj.id]})
|
||||
self.pool.get('ir.actions.server').run(cr, uid, [action.server_action_id.id], context)
|
||||
write = {}
|
||||
write = {}
|
||||
if hasattr(obj, 'user_id') and action.act_user_id:
|
||||
obj.user_id = action.act_user_id
|
||||
write['user_id'] = action.act_user_id.id
|
||||
if hasattr(obj, 'date_action_last'):
|
||||
if hasattr(obj, 'date_action_last'):
|
||||
write['date_action_last'] = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
if hasattr(obj, 'state') and action.act_state:
|
||||
obj.state = action.act_state
|
||||
|
@ -135,7 +168,7 @@ class base_action_rule(osv.osv):
|
|||
write['priority'] = action.act_priority
|
||||
|
||||
model_obj.write(cr, uid, [obj.id], write, context)
|
||||
|
||||
|
||||
if hasattr(model_obj, 'remind_user') and action.act_remind_user:
|
||||
model_obj.remind_user(cr, uid, [obj.id], context, attach=action.act_remind_attach)
|
||||
if hasattr(model_obj, 'remind_partner') and action.act_remind_partner:
|
||||
|
@ -146,7 +179,7 @@ class base_action_rule(osv.osv):
|
|||
if hasattr(obj, 'user_id') and action.act_mail_to_user:
|
||||
if obj.user_id and obj.user_id.address_id:
|
||||
emails.append(obj.user_id.address_id.email)
|
||||
|
||||
|
||||
if action.act_mail_to_watchers:
|
||||
emails += (action.act_email_cc or '').split(',')
|
||||
if action.act_mail_to_email:
|
||||
|
@ -158,11 +191,19 @@ class base_action_rule(osv.osv):
|
|||
return True
|
||||
|
||||
def _action(self, cr, uid, ids, objects, scrit=None, context={}):
|
||||
""" Do Action
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Basic Action Rule’s IDs,
|
||||
@param objects: pass objects
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
if not scrit:
|
||||
scrit = []
|
||||
rule_line_obj = self.pool.get('base.action.rule.line')
|
||||
for rule in self.browse(cr, uid, ids):
|
||||
level = rule.max_level
|
||||
for rule in self.browse(cr, uid, ids):
|
||||
level = rule.max_level
|
||||
if not level:
|
||||
break
|
||||
newactions = []
|
||||
|
@ -184,7 +225,8 @@ class base_action_rule(osv.osv):
|
|||
base = mx.DateTime.strptime(obj.date_action_last, '%Y-%m-%d %H:%M:%S')
|
||||
else:
|
||||
base = mx.DateTime.strptime(obj.create_date[:19], '%Y-%m-%d %H:%M:%S')
|
||||
elif hasattr(obj, 'date_deadline') and action.trg_date_type=='deadline' and obj.date_deadline:
|
||||
elif hasattr(obj, 'date_deadline') and action.trg_date_type=='deadline' \
|
||||
and obj.date_deadline:
|
||||
base = mx.DateTime.strptime(obj.date_deadline, '%Y-%m-%d %H:%M:%S')
|
||||
elif hasattr(obj, 'date') and action.trg_date_type=='date' and obj.date:
|
||||
base = mx.DateTime.strptime(obj.date, '%Y-%m-%d %H:%M:%S')
|
||||
|
@ -212,7 +254,7 @@ class base_action_rule(osv.osv):
|
|||
|
||||
if ok:
|
||||
self.do_action(cr, uid, action, model_obj, obj, context)
|
||||
break
|
||||
break
|
||||
level -= 1
|
||||
return True
|
||||
base_action_rule()
|
||||
|
@ -222,20 +264,46 @@ class base_action_rule_line(osv.osv):
|
|||
_description = 'Action Rule Lines'
|
||||
|
||||
def _state_get(self, cr, uid, context={}):
|
||||
""" Get State
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
return self.state_get(cr, uid, context=context)
|
||||
def _priority_get(self, cr, uid, context={}):
|
||||
""" Get Priority
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
return self.priority_get(cr, uid, context=context)
|
||||
|
||||
def state_get(self, cr, uid, context={}):
|
||||
""" Get State
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
return [('','')]
|
||||
def priority_get(self, cr, uid, context={}):
|
||||
""" Get Priority
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
return [('','')]
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Rule Name',size=64, required=True),
|
||||
'rule_id': fields.many2one('base.action.rule','Rule'),
|
||||
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the rule without removing it."),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of rules."),
|
||||
'active': fields.boolean('Active', help="If the active field is set to true,\
|
||||
it will allow you to hide the rule without removing it."),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when\
|
||||
displaying a list of rules."),
|
||||
|
||||
'trg_date_type': fields.selection([
|
||||
('none','None'),
|
||||
|
@ -243,11 +311,13 @@ class base_action_rule_line(osv.osv):
|
|||
('action_last','Last Action Date'),
|
||||
('date','Date'),
|
||||
], 'Trigger Date', size=16),
|
||||
'trg_date_range': fields.integer('Delay after trigger date',help="Delay After Trigger Date, specifies you can put a negative number " \
|
||||
"if you need a delay before the trigger date, like sending a reminder 15 minutes before a meeting."),
|
||||
'trg_date_range_type': fields.selection([('minutes', 'Minutes'),('hour','Hours'),('day','Days'),('month','Months')], 'Delay type'),
|
||||
'trg_date_range': fields.integer('Delay after trigger date',help="Delay After Trigger Date,\
|
||||
specifies you can put a negative number " \
|
||||
"if you need a delay before the trigger date, like sending a reminder 15 minutes before a meeting."),
|
||||
'trg_date_range_type': fields.selection([('minutes', 'Minutes'),('hour','Hours'),\
|
||||
('day','Days'),('month','Months')], 'Delay type'),
|
||||
|
||||
|
||||
|
||||
'trg_user_id': fields.many2one('res.users', 'Responsible'),
|
||||
|
||||
'trg_partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
|
@ -255,42 +325,59 @@ class base_action_rule_line(osv.osv):
|
|||
'trg_state_from': fields.selection(_state_get, 'State', size=16),
|
||||
'trg_state_to': fields.selection(_state_get, 'Button Pressed', size=16),
|
||||
'trg_priority_from': fields.selection(_priority_get, 'Minimum Priority'),
|
||||
'trg_priority_to': fields.selection(_priority_get, 'Maximum Priority'),
|
||||
|
||||
'act_method': fields.char('Call Object Method', size=64),
|
||||
'act_user_id': fields.many2one('res.users', 'Set responsible to'),
|
||||
'trg_priority_to': fields.selection(_priority_get, 'Maximum Priority'),
|
||||
|
||||
'act_method': fields.char('Call Object Method', size=64),
|
||||
'act_user_id': fields.many2one('res.users', 'Set responsible to'),
|
||||
'act_state': fields.selection(_state_get, 'Set state to', size=16),
|
||||
'act_priority': fields.selection(_priority_get, 'Set priority to'),
|
||||
'act_email_cc': fields.char('Add watchers (Cc)', size=250, help="These people will receive a copy of the future communication between partner and users by email"),
|
||||
'act_priority': fields.selection(_priority_get, 'Set priority to'),
|
||||
'act_email_cc': fields.char('Add watchers (Cc)', size=250, help="These people\
|
||||
will receive a copy of the future communication between partner and users by email"),
|
||||
|
||||
'act_remind_partner': fields.boolean('Remind Partner', help="Check this if you want the rule to send a reminder by email to the partner."),
|
||||
'act_remind_user': fields.boolean('Remind responsible', help="Check this if you want the rule to send a reminder by email to the user."),
|
||||
'act_remind_partner': fields.boolean('Remind Partner', help="Check this if\
|
||||
you want the rule to send a reminder by email to the partner."),
|
||||
'act_remind_user': fields.boolean('Remind responsible', help="Check this if \
|
||||
you want the rule to send a reminder by email to the user."),
|
||||
'act_reply_to': fields.char('Reply-To', size=64),
|
||||
'act_remind_attach': fields.boolean('Remind with attachment', help="Check this if you want that all documents attached to the object be attached to the reminder email sent."),
|
||||
'act_remind_attach': fields.boolean('Remind with attachment', help="Check this if\
|
||||
you want that all documents attached to the object be attached \
|
||||
to the reminder email sent."),
|
||||
|
||||
'act_mail_to_user': fields.boolean('Mail to responsible',help="Check this if you want the rule to send an email to the responsible person."),
|
||||
'act_mail_to_watchers': fields.boolean('Mail to watchers (CC)',help="Check this if you want the rule to mark CC(mail to any other person defined in actions)."),
|
||||
'act_mail_to_email': fields.char('Mail to these emails', size=128,help="Email-id of the persons whom mail is to be sent"),
|
||||
'act_mail_to_user': fields.boolean('Mail to responsible',help="Check this if \
|
||||
you want the rule to send an email to the responsible person."),
|
||||
'act_mail_to_watchers': fields.boolean('Mail to watchers (CC)',help="Check this\
|
||||
if you want the rule to mark CC(mail to any other person\
|
||||
defined in actions)."),
|
||||
'act_mail_to_email': fields.char('Mail to these emails', size=128,help="Email-id \
|
||||
of the persons whom mail is to be sent"),
|
||||
'act_mail_body': fields.text('Mail body',help="Content of mail"),
|
||||
'regex_name': fields.char('Regular Expression on Model Name', size=128),
|
||||
'server_action_id': fields.many2one('ir.actions.server','Server Action',help="Describes the action name." \
|
||||
"eg:on which object which action to be taken on basis of which condition"),
|
||||
'server_action_id': fields.many2one('ir.actions.server','Server Action',help="Describes the\
|
||||
action name." \
|
||||
"eg:on which object which action to be taken on basis of which condition"),
|
||||
}
|
||||
|
||||
|
||||
_defaults = {
|
||||
'active': lambda *a: 1,
|
||||
'trg_date_type': lambda *a: 'none',
|
||||
'trg_date_range_type': lambda *a: 'day',
|
||||
'act_mail_to_user': lambda *a: 0,
|
||||
'act_remind_partner': lambda *a: 0,
|
||||
'act_remind_user': lambda *a: 0,
|
||||
'act_remind_user': lambda *a: 0,
|
||||
'act_mail_to_watchers': lambda *a: 0,
|
||||
}
|
||||
|
||||
_order = 'sequence'
|
||||
|
||||
|
||||
|
||||
_order = 'sequence'
|
||||
|
||||
|
||||
def _check_mail(self, cr, uid, ids, context=None):
|
||||
""" Check Mail
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Action Rule’s IDs
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
empty = orm.browse_null()
|
||||
rule_obj = self.pool.get('base.action.rule')
|
||||
for rule in self.browse(cr, uid, ids):
|
||||
|
@ -300,10 +387,11 @@ class base_action_rule_line(osv.osv):
|
|||
except (ValueError, KeyError, TypeError):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
_constraints = [
|
||||
(_check_mail, 'Error: The mail is not well formated', ['act_mail_body']),
|
||||
]
|
||||
|
||||
|
||||
base_action_rule_line()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<menuitem id="menu_base_action_rule" name="Action Rule" parent="base.menu_base_config" sequence="0"/>
|
||||
<menuitem id="menu_base_action_rule" name="Action Rule"
|
||||
parent="base.menu_base_config" sequence="0" />
|
||||
|
||||
<!--
|
||||
Action Rule
|
||||
<!--
|
||||
Action Rule Form View
|
||||
-->
|
||||
<record id="view_base_action_rule_form" model="ir.ui.view">
|
||||
<field name="name">base.action.rule.form</field>
|
||||
|
@ -21,6 +22,8 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action Rule Tree View -->
|
||||
|
||||
<record id="view_base_action_rule_tree" model="ir.ui.view">
|
||||
<field name="name">base.action.rule.tree</field>
|
||||
<field name="model">base.action.rule</field>
|
||||
|
@ -34,6 +37,8 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action Rule Action -->
|
||||
|
||||
<record id="base_action_rule_act" model="ir.actions.act_window">
|
||||
<field name="name">Action Rules</field>
|
||||
<field name="res_model">base.action.rule</field>
|
||||
|
@ -42,10 +47,11 @@
|
|||
<field name="view_id" ref="view_base_action_rule_tree"/>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_base_action_rule_form" parent="menu_base_action_rule" action="base_action_rule_act"/>
|
||||
<menuitem id="menu_base_action_rule_form"
|
||||
parent="menu_base_action_rule" action="base_action_rule_act" />
|
||||
|
||||
<!--
|
||||
Action Rule Lines
|
||||
<!--
|
||||
Action Rule Lines Form View
|
||||
-->
|
||||
<record id="view_base_action_rule_line_form" model="ir.ui.view">
|
||||
<field name="name">base.action.rule.line.form</field>
|
||||
|
@ -127,6 +133,9 @@
|
|||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action Rule Lines Tree View -->
|
||||
|
||||
<record id="view_base_action_rule_line_tree" model="ir.ui.view">
|
||||
<field name="name">base.action.rule.line.tree</field>
|
||||
<field name="model">base.action.rule.line</field>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
|
@ -15,36 +15,33 @@
|
|||
# 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/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
{
|
||||
"name" : "Basic Calendar Functionality",
|
||||
"version" : "1.0",
|
||||
"depends" : [
|
||||
"base",
|
||||
],
|
||||
'description': """
|
||||
Full featured calendar system that support:
|
||||
- Alerts (create requests)
|
||||
- Recurring events (*)
|
||||
- Invitations to other people
|
||||
""",
|
||||
"author" : "Tiny",
|
||||
'category': 'Generic Modules/Others',
|
||||
'website': 'http://www.openerp.com',
|
||||
"name" : "Basic Calendar Functionality",
|
||||
"version" : "1.0",
|
||||
"depends" : ["base"],
|
||||
'description': """Full featured calendar system that support:
|
||||
- Alerts (create requests)
|
||||
- Recurring events (*)
|
||||
- Invitations to others people""",
|
||||
"author" : "Tiny",
|
||||
'category': 'Generic Modules/Others',
|
||||
'website': 'http://www.openerp.com',
|
||||
"init_xml" : [
|
||||
'base_calendar_data.xml'
|
||||
],
|
||||
"demo_xml" : [],
|
||||
'base_calendar_data.xml'
|
||||
],
|
||||
"demo_xml" : [],
|
||||
"update_xml" : [
|
||||
'security/ir.model.access.csv',
|
||||
'base_calendar_view.xml'
|
||||
],
|
||||
"installable" : True,
|
||||
"active" : False,
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/calendar_event_edit_all_view.xml',
|
||||
'wizard/base_calendar_invite_attendee_view.xml',
|
||||
'base_calendar_view.xml'
|
||||
],
|
||||
"installable" : True,
|
||||
"active" : False,
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,141 +1,112 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Attendee invite wizard-->
|
||||
|
||||
<record id="view_calendar_invite_attendee_wizard" model="ir.ui.view">
|
||||
<field name="name">Invite Attendees</field>
|
||||
<field name="model">base_calendar.invite.attendee</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Invite People">
|
||||
<field name="type" />
|
||||
<field name="send_mail" />
|
||||
<newline/>
|
||||
<group col="1" colspan="4"
|
||||
attrs="{'invisible': [('type', '!=', 'external')]}">
|
||||
<field name="email" colspan="4"
|
||||
attrs="{'required': [('type', '=', 'external')]}" />
|
||||
</group>
|
||||
<group col="1" colspan="4"
|
||||
attrs="{'invisible': [('type', '!=', 'internal')]}">
|
||||
<separator string="Users" colspan="4" />
|
||||
<field name="user_ids" select="1" colspan="4"
|
||||
nolabel="1" />
|
||||
<newline />
|
||||
</group>
|
||||
<group col="2" colspan="4"
|
||||
attrs="{'invisible': [('type', '!=', 'partner')]}">
|
||||
<field name="partner_id" colspan="2"
|
||||
on_change="onchange_partner_id(partner_id)"
|
||||
attrs="{'required': [('type', '=', 'partner')]}" />
|
||||
<newline />
|
||||
<separator string="Partner Contacts"
|
||||
colspan="4" />
|
||||
<field name="contact_ids" select="1" colspan="4"
|
||||
nolabel="1" domain="[('partner_id', '=', partner_id)]"
|
||||
attrs="{'readonly': [('type', '!=', 'partner')]}" />
|
||||
</group>
|
||||
<newline/>
|
||||
<separator string="" colspan="6" />
|
||||
<label string="" colspan="2" />
|
||||
<button icon='gtk-cancel' special="cancel"
|
||||
string="Cancel" />
|
||||
<button name="do_invite" string="Invite"
|
||||
type="object" icon="gtk-ok" />
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_calendar_invite_attendee_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Invite Attendees</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">base_calendar.invite.attendee</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<record id="base_calendar_attendee_form_view" model="ir.ui.view">
|
||||
<field name="name">calendar.attendee.form</field>
|
||||
<field name="model">calendar.attendee</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Invitation details">
|
||||
<field name="email" string="Invitation To"/>
|
||||
<field name="sent_by_uid" string="Invitation From"/>
|
||||
<notebook colspan="4">
|
||||
<page string="Invitation">
|
||||
<form string="Invitation details">
|
||||
<field name="email" string="Invitation To"/>
|
||||
<field name="sent_by_uid" string="Invitation From" />
|
||||
<notebook colspan="4">
|
||||
<page string="Invitation">
|
||||
<separator string="Invitation Detail" colspan="4" />
|
||||
<group colspan="4" col="4">
|
||||
<field name="user_id" string="Invited User"/>
|
||||
<newline/>
|
||||
<field name="partner_address_id" string="Partner Contact"/>
|
||||
<field name="partner_id" string="Partner" readonly="1"/>
|
||||
<field name="partner_address_id"
|
||||
string="Partner Contact" />
|
||||
<field name="partner_id"
|
||||
string="Partner" readonly="1" />
|
||||
<field name="role" string="Role" />
|
||||
<field name="cutype" string="Invitation type" />
|
||||
<field name="rsvp" />
|
||||
<field name="rsvp" />
|
||||
</group>
|
||||
<separator string="Event Detail" colspan="4" />
|
||||
<group colspan="4" col="4">
|
||||
<field name="event_date" />
|
||||
<field name="event_end_date" />
|
||||
<field name="language"/>
|
||||
<field name="ref" colspan="4"/>
|
||||
<field name="ref" colspan="4" readonly="1"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Delegation Info">
|
||||
<separator string="Delegated From" colspan="4" />
|
||||
<field name="parent_ids" nolabel="1"
|
||||
colspan="4" readonly="1" />
|
||||
<separator string="Delegated To" colspan="4" />
|
||||
<field name="child_ids" nolabel="1"
|
||||
colspan="4" readonly="1" />
|
||||
</page>
|
||||
</notebook>
|
||||
<group col="6" colspan="4">
|
||||
<field name="state" select="2" />
|
||||
<button name="do_tentative" states="needs-action,declined,accepted"
|
||||
string="Uncertain" type="object"
|
||||
icon="terp-crm" />
|
||||
<button name="do_accept" string="Accept" states="needs-action,tentative,declined"
|
||||
type="object" icon="gtk-apply" />
|
||||
<button name="do_decline" string="Decline" states="needs-action,tentative,accepted"
|
||||
type="object" icon="gtk-cancel" />
|
||||
<button
|
||||
name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d"
|
||||
string="Delegate" type="action"
|
||||
icon="gtk-sort-descending" states="needs-action,tentative,declined,accepted"
|
||||
context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}" />
|
||||
</group>
|
||||
</form>
|
||||
</page>
|
||||
<page string="Delegation Info">
|
||||
<separator string="Delegated From" colspan="4" />
|
||||
<field name="parent_ids" nolabel="1"
|
||||
colspan="4" readonly="1" />
|
||||
<separator string="Delegated To" colspan="4" />
|
||||
<field name="child_ids" nolabel="1"
|
||||
colspan="4" readonly="1" />
|
||||
</page>
|
||||
</notebook>
|
||||
<group col="6" colspan="4">
|
||||
<field name="state" />
|
||||
<button name="do_tentative"
|
||||
states="needs-action,declined,accepted"
|
||||
string="Uncertain" type="object"
|
||||
icon="terp-crm" />
|
||||
<button name="do_accept" string="Accept"
|
||||
states="needs-action,tentative,declined"
|
||||
type="object" icon="gtk-apply" />
|
||||
<button name="do_decline" string="Decline"
|
||||
states="needs-action,tentative,accepted"
|
||||
type="object" icon="gtk-cancel" />
|
||||
<button
|
||||
name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d"
|
||||
string="Delegate" type="action"
|
||||
icon="gtk-sort-descending"
|
||||
states="needs-action,tentative,declined,accepted"
|
||||
context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="base_calendar_attendee_tree_view" model="ir.ui.view">
|
||||
<record id="base_calendar_attendee_tree_view" model="ir.ui.view">
|
||||
<field name="name">calendar.attendee.tree</field>
|
||||
<field name="model">calendar.attendee</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Invitation details">
|
||||
<field name="email" string="Invitation To"/>
|
||||
<tree string="Invitation details">
|
||||
<field name="email" string="Invitation To"/>
|
||||
<field name="partner_id" string="Partner" />
|
||||
<field name="partner_address_id" string="Contact" />
|
||||
<field name="role" />
|
||||
<field name="state" />
|
||||
</tree>
|
||||
<field name="role" />
|
||||
<field name="state" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
</record>
|
||||
|
||||
<record id="base_calendar_attendee_search_view" model="ir.ui.view">
|
||||
<field name="name">calendar.attendee.search</field>
|
||||
<field name="model">calendar.attendee</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Invitations">
|
||||
<filter icon="gtk-apply" string="Accepted"
|
||||
domain="[('state','=', 'accepted')]"
|
||||
separator="1" help="Accepted Invitations" />
|
||||
<filter icon="gtk-close" string="Declined"
|
||||
domain="[('state','=', 'declined')]"
|
||||
separator="1" help="Declined Invitations" />
|
||||
<separator orientation="vertical"/>
|
||||
<field name="email" select='1'/>
|
||||
<field name="sent_by_uid" select="1" widget="selection"/>
|
||||
<separator orientation="vertical"/>
|
||||
<field name="cutype" string="Invitation type" select="1"/>
|
||||
<field name="event_date" select="1"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<record id="res_alarm_form_view" model="ir.ui.view">
|
||||
<field name="name">res.alarm.form</field>
|
||||
<field name="model">res.alarm</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Reminder details">
|
||||
<form string="Reminder details">
|
||||
<field name="name" />
|
||||
<field name="active" />
|
||||
<separator string="Reminder Details" colspan="4" />
|
||||
|
@ -146,7 +117,7 @@
|
|||
<separator string="" colspan="4" />
|
||||
<field name="duration" />
|
||||
<field name="repeat" />
|
||||
</form>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
@ -154,34 +125,31 @@
|
|||
<field name="name">res.alarm.tree</field>
|
||||
<field name="model">res.alarm</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Reminder details">
|
||||
<field name="name" select="1"/>
|
||||
<field name="trigger_interval" select="1"/>
|
||||
<field name="trigger_duration" select="1"/>
|
||||
<field name="trigger_occurs" select="1"/>
|
||||
<field name="trigger_related" select="1"/>
|
||||
</tree>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Reminder details">
|
||||
<field name="name" select="1"/>
|
||||
<field name="trigger_interval" select="1"/>
|
||||
<field name="trigger_duration" select="1"/>
|
||||
<field name="trigger_occurs" select="1"/>
|
||||
<field name="trigger_related" select="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_res_alarm_view" model="ir.actions.act_window">
|
||||
<field name="name">Available Alarms</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">res.alarm</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="name">Available Alarms</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">res.alarm</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Available alarms-->
|
||||
<menuitem id="base.menu_calendar_configuration" name="Calendar"
|
||||
parent="base.menu_base_config" sequence="10" />
|
||||
<!--Available alarms-->
|
||||
<menuitem id="base.menu_calendar_configuration" name="Calendar"
|
||||
parent="base.menu_base_config" sequence="10" />
|
||||
|
||||
<menuitem name="Available Alarms" id="menu_crm_meeting_avail_alarm"
|
||||
action="base_calendar.action_res_alarm_view"
|
||||
parent="base.menu_calendar_configuration" />
|
||||
|
||||
<menuitem name="Available Alarms" id="menu_crm_meeting_avail_alarm"
|
||||
action="base_calendar.action_res_alarm_view"
|
||||
parent="base.menu_calendar_configuration" />
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -5,3 +5,4 @@
|
|||
"access_calendar_event_all","calendar.event","model_calendar_event",,1,1,1,1
|
||||
"access_calendar_todo","calendar.todo","model_calendar_todo",,1,1,1,1
|
||||
"access_base_calendar_invite_attendee","base_calendar.invite.attendee","model_base_calendar_invite_attendee",,1,1,1,1
|
||||
"access_calendar_event_edit_all","calendar_event_edit_all","model_calendar_event_edit_all",,1,1,1,1
|
||||
|
|
|
|
@ -18,7 +18,9 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import wizard_cal_edit_event
|
||||
|
||||
import calendar_event_edit_all
|
||||
import base_calendar_invite_attendee
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 base_calendar import base_calendar
|
||||
from osv import fields, osv
|
||||
from tools.translate import _
|
||||
import tools
|
||||
|
||||
|
||||
class base_calendar_invite_attendee(osv.osv_memory):
|
||||
"""
|
||||
Invite attendee.
|
||||
"""
|
||||
|
||||
_name = "base_calendar.invite.attendee"
|
||||
_description = "Invite Attendees"
|
||||
|
||||
_columns = {
|
||||
'type': fields.selection([('internal', 'Internal User'), \
|
||||
('external', 'External Email'), \
|
||||
('partner', 'Partner Contacts')], 'Type', required=True),
|
||||
'user_ids': fields.many2many('res.users', 'invite_user_rel',
|
||||
'invite_id', 'user_id', 'Users'),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
'email': fields.char('Email', size=124),
|
||||
'contact_ids': fields.many2many('res.partner.address', 'invite_contact_rel',
|
||||
'invite_id', 'contact_id', 'Contacts'),
|
||||
'send_mail': fields.boolean('Send mail?', help='Check this if you want to \
|
||||
send an Email to Invited Person')
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'type': lambda *x: 'internal'
|
||||
}
|
||||
|
||||
def do_invite(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Invites attendee for meeting..
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of base calendar invite attendee’s IDs.
|
||||
@param context: A standard dictionary for contextual values
|
||||
@return: Dictionary of {}.
|
||||
"""
|
||||
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
model = False
|
||||
model_field = False
|
||||
|
||||
context_id = context and context.get('active_id', False) or False
|
||||
if not context or not context.get('model'):
|
||||
return {}
|
||||
else:
|
||||
model = context.get('model')
|
||||
model_field = context.get('attendee_field', False)
|
||||
|
||||
for datas in self.read(cr, uid, ids, context=context):
|
||||
|
||||
obj = self.pool.get(model)
|
||||
res_obj = obj.browse(cr, uid, context_id)
|
||||
type = datas.get('type')
|
||||
att_obj = self.pool.get('calendar.attendee')
|
||||
vals = []
|
||||
mail_to = []
|
||||
attendees = []
|
||||
ref = {}
|
||||
|
||||
if not model == 'calendar.attendee':
|
||||
if context_id:
|
||||
ref = {'ref': '%s,%s' % (model, base_calendar.base_calendar_id2real_id(context_id))}
|
||||
else:
|
||||
return {}
|
||||
if type == 'internal':
|
||||
user_obj = self.pool.get('res.users')
|
||||
if not datas.get('user_ids'):
|
||||
raise osv.except_osv(_('Error!'), ("Please select any User"))
|
||||
for user_id in datas.get('user_ids'):
|
||||
user = user_obj.browse(cr, uid, user_id)
|
||||
res = {
|
||||
'user_id': user_id,
|
||||
'email': user.address_id.email
|
||||
}
|
||||
res.update(ref)
|
||||
vals.append(res)
|
||||
if user.address_id.email:
|
||||
mail_to.append(user.address_id.email)
|
||||
|
||||
elif type == 'external' and datas.get('email'):
|
||||
res = {'email': datas['email']}
|
||||
res.update(ref)
|
||||
vals.append(res)
|
||||
mail_to.append(datas['email'])
|
||||
|
||||
elif type == 'partner':
|
||||
add_obj = self.pool.get('res.partner.address')
|
||||
for contact in add_obj.browse(cr, uid, datas['contact_ids']):
|
||||
res = {
|
||||
'partner_address_id': contact.id,
|
||||
'email': contact.email
|
||||
}
|
||||
res.update(ref)
|
||||
vals.append(res)
|
||||
if contact.email:
|
||||
mail_to.append(contact.email)
|
||||
|
||||
att = att_obj.browse(cr, uid, context_id)
|
||||
|
||||
for att_val in vals:
|
||||
if model == 'calendar.attendee':
|
||||
if ref:
|
||||
att_val.update({
|
||||
'parent_ids': [(4, att.id)],
|
||||
'ref': att.ref._name + ',' +str(att.ref.id)
|
||||
})
|
||||
attendees.append(att_obj.create(cr, uid, att_val))
|
||||
if model_field:
|
||||
for attendee in attendees:
|
||||
obj.write(cr, uid, res_obj.id, {model_field: [(4, attendee)]})
|
||||
|
||||
if datas.get('send_mail'):
|
||||
if not mail_to:
|
||||
name = map(lambda x: x[1], filter(lambda x: type==x[0], \
|
||||
self._columns['type'].selection))
|
||||
raise osv.except_osv(_('Error!'), ("%s must have an email Address to send mail") %(name[0]))
|
||||
att_obj._send_mail(cr, uid, attendees, mail_to, \
|
||||
email_from= tools.config.get('email_from', False))
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, partner_id, *args, **argv):
|
||||
"""
|
||||
Make entry on contact_ids on change of partner_id field.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of base calendar invite attendee’s IDs.
|
||||
@param partner_id: id of Partner
|
||||
@return: dictionary of value.
|
||||
"""
|
||||
|
||||
if not partner_id:
|
||||
return {'value': {'contact_ids': []}}
|
||||
cr.execute('select id from res_partner_address \
|
||||
where partner_id=%s' % (partner_id))
|
||||
contacts = map(lambda x: x[0], cr.fetchall())
|
||||
return {'value': {'contact_ids': contacts}}
|
||||
|
||||
base_calendar_invite_attendee()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- Attendee invite wizard-->
|
||||
|
||||
<record id="view_calendar_invite_attendee_wizard"
|
||||
model="ir.ui.view">
|
||||
<field name="name">Invite Attendees</field>
|
||||
<field name="model">base_calendar.invite.attendee</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Invite People">
|
||||
<field name="type" />
|
||||
<field name="send_mail" />
|
||||
<newline />
|
||||
<group col="1" colspan="4"
|
||||
attrs="{'invisible': [('type', '!=', 'external')]}">
|
||||
<field name="email" colspan="4"
|
||||
attrs="{'required': [('type', '=', 'external')]}" />
|
||||
</group>
|
||||
<group col="1" colspan="4"
|
||||
attrs="{'invisible': [('type', '!=', 'internal')]}">
|
||||
<separator string="Users" colspan="4" />
|
||||
<field name="user_ids" select="1" colspan="4"
|
||||
nolabel="1" />
|
||||
<newline />
|
||||
</group>
|
||||
<group col="2" colspan="4"
|
||||
attrs="{'invisible': [('type', '!=', 'partner')]}">
|
||||
<field name="partner_id" colspan="2"
|
||||
on_change="onchange_partner_id(partner_id)"
|
||||
attrs="{'required': [('type', '=', 'partner')]}" />
|
||||
<newline />
|
||||
<separator string="Partner Contacts"
|
||||
colspan="4" />
|
||||
<field name="contact_ids" select="1" colspan="4"
|
||||
nolabel="1" domain="[('partner_id', '=', partner_id)]"
|
||||
attrs="{'readonly': [('type', '!=', 'partner')]}" />
|
||||
</group>
|
||||
<newline />
|
||||
<separator string="" colspan="6" />
|
||||
<label string="" colspan="2" />
|
||||
<button icon='gtk-cancel' special="cancel"
|
||||
string="Cancel" />
|
||||
<button name="do_invite" string="Invite"
|
||||
type="object" icon="gtk-ok" />
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Attendee invite action-->
|
||||
|
||||
<record id="action_view_calendar_invite_attendee_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Invite Attendees</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">base_calendar.invite.attendee</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,98 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import osv
|
||||
from osv import fields
|
||||
|
||||
class calendar_event_edit_all(osv.osv_memory):
|
||||
|
||||
def _default_values(self, cr, uid, context={}):
|
||||
""" Get Default value for Start Date
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values
|
||||
@Return: Get Default value for Start Date
|
||||
"""
|
||||
context_id = context and context.get('active_id', False) or False
|
||||
if context_id:
|
||||
if context.get('date'):
|
||||
return context.get('date')
|
||||
else:
|
||||
model = context.get('model', False)
|
||||
model_obj = self.pool.get(model)
|
||||
event = model_obj.read(cr, uid, context_id, ['name', 'location', 'alarm_id'])
|
||||
return event['date']
|
||||
|
||||
def _default_deadline(self, cr, uid, context={}):
|
||||
""" Get Default value for End Date
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values
|
||||
@return: Get Default value for End Date
|
||||
"""
|
||||
|
||||
context_id = context and context.get('active_id', False) or False
|
||||
if context_id:
|
||||
if context.get('date_deadline'):
|
||||
return context.get('date_deadline')
|
||||
else:
|
||||
model = context.get('model', False)
|
||||
model_obj = self.pool.get(model)
|
||||
event = model_obj.read(cr, uid, context_id, ['name', 'location', 'alarm_id'])
|
||||
return event['date_deadline']
|
||||
|
||||
def modify_this(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Modify All event for Crm Meeting.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of calendar event edit all’s IDs
|
||||
@return: dictionary {}
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
context_id = context and context.get('active_id', False) or False
|
||||
if context_id:
|
||||
for datas in self.read(cr, uid, ids):
|
||||
model = context.get('model', False)
|
||||
model_obj = self.pool.get(model)
|
||||
model_obj.modify_all(cr, uid, [context_id], datas, context=context)
|
||||
return {}
|
||||
|
||||
_name = "calendar.event.edit.all"
|
||||
_description = "Calendar Edit all event"
|
||||
_columns = {
|
||||
'name': fields.char('Title', size=64, required=True),
|
||||
'date': fields.datetime('Start Date', required=True),
|
||||
'date_deadline': fields.datetime('End Date', required=True),
|
||||
'location': fields.char('Location', size=124),
|
||||
'alarm_id': fields.many2one('res.alarm', 'Reminder'),
|
||||
}
|
||||
_defaults = {
|
||||
'date': _default_values,
|
||||
'date_deadline': _default_deadline
|
||||
}
|
||||
calendar_event_edit_all()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_calendar_event_edit_all" model="ir.ui.view">
|
||||
<field name="name">calendar.event.edit.all.form</field>
|
||||
<field name="model">calendar.event.edit.all</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Edit all Occurrences">
|
||||
<group colspan="4" >
|
||||
<separator string="" colspan="4" />
|
||||
<newline/>
|
||||
<field name='name' colspan="4" />
|
||||
<newline />
|
||||
<field name='location' colspan="4" />
|
||||
<newline />
|
||||
<field name='date' />
|
||||
<field name='date_deadline' />
|
||||
<newline />
|
||||
<field name='alarm_id'/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
|
||||
<button icon="gtk-save" string="_Save" name="modify_this" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_calendar_event_edit_all" model="ir.actions.act_window">
|
||||
<field name="name">Edit all events</field>
|
||||
<field name="res_model">calendar.event.edit.all</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_calendar_event_edit_all"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,78 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
import pooler
|
||||
|
||||
class event_edit_all(wizard.interface):
|
||||
event_form = """<?xml version="1.0"?>
|
||||
<form string="Edit all Occurrences">
|
||||
<separator string="" colspan="4" />
|
||||
<newline />
|
||||
<field name='name' colspan="4" />
|
||||
<newline />
|
||||
<field name='location' colspan="4" />
|
||||
<newline />
|
||||
<field name='date' />
|
||||
<field name='date_deadline' />
|
||||
<newline />
|
||||
<field name='alarm_id'/>
|
||||
</form>"""
|
||||
|
||||
event_fields = {
|
||||
'name': {'string': 'Title', 'type': 'char', 'size': 64, 'required': True},
|
||||
'date': {'string': 'Start Date', 'type': 'datetime', 'required': True},
|
||||
'date_deadline': {'string': 'End Date', 'type': 'datetime', 'required': True},
|
||||
'location': {'string': 'Location', 'type': 'char', 'size': 124},
|
||||
'alarm_id': {'string': 'Reminder', 'type': 'many2one', 'relation': 'res.alarm'},
|
||||
}
|
||||
|
||||
def _default_values(self, cr, uid, data, context=None):
|
||||
model = data.get('model')
|
||||
model_obj = pooler.get_pool(cr.dbname).get(model)
|
||||
event = model_obj.read(cr, uid, data['id'], ['name', 'location', 'alarm_id'])
|
||||
event.update({
|
||||
'date': context.get('date'),
|
||||
'date_deadline': context.get('date_deadline')
|
||||
})
|
||||
return event
|
||||
|
||||
def _modify_all(self, cr, uid, datas, context=None):
|
||||
model = datas.get('model')
|
||||
model_obj = pooler.get_pool(cr.dbname).get(model)
|
||||
model_obj.modify_all(cr, uid, datas['id'], datas['form'], context)
|
||||
return {}
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [_default_values],
|
||||
'result': {'type': 'form', 'arch': event_form, 'fields': event_fields,
|
||||
'state': [('end', 'Cancel', 'gtk-cancel'), ('edit', '_Save', 'gtk-save')]}
|
||||
},
|
||||
'edit': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action': _modify_all, 'state': 'end'}
|
||||
}
|
||||
}
|
||||
|
||||
event_edit_all('calendar.event.edit.all')
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
|
@ -15,7 +15,7 @@
|
|||
# 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/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
@ -23,16 +23,19 @@ import netsvc
|
|||
from osv import fields, osv
|
||||
|
||||
class res_partner_contact(osv.osv):
|
||||
""" Partner Contact """
|
||||
|
||||
_name = "res.partner.contact"
|
||||
_description = "res.partner.contact"
|
||||
# def init(self, cr):
|
||||
# address_obj = self.pool.get('res.partner.address')
|
||||
# job_obj = self.pool.get('res.partner.job')
|
||||
# address_ids = address_obj.search(cr, 1, [])
|
||||
# for address in address_obj.browse(cr, 1, address_ids):
|
||||
# contact_id = self.create(cr, 1, {'name': address.name or 't'})
|
||||
|
||||
def _title_get(self,cr, user, context={}):
|
||||
"""
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param user: the current user,
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
obj = self.pool.get('res.partner.title')
|
||||
ids = obj.search(cr, user, [])
|
||||
res = obj.read(cr, user, ids, ['shortcut', 'name','domain'], context)
|
||||
|
@ -40,6 +43,16 @@ class res_partner_contact(osv.osv):
|
|||
return res
|
||||
|
||||
def _main_job(self, cr, uid, ids, fields, arg, context=None):
|
||||
"""
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of partner contact’s IDs
|
||||
@fields: Get Fields
|
||||
@param context: A standard dictionary for contextual values
|
||||
@param arg: list of tuples of form [(‘name_of_the_field’, ‘operator’, value), ...]. """
|
||||
|
||||
|
||||
res = dict.fromkeys(ids, False)
|
||||
for contact in self.browse(cr, uid, ids, context):
|
||||
if contact.job_ids:
|
||||
|
@ -49,30 +62,43 @@ class res_partner_contact(osv.osv):
|
|||
_columns = {
|
||||
'name': fields.char('Last Name', size=30,required=True),
|
||||
'first_name': fields.char('First Name', size=30),
|
||||
'mobile':fields.char('Mobile',size=30),
|
||||
'mobile': fields.char('Mobile',size=30),
|
||||
'title': fields.selection(_title_get, 'Title'),
|
||||
'website':fields.char('Website',size=120),
|
||||
'lang_id':fields.many2one('res.lang','Language'),
|
||||
'job_ids':fields.one2many('res.partner.job','contact_id','Functions and Addresses'),
|
||||
'country_id':fields.many2one('res.country','Nationality'),
|
||||
'birthdate':fields.date('Birth Date'),
|
||||
'active' : fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the partner contact without removing it."),
|
||||
'partner_id':fields.related('job_ids','address_id','partner_id',type='many2one', relation='res.partner', string='Main Employer'),
|
||||
'function_id':fields.related('job_ids','function_id',type='many2one', relation='res.partner.function', string='Main Function'),
|
||||
'job_id': fields.function(_main_job, method=True, type='many2one', relation='res.partner.job', string='Main Job'),
|
||||
'website': fields.char('Website',size=120),
|
||||
'lang_id': fields.many2one('res.lang','Language'),
|
||||
'job_ids': fields.one2many('res.partner.job','contact_id','Functions and Addresses'),
|
||||
'country_id': fields.many2one('res.country','Nationality'),
|
||||
'birthdate': fields.date('Birth Date'),
|
||||
'active': fields.boolean('Active', help="If the active field is set to true,\
|
||||
it will allow you to hide the partner contact without removing it."),
|
||||
'partner_id': fields.related('job_ids','address_id','partner_id',type='many2one',\
|
||||
relation='res.partner', string='Main Employer'),
|
||||
'function_id': fields.related('job_ids','function_id',type='many2one', \
|
||||
relation='res.partner.function', string='Main Function'),
|
||||
'job_id': fields.function(_main_job, method=True, type='many2one',\
|
||||
relation='res.partner.job', string='Main Job'),
|
||||
'email': fields.char('E-Mail', size=240),
|
||||
'comment' : fields.text('Notes', translate=True),
|
||||
'photo' : fields.binary('Image'),
|
||||
|
||||
'comment': fields.text('Notes', translate=True),
|
||||
'photo': fields.binary('Image'),
|
||||
|
||||
}
|
||||
_defaults = {
|
||||
'active' : lambda *a: True,
|
||||
}
|
||||
|
||||
|
||||
_order = "name,first_name"
|
||||
|
||||
|
||||
def name_get(self, cr, user, ids, context={}):
|
||||
#will return name and first_name.......
|
||||
|
||||
""" will return name and first_name.......
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param user: the current user’s ID for security checks,
|
||||
@param ids: List of create menu’s IDs
|
||||
@return: name and first_name
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
if not len(ids):
|
||||
return []
|
||||
res = []
|
||||
|
@ -84,60 +110,93 @@ class res_partner_contact(osv.osv):
|
|||
addr += (r.get('first_name', '') or '')
|
||||
res.append((r['id'], addr))
|
||||
return res
|
||||
|
||||
res_partner_contact()
|
||||
|
||||
|
||||
class res_partner_address(osv.osv):
|
||||
|
||||
def search(self, cr, user, args, offset=0, limit=None, order=None,
|
||||
context=None, count=False):
|
||||
""" search parnter address
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param user: the current user
|
||||
@param args: list of tuples of form [(‘name_of_the_field’, ‘operator’, value), ...].
|
||||
@param offset: The Number of Results to Pass
|
||||
@param limit: The Number of Results to Return
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
if context and context.has_key('address_partner_id' ) and context['address_partner_id']:
|
||||
args.append(('partner_id', '=', context['address_partner_id']))
|
||||
return super(res_partner_address, self).search(cr, user, args, offset, limit, order, context, count)
|
||||
|
||||
#overriding of the name_get defined in base in order to remove the old contact name
|
||||
def name_get(self, cr, user, ids, context={}):
|
||||
"""
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param user: the current user,
|
||||
@param ids: List of partner address’s IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
if not len(ids):
|
||||
return []
|
||||
res = []
|
||||
for r in self.read(cr, user, ids, ['zip','city','partner_id', 'street']):
|
||||
for r in self.read(cr, user, ids, ['zip', 'city', 'partner_id', 'street']):
|
||||
if context.get('contact_display', 'contact')=='partner' and r['partner_id']:
|
||||
res.append((r['id'], r['partner_id'][1]))
|
||||
else:
|
||||
addr = str('')
|
||||
addr += "%s %s %s" % ( r.get('street', '') or '', r.get('zip', '') or '', r.get('city', '') or '' )
|
||||
addr += "%s %s %s" % (r.get('street', '') or '', r.get('zip', '') \
|
||||
or '', r.get('city', '') or '')
|
||||
res.append((r['id'], addr.strip() or '/'))
|
||||
return res
|
||||
|
||||
_name = 'res.partner.address'
|
||||
_inherit='res.partner.address'
|
||||
_inherit = 'res.partner.address'
|
||||
_description ='Partner Address'
|
||||
|
||||
_columns = {
|
||||
'job_id':fields.related('job_ids','contact_id','job_id',type='many2one', relation='res.partner.job', string='Main Job'),
|
||||
'job_ids':fields.one2many('res.partner.job', 'address_id', 'Contacts'),
|
||||
'job_id': fields.related('job_ids','contact_id','job_id',type='many2one',\
|
||||
relation='res.partner.job', string='Main Job'),
|
||||
'job_ids': fields.one2many('res.partner.job', 'address_id', 'Contacts'),
|
||||
}
|
||||
res_partner_address()
|
||||
|
||||
class res_partner_job(osv.osv):
|
||||
# def init(self, cr):
|
||||
# address_obj = self.pool.get('res.partner.address')
|
||||
# contact_obj = self.pool.get('res.partner.contact')
|
||||
# address_ids = address_obj.search(cr, 1, [])
|
||||
# for address in address_obj.browse(cr, 1, address_ids):
|
||||
# contact_id = contact_obj.search(cr, 1, [('name','=', address.name)])
|
||||
# if contact_id:
|
||||
# contact_id = contact_id[0]
|
||||
# self.create(cr, 1, {'address_id': address.id, 'contact_id': contact_id})
|
||||
|
||||
def name_get(self, cr, uid, ids, context={}):
|
||||
"""
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param user: the current user,
|
||||
@param ids: List of partner address’s IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
if not len(ids):
|
||||
return []
|
||||
res = []
|
||||
for r in self.browse(cr, uid, ids):
|
||||
funct = r.function_id and (", " + r.function_id.name) or ""
|
||||
res.append((r.id, self.pool.get('res.partner.contact').name_get(cr, uid, [r.contact_id.id])[0][1] + funct))
|
||||
res.append((r.id, self.pool.get('res.partner.contact').name_get(cr, uid, \
|
||||
[r.contact_id.id])[0][1] + funct))
|
||||
return res
|
||||
|
||||
def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
|
||||
""" search parnter job
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param user: the current user
|
||||
@param args: list of tuples of form [(‘name_of_the_field’, ‘operator’, value), ...].
|
||||
@param offset: The Number of Results to Pass
|
||||
@param limit: The Number of Results to Return
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
job_ids = []
|
||||
for arg in args:
|
||||
if arg[0] == 'address_id':
|
||||
|
@ -147,12 +206,14 @@ class res_partner_job(osv.osv):
|
|||
|
||||
contact_obj = self.pool.get('res.partner.contact')
|
||||
search_arg = ['|', ('first_name', 'ilike', arg[2]), ('name', 'ilike', arg[2])]
|
||||
contact_ids = contact_obj.search(cr, user, search_arg, offset=offset, limit=limit, order=order, context=context, count=count)
|
||||
contact_ids = contact_obj.search(cr, user, search_arg, offset=offset, \
|
||||
limit=limit, order=order, context=context, count=count)
|
||||
contacts = contact_obj.browse(cr, user, contact_ids, context=context)
|
||||
for contact in contacts:
|
||||
job_ids.extend([item.id for item in contact.job_ids])
|
||||
|
||||
res = super(res_partner_job,self).search(cr, user, args, offset=offset, limit=limit, order=order, context=context, count=count)
|
||||
res = super(res_partner_job,self).search(cr, user, args, offset=offset,\
|
||||
limit=limit, order=order, context=context, count=count)
|
||||
if job_ids:
|
||||
res = list(set(res + job_ids))
|
||||
|
||||
|
@ -161,27 +222,36 @@ class res_partner_job(osv.osv):
|
|||
_name = 'res.partner.job'
|
||||
_description ='Contact Partner Function'
|
||||
_order = 'sequence_contact'
|
||||
|
||||
_columns = {
|
||||
'name': fields.related('address_id','partner_id', type='many2one', relation='res.partner', string='Partner', help="You may enter Address first,Partner will be linked automatically if any."),
|
||||
'address_id':fields.many2one('res.partner.address','Address', help='Address which is linked to the Partner'),
|
||||
'contact_id':fields.many2one('res.partner.contact','Contact', required=True, ondelete='cascade'),
|
||||
'function_id': fields.many2one('res.partner.function','Partner Function', help="Function of this contact with this partner"),
|
||||
'sequence_contact':fields.integer('Contact Seq.',help='Order of importance of this address in the list of addresses of the linked contact'),
|
||||
'sequence_partner':fields.integer('Partner Seq.',help='Order of importance of this job title in the list of job title of the linked partner'),
|
||||
'name': fields.related('address_id','partner_id', type='many2one',\
|
||||
relation='res.partner', string='Partner', help="You may\
|
||||
enter Address first,Partner will be linked automatically if any."),
|
||||
'address_id': fields.many2one('res.partner.address','Address', \
|
||||
help='Address which is linked to the Partner'),
|
||||
'contact_id': fields.many2one('res.partner.contact','Contact', required=True, ondelete='cascade'),
|
||||
'function_id': fields.many2one('res.partner.function','Partner Function', \
|
||||
help="Function of this contact with this partner"),
|
||||
'sequence_contact': fields.integer('Contact Seq.',help='Order of\
|
||||
importance of this address in the list of addresses of the linked contact'),
|
||||
'sequence_partner': fields.integer('Partner Seq.',help='Order of importance\
|
||||
of this job title in the list of job title of the linked partner'),
|
||||
'email': fields.char('E-Mail', size=240, help="Job E-Mail"),
|
||||
'phone': fields.char('Phone', size=64, help="Job Phone no."),
|
||||
'fax': fields.char('Fax', size=64, help="Job FAX no."),
|
||||
'extension': fields.char('Extension', size=64, help='Internal/External extension phone number'),
|
||||
'other': fields.char('Other', size=64, help='Additional phone field'),
|
||||
'date_start' : fields.date('Date Start',help="Start date of job(Joining Date)"),
|
||||
'date_stop' : fields.date('Date Stop', help="Last date of job"),
|
||||
'state' : fields.selection([('past', 'Past'),('current', 'Current')], 'State', required=True, help="Status of Address"),
|
||||
'date_start': fields.date('Date Start',help="Start date of job(Joining Date)"),
|
||||
'date_stop': fields.date('Date Stop', help="Last date of job"),
|
||||
'state': fields.selection([('past', 'Past'),('current', 'Current')], \
|
||||
'State', required=True, help="Status of Address"),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'sequence_contact' : lambda *a: 0,
|
||||
'state' : lambda *a: 'current',
|
||||
'state': lambda *a: 'current',
|
||||
}
|
||||
|
||||
res_partner_job()
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Views for Contacts -->
|
||||
<!-- Views for Contacts Tree View -->
|
||||
|
||||
<record model="ir.ui.view" id="view_partner_contact_tree">
|
||||
<field name="name">res.partner.contact.tree</field>
|
||||
<field name="model">res.partner.contact</field>
|
||||
|
@ -20,6 +21,8 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Views for Contacts Form View -->
|
||||
|
||||
<record model="ir.ui.view" id="view_partner_contact_form">
|
||||
<field name="name">res.partner.contact.form</field>
|
||||
<field name="model">res.partner.contact</field>
|
||||
|
@ -93,6 +96,8 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Views for Contacts Search View -->
|
||||
|
||||
<record model="ir.ui.view" id="view_partner_contact_search">
|
||||
<field name="name">res.partner.contact.search</field>
|
||||
<field name="model">res.partner.contact</field>
|
||||
|
@ -106,6 +111,8 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Views for Contacts Action -->
|
||||
|
||||
<record model="ir.actions.act_window" id="action_partner_contact_form">
|
||||
<field name="name">Contacts</field>
|
||||
<field name="res_model">res.partner.contact</field>
|
||||
|
@ -116,7 +123,7 @@
|
|||
</record>
|
||||
<menuitem name="Contacts" id="menu_partner_contact_form" action="action_partner_contact_form" parent = "base.menu_address_book" sequence="2"/>
|
||||
|
||||
<!-- Views for Partners -->
|
||||
<!-- Views for Partners Form View -->
|
||||
|
||||
<record model="ir.ui.view" id="view_partner_form_inherit">
|
||||
<field name="name">Partner form inherited</field>
|
||||
|
@ -186,6 +193,7 @@
|
|||
|
||||
|
||||
<!-- don't display the categories, since it is displayed in an other tab-->
|
||||
|
||||
<record model="ir.ui.view" id="view_partner_form_inherit2">
|
||||
<field name="name">res.partner.form</field>
|
||||
<field name="type">form</field>
|
||||
|
@ -198,6 +206,7 @@
|
|||
</record>
|
||||
|
||||
<!-- don't display the categories label-->
|
||||
|
||||
<record model="ir.ui.view" id="view_partner_form_inherit2bis">
|
||||
<field name="name">res.partner.form</field>
|
||||
<field name="type">form</field>
|
||||
|
@ -225,6 +234,7 @@
|
|||
|
||||
|
||||
<!-- Views for Addresses -->
|
||||
|
||||
<record model="ir.ui.view" id="view_partner_address_tree_inherited1">
|
||||
<field name="name">Partner addresses inherited</field>
|
||||
<field name="model">res.partner.address</field>
|
||||
|
@ -306,39 +316,6 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!--
|
||||
<record id='view_partner_address_form_inherited5' model='ir.ui.view'>
|
||||
<field name='name'>res.partner.address.form.inherited5</field>
|
||||
<field name='model'>res.partner.address</field>
|
||||
<field name="inherit_id" ref="base.view_partner_address_form1"/>
|
||||
<field name='type'>form</field>
|
||||
<field name='arch' type='xml'>
|
||||
<group string="Communication" colspan="2" col="2" position="after">
|
||||
<newline/>
|
||||
<field name="job_ids" mode="tree,form" colspan="4">
|
||||
<tree string="Contacts" editable="top">
|
||||
<field name="contact_id"/>
|
||||
<field name="function_id"/>
|
||||
<field name="phone"/>
|
||||
<field name="fax"/>
|
||||
<field name="extension"/>
|
||||
<field name="email"/>
|
||||
</tree>
|
||||
<form string="Contacts">
|
||||
<field name="contact_id"/>
|
||||
<field name="function_id"/>
|
||||
<field name="phone"/>
|
||||
<field name="fax"/>
|
||||
<field name="extension"/>
|
||||
<field name="email" widget="email"/>
|
||||
</form>
|
||||
</field>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
-->
|
||||
|
||||
<record id="view_res_partner_address_filter" model="ir.ui.view">
|
||||
<field name="name">res.partner.address.select</field>
|
||||
<field name="model">res.partner.address</field>
|
||||
|
@ -351,8 +328,8 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Views for partner job Tree view -->
|
||||
|
||||
<!-- Views for res.partner.job -->
|
||||
<record model="ir.ui.view" id="view_partner_job_tree">
|
||||
<field name="name">res.partner.job.tree</field>
|
||||
<field name="model">res.partner.job</field>
|
||||
|
@ -372,6 +349,8 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Views for partner job Form view -->
|
||||
|
||||
<record model="ir.ui.view" id="view_partner_job_form">
|
||||
<field name="name">res.partner.job.form</field>
|
||||
<field name="model">res.partner.job</field>
|
||||
|
@ -400,19 +379,14 @@
|
|||
</record>
|
||||
|
||||
<!-- Menuitem for res.partner.job -->
|
||||
|
||||
<record model="ir.actions.act_window" id="action_res_partner_job">
|
||||
<field name="name">Contact's Jobs</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">res.partner.job</field>
|
||||
<field name="view_type">form</field>
|
||||
</record>
|
||||
<!-- <menuitem-->
|
||||
<!-- name="Partners/Contact's Jobs"-->
|
||||
<!-- action="action_res_partner_job"-->
|
||||
<!-- id="menu_action_res_partner_job"-->
|
||||
<!-- groups="base.group_extended"/>-->
|
||||
|
||||
<!-- Act window defining a shorcut on partners to open all his contacts -->
|
||||
<act_window domain="[('name', '=', active_id)]"
|
||||
id="act_res_partner_jobs" name="Partner Contacts"
|
||||
res_model="res.partner.job"
|
||||
|
@ -420,6 +394,7 @@
|
|||
/>
|
||||
|
||||
<!-- Act window defining a shorcut on partner address to open all his jobs -->
|
||||
|
||||
<act_window
|
||||
id="act_res_partner_jobs" name="Open Jobs"
|
||||
domain="[('address_id', '=', active_id)]"
|
||||
|
@ -427,9 +402,13 @@
|
|||
src_model="res.partner.address"
|
||||
/>
|
||||
|
||||
<menuitem icon="terp-purchase" id="base.menu_purchase_root" name="Procurement Management" sequence="7"/>
|
||||
<menuitem id="base.menu_procurement_management_supplier" name="Suppliers"
|
||||
parent="base.menu_purchase_root" sequence="3"/>
|
||||
<menuitem name="Contacts" id="menu_partner_contact_supplier_form" action="action_partner_contact_form" parent = "base.menu_procurement_management_supplier" sequence="2"/>
|
||||
<menuitem icon="terp-purchase" id="base.menu_purchase_root"
|
||||
name="Procurement Management" sequence="7" />
|
||||
<menuitem id="base.menu_procurement_management_supplier"
|
||||
name="Suppliers" parent="base.menu_purchase_root" sequence="3" />
|
||||
<menuitem name="Contacts" id="menu_partner_contact_supplier_form"
|
||||
action="action_partner_contact_form"
|
||||
parent="base.menu_procurement_management_supplier" sequence="2" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -37,6 +37,8 @@ the "Dashboard" menu.
|
|||
'init_xml': [],
|
||||
'update_xml': [
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/report_menu_create_view.xml',
|
||||
'wizard/report_open_view.xml',
|
||||
'base_report_creator_wizard.xml',
|
||||
'base_report_creator_view.xml'
|
||||
],
|
||||
|
|
|
@ -19,35 +19,13 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import string
|
||||
import time
|
||||
import tools
|
||||
from osv import fields,osv,orm
|
||||
from osv import fields, osv
|
||||
from tools.translate import _
|
||||
|
||||
#class ir_model_fields(osv.osv):
|
||||
# _inherit = 'ir.model.fields'
|
||||
# def _get_models(self, cr, uid, model_name, level=1):
|
||||
# if not level:
|
||||
# return []
|
||||
# result = [model_name]
|
||||
# print model_name
|
||||
# for field,data in self.pool.get(model_name).fields_get(cr, uid).items():
|
||||
# if data.get('relation', False):
|
||||
# result += self._get_models(cr, uid, data['relation'], level-1)
|
||||
# return result
|
||||
# def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None):
|
||||
# if context and ('model_id' in context):
|
||||
# model_name = self.pool.get("ir.model").browse(cr, uid, context['model_id'], context).model
|
||||
# models = self._get_models(cr, uid, model_name, context.get('model_level',2))
|
||||
# models = map(lambda x: self.pool.get('ir.model').search(cr, uid, [('model','=',x)])[0], models)
|
||||
# args.append(('model_id','in',models))
|
||||
# print args
|
||||
# return super(ir_model_fields, self).search(cr, uid, args, offset, limit, order, context)
|
||||
#ir_model_fields()
|
||||
|
||||
|
||||
class report_creator(osv.osv):
|
||||
"""
|
||||
Report Creator
|
||||
"""
|
||||
_name = "base_report_creator.report"
|
||||
_description = "Report"
|
||||
model_set_id = False
|
||||
|
@ -55,45 +33,74 @@ class report_creator(osv.osv):
|
|||
# Should request only used fields
|
||||
#
|
||||
def export_data(self, cr, uid, ids, fields_to_export, context=None):
|
||||
|
||||
if not context:
|
||||
context = {}
|
||||
data_l = self.read(cr, uid, ids, ['sql_query'], context)
|
||||
final_datas =[]
|
||||
final_datas = []
|
||||
#start Loop
|
||||
for i in data_l:
|
||||
datas = []
|
||||
for key,value in i.items():
|
||||
for key, value in i.items():
|
||||
if key not in fields_to_export:
|
||||
continue
|
||||
if isinstance(value,tuple):
|
||||
if isinstance(value, tuple):
|
||||
datas.append(str(value[1]))
|
||||
else:
|
||||
datas.append(str(value))
|
||||
final_datas += [datas]
|
||||
return {'datas':final_datas}
|
||||
#End Loop
|
||||
return {'datas': final_datas}
|
||||
|
||||
def fields_get(self, cr, user, fields=None, context=None):
|
||||
"""
|
||||
Get Fields.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param user: the current user’s ID for security checks,
|
||||
@param Fields: List of field of customer reports form.
|
||||
@return: Dictionary of Fields
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
data = context and context.get('report_id', False) or False
|
||||
if (not context) or 'report_id' not in context:
|
||||
return super(report_creator, self).fields_get(cr, user, fields, context)
|
||||
report = self.browse(cr, user, context['report_id'])
|
||||
models = {}
|
||||
for model in report.model_ids:
|
||||
models[model.model] = self.pool.get(model.model).fields_get(cr, user, context=context)
|
||||
fields = {}
|
||||
i = 0
|
||||
for f in report.field_ids:
|
||||
if f.field_id.model:
|
||||
fields['field'+str(i)] = models[f.field_id.model][f.field_id.name]
|
||||
i+=1
|
||||
else:
|
||||
fields['column_count'] = {'readonly': True, 'type': 'integer', 'string': 'Count', 'size': 64, 'name': 'column_count'}
|
||||
|
||||
return fields
|
||||
if data:
|
||||
report = self.browse(cr, user, data)
|
||||
models = {}
|
||||
#Start Loop
|
||||
for model in report.model_ids:
|
||||
models[model.model] = self.pool.get(model.model).fields_get(cr, user, context=context)
|
||||
#End Loop
|
||||
fields = {}
|
||||
i = 0
|
||||
for f in report.field_ids:
|
||||
if f.field_id.model:
|
||||
fields['field'+str(i)] = models[f.field_id.model][f.field_id.name]
|
||||
i += 1
|
||||
else:
|
||||
fields['column_count'] = {'readonly': True, 'type': 'integer', 'string': 'Count', 'size': 64, 'name': 'column_count'}
|
||||
|
||||
return fields
|
||||
|
||||
#
|
||||
# Should Call self.fields_get !
|
||||
#
|
||||
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
|
||||
"""
|
||||
Overrides orm field_view_get.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param user: the current user’s ID for security checks,
|
||||
@return: Dictionary of Fields, arch and toolbar.
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
data = context and context.get('report_id', False) or False
|
||||
if (not context) or 'report_id' not in context:
|
||||
return super(report_creator, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
|
||||
report = self.browse(cr, user, context['report_id'])
|
||||
report = self.browse(cr, user, data)
|
||||
models = {}
|
||||
for model in report.model_ids:
|
||||
models[model.model] = self.pool.get(model.model).fields_get(cr, user, context=context)
|
||||
|
@ -102,33 +109,33 @@ class report_creator(osv.osv):
|
|||
for f in report.field_ids:
|
||||
if f.field_id.model:
|
||||
fields['field'+str(i)] = models[f.field_id.model][f.field_id.name]
|
||||
i+=1
|
||||
i += 1
|
||||
else:
|
||||
fields['column_count'] = {'readonly': True, 'type': 'integer', 'string': 'Count', 'size': 64, 'name': 'column_count'}
|
||||
|
||||
arch = '<?xml version="1.0" encoding="utf-8"?>\n'
|
||||
if view_type=='graph':
|
||||
arch +='<graph string="%s" type="%s" orientation="%s">' % (report.name, report.view_graph_type,report.view_graph_orientation)
|
||||
if view_type == 'graph':
|
||||
arch += '<graph string="%s" type="%s" orientation="%s">' % (report.name, report.view_graph_type, report.view_graph_orientation)
|
||||
for val in ('x','y'):
|
||||
i = 0
|
||||
for f in report.field_ids:
|
||||
if f.graph_mode==val:
|
||||
if f.graph_mode == val:
|
||||
if f.field_id.model:
|
||||
arch += '<field name="%s" select="1"/>' % ('field'+str(i),)
|
||||
i+=1
|
||||
i += 1
|
||||
else:
|
||||
arch += '<field name="%s" select="1"/>' % ('column_count',)
|
||||
|
||||
elif view_type=='calendar':
|
||||
required_types = ['date_start','date_delay','color']
|
||||
set_dict = {'view_type':view_type,'string':report.name}
|
||||
elif view_type == 'calendar':
|
||||
required_types = ['date_start', 'date_delay', 'color']
|
||||
set_dict = {'view_type':view_type, 'string':report.name}
|
||||
temp_list = []
|
||||
i=0
|
||||
i = 0
|
||||
for f in report.field_ids:
|
||||
if f.calendar_mode and f.calendar_mode in required_types:
|
||||
if f.field_id.model:
|
||||
field_cal = 'field'+str(i)
|
||||
i+=1
|
||||
i += 1
|
||||
else:
|
||||
field_cal = 'column_count'
|
||||
set_dict[f.calendar_mode] = field_cal
|
||||
|
@ -136,20 +143,20 @@ class report_creator(osv.osv):
|
|||
|
||||
else:
|
||||
if f.field_id.model:
|
||||
temp_list.append('''<field name="%(name)s" select="1"/>''' % {'name':'field'+str(i)})
|
||||
i+=1
|
||||
temp_list.append('''<field name = "%(name)s" select = "1"/>''' % {'name': 'field' + str(i)})
|
||||
i += 1
|
||||
else:
|
||||
temp_list.append('''<field name="%(name)s" select="1"/>''' % {'name':'column_count'})
|
||||
|
||||
arch += '''<%(view_type)s string="%(string)s" date_start="%(date_start)s" ''' %set_dict
|
||||
if set_dict.get('date_delay',False):
|
||||
arch +=''' date_delay="%(date_delay)s" '''%set_dict
|
||||
arch += '''<% (view_type)s string = "%(string)s" date_start = "%(date_start)s" ''' % set_dict
|
||||
if set_dict.get('date_delay', False):
|
||||
arch += ''' date_delay = "%(date_delay)s" ''' % set_dict
|
||||
|
||||
if set_dict.get('date_stop',False):
|
||||
arch +=''' date_stop="%(date_stop)s" '''%set_dict
|
||||
if set_dict.get('date_stop', False):
|
||||
arch += ''' date_stop="%(date_stop)s" '''%set_dict
|
||||
|
||||
if set_dict.get('color',False):
|
||||
arch +=''' color="%(color)s"'''%set_dict
|
||||
if set_dict.get('color', False):
|
||||
arch += ''' color="%(color)s"'''%set_dict
|
||||
arch += '''>'''
|
||||
arch += ''.join(temp_list)
|
||||
else:
|
||||
|
@ -157,8 +164,8 @@ class report_creator(osv.osv):
|
|||
i = 0
|
||||
for f in report.field_ids:
|
||||
if f.field_id.model:
|
||||
arch += '<field name="%s" select="1"/>' % ('field'+str(i),)
|
||||
i+=1
|
||||
arch += '<field name="%s" select="1"/>' % ('field' + str(i),)
|
||||
i += 1
|
||||
else:
|
||||
arch += '<field name="%s" select="1"/>' % ('column_count',)
|
||||
arch += '</%s>' % (view_type,)
|
||||
|
@ -171,70 +178,90 @@ class report_creator(osv.osv):
|
|||
'action': [],
|
||||
'relate': []
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
|
||||
def read(self, cr, user, ids, fields = None, context = None, load = '_classic_read'):
|
||||
"""
|
||||
overrides orm Read method.Read List of fields for report creator.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param user: the current user’s ID for security checks,
|
||||
@param ids: List of report creator's id.
|
||||
@param fields: List of fields.
|
||||
@return: List of Dictionary of form [{‘name_of_the_field’: value, ...}, ...]
|
||||
"""
|
||||
data = context and context.get('report_id', False) or False
|
||||
if (not context) or 'report_id' not in context:
|
||||
return super(report_creator, self).read(cr, user, ids, fields, context, load)
|
||||
ctx = context or {}
|
||||
wp = ''
|
||||
if self.model_set_id:
|
||||
wp = [self._id_get(cr, user, context['report_id'], context)+(' in (%s)' % (','.join(map(lambda x: "'"+str(x)+"'",ids))))]
|
||||
report = self._sql_query_get(cr, user, [context['report_id']], 'sql_query', None, ctx, where_plus = wp)
|
||||
sql_query = report[context['report_id']]
|
||||
cr.execute(sql_query)
|
||||
res = cr.dictfetchall()
|
||||
fields_get = self.fields_get(cr,user,None,context)
|
||||
for r in res:
|
||||
for k in r:
|
||||
r[k] = r[k] or False
|
||||
field_dict = fields_get.get(k)
|
||||
field_type = field_dict and field_dict.get('type',False) or False
|
||||
if field_type and field_type == 'many2one':
|
||||
if r[k]==False:
|
||||
continue
|
||||
related_name = self.pool.get(field_dict.get('relation')).name_get(cr,user,[r[k]],context)[0]
|
||||
r[k] = related_name
|
||||
return res
|
||||
if data:
|
||||
if self.model_set_id:
|
||||
wp = [self._id_get(cr, user, data, context) + (' in (%s)' % (','.join(map(lambda x: "'" + str(x) + "'", ids))))]
|
||||
report = self._sql_query_get(cr, user, [data], 'sql_query', None, ctx, where_plus = wp)
|
||||
sql_query = report[data]
|
||||
cr.execute(sql_query)
|
||||
res = cr.dictfetchall()
|
||||
fields_get = self.fields_get(cr, user, None, context)
|
||||
for r in res:
|
||||
for k in r:
|
||||
r[k] = r[k] or False
|
||||
field_dict = fields_get.get(k)
|
||||
field_type = field_dict and field_dict.get('type', False) or False
|
||||
if field_type and field_type == 'many2one':
|
||||
if r[k] == False:
|
||||
continue
|
||||
related_name = self.pool.get(field_dict.get('relation')).name_get(cr, user, [r[k]], context)[0]
|
||||
r[k] = related_name
|
||||
|
||||
return res
|
||||
|
||||
def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
|
||||
"""
|
||||
overrides orm search method.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param user: the current user’s ID for security checks,
|
||||
@param args: list of tuples of form [(‘name_of_the_field’, ‘operator’, value), ...].
|
||||
@return: List of id
|
||||
"""
|
||||
|
||||
context_id = context and context.get('report_id', False) or False
|
||||
|
||||
if (not context) or 'report_id' not in context:
|
||||
return super(report_creator, self).search(cr, user, args, offset, limit, order, context, count)
|
||||
report = self.browse(cr, user, context['report_id'])
|
||||
i = 0
|
||||
fields = {}
|
||||
for f in report.field_ids:
|
||||
if f.field_id.model:
|
||||
fields['field'+str(i)] = (f.field_id.model, f.field_id.name)
|
||||
i+=1
|
||||
else:
|
||||
fields['column_count'] = (False, 'Count')
|
||||
newargs = []
|
||||
newargs2 = []
|
||||
for a in args:
|
||||
if fields[a[0]][0]:
|
||||
res = self.pool.get(fields[a[0]][0])._where_calc(cr, user, [[fields[a[0]][1],a[1],a[2]]], active_test=False, context=context)
|
||||
newargs+=res[0]
|
||||
newargs2+=res[1]
|
||||
else:
|
||||
newargs += [("count(*) " + a[1] +" " + str(a[2]))]
|
||||
ctx = context or {}
|
||||
ctx['getid'] = True
|
||||
report = self._sql_query_get(cr, user, [context['report_id']], 'sql_query', None, ctx, where_plus=newargs, limit=limit, offset=offset)
|
||||
query = report[context['report_id']]
|
||||
cr.execute(query, newargs2)
|
||||
result = cr.fetchall()
|
||||
return map(lambda x: x[0], result)
|
||||
if context_id:
|
||||
report = self.browse(cr, user, context_id)
|
||||
i = 0
|
||||
fields = {}
|
||||
for f in report.field_ids:
|
||||
if f.field_id.model:
|
||||
fields['field'+str(i)] = (f.field_id.model, f.field_id.name)
|
||||
i += 1
|
||||
else:
|
||||
fields['column_count'] = (False, 'Count')
|
||||
newargs = []
|
||||
newargs2 = []
|
||||
for a in args:
|
||||
if fields[a[0]][0]:
|
||||
res = self.pool.get(fields[a[0]][0])._where_calc(cr, user, [[fields[a[0]][1], a[1], a[2]]], active_test = False, context = context)
|
||||
newargs += res[0]
|
||||
newargs2 += res[1]
|
||||
else:
|
||||
newargs += [("count(*) " + a[1] +" " + str(a[2]))]
|
||||
ctx = context or {}
|
||||
ctx['getid'] = True
|
||||
report = self._sql_query_get(cr, user, [context_id], 'sql_query', None, ctx, where_plus = newargs, limit=limit, offset=offset)
|
||||
query = report[context_id]
|
||||
cr.execute(query, newargs2)
|
||||
result = cr.fetchall()
|
||||
return map(lambda x: x[0], result)
|
||||
|
||||
def _path_get(self,cr, uid, models, filter_ids=[]):
|
||||
# ret_str = """ sale_order_line
|
||||
# left join sale_order on (sale_order_line.order_id=sale_order.id)
|
||||
# left join res_partner on (res_partner.id=sale_order.partner_id)"""
|
||||
# where_list = []
|
||||
# for filter_id in filter_ids:
|
||||
# where_list.append(filter_id.expression)
|
||||
# if where_list:
|
||||
# ret_str+="\nwhere\n\t"+" and\n\t".join(where_list)
|
||||
def _path_get(self, cr, uid, models, filter_ids=[]):
|
||||
"""
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param models: List of object.
|
||||
"""
|
||||
self.model_set_id = False
|
||||
model_dict = {}
|
||||
from_list = []
|
||||
|
@ -242,7 +269,7 @@ class report_creator(osv.osv):
|
|||
filter_list = []
|
||||
for model in models:
|
||||
model_dict[model.model] = self.pool.get(model.model)._table
|
||||
|
||||
|
||||
model_list = model_dict.keys()
|
||||
reference_model_dict = {}
|
||||
for model in model_dict:
|
||||
|
@ -250,7 +277,7 @@ class report_creator(osv.osv):
|
|||
rest_list = model_dict.keys()
|
||||
rest_list.remove(model)
|
||||
model_pool = self.pool.get(model)
|
||||
fields_get = model_pool.fields_get(cr,uid)
|
||||
fields_get = model_pool.fields_get(cr, uid)
|
||||
model_columns = {}
|
||||
|
||||
def _get_inherit_fields(obj):
|
||||
|
@ -259,24 +286,24 @@ class report_creator(osv.osv):
|
|||
model_columns.update(pool_model._columns)
|
||||
#Adding the columns of its _inherits
|
||||
for record in pool_model._inherits.keys():
|
||||
_get_inherit_fields(record)
|
||||
_get_inherit_fields(record)
|
||||
|
||||
_get_inherit_fields(model)
|
||||
|
||||
fields_filter = dict(filter(lambda x:x[1].get('relation',False)
|
||||
fields_filter = dict(filter(lambda x:x[1].get('relation', False)
|
||||
and x[1].get('relation') in rest_list
|
||||
and x[1].get('type')=='many2one'
|
||||
and not (isinstance(model_columns[x[0]],fields.function) or isinstance(model_columns[x[0]],fields.related)), fields_get.items()))
|
||||
and x[1].get('type') == 'many2one'
|
||||
and not (isinstance(model_columns[x[0]], fields.function) or isinstance(model_columns[x[0]], fields.related)), fields_get.items()))
|
||||
if fields_filter:
|
||||
model in model_list and model_list.remove(model)
|
||||
model_count = reference_model_dict.get(model,False)
|
||||
model_count = reference_model_dict.get(model, False)
|
||||
if model_count:
|
||||
reference_model_dict[model] = model_count +1
|
||||
else:
|
||||
reference_model_dict[model] = 1
|
||||
for k,v in fields_filter.items():
|
||||
for k, v in fields_filter.items():
|
||||
v.get('relation') in model_list and model_list.remove(v.get('relation'))
|
||||
relation_count = reference_model_dict.get(v.get('relation'),False)
|
||||
relation_count = reference_model_dict.get(v.get('relation'), False)
|
||||
if relation_count:
|
||||
reference_model_dict[v.get('relation')] = relation_count+1
|
||||
else:
|
||||
|
@ -288,9 +315,9 @@ class report_creator(osv.osv):
|
|||
if reference_model_dict:
|
||||
self.model_set_id = model_dict.get(reference_model_dict.keys()[reference_model_dict.values().index(min(reference_model_dict.values()))])
|
||||
if model_list and not len(model_dict.keys()) == 1:
|
||||
raise osv.except_osv(_('No Related Models!!'),_('These is/are model(s) (%s) in selection which is/are not related to any other model') % ','.join(model_list))
|
||||
raise osv.except_osv(_('No Related Models!!'), _('These is/are model(s) (%s) in selection which is/are not related to any other model') % ','.join(model_list))
|
||||
|
||||
if filter_ids and where_list<>[]:
|
||||
if filter_ids and where_list <> []:
|
||||
filter_list.append(' and ')
|
||||
filter_list.append(' ')
|
||||
|
||||
|
@ -305,25 +332,32 @@ class report_creator(osv.osv):
|
|||
else:
|
||||
ret_str = ",\n".join(from_list)
|
||||
|
||||
|
||||
if where_list:
|
||||
where_list = list(set(where_list))
|
||||
ret_str+="\n where \n"+" and\n".join(where_list)
|
||||
ret_str += "\n where \n"+" and\n".join(where_list)
|
||||
ret_str = ret_str.strip()
|
||||
if filter_list:
|
||||
ret_str +="\n".join(filter_list)
|
||||
ret_str += "\n".join(filter_list)
|
||||
if ret_str.endswith('and'):
|
||||
ret_str = ret_str[0:len(ret_str)-3]
|
||||
if ret_str.endswith('or'):
|
||||
ret_str = ret_str[0:len(ret_str)-2]
|
||||
ret_str = ret_str.strip()
|
||||
return ret_str % {'uid' : uid}
|
||||
|
||||
return ret_str % {'uid': uid}
|
||||
|
||||
def _id_get(self, cr, uid, id, context):
|
||||
"""
|
||||
Get Model id
|
||||
"""
|
||||
# return 'min(sale_order_line.id)'
|
||||
return self.model_set_id and 'min('+self.model_set_id+'.id)'
|
||||
|
||||
def _sql_query_get(self, cr, uid, ids, prop, unknow_none, context, where_plus=[], limit=None, offset=None):
|
||||
"""
|
||||
Get sql query which return on sql_query field.
|
||||
@return: Dictionary of sql query.
|
||||
"""
|
||||
result = {}
|
||||
for obj in self.browse(cr, uid, ids):
|
||||
fields = []
|
||||
|
@ -332,7 +366,7 @@ class report_creator(osv.osv):
|
|||
for f in obj.field_ids:
|
||||
# Allowing to use count(*)
|
||||
if not f.field_id.model and f.group_method == 'count':
|
||||
fields.insert(0,('count(*) as column_count'))
|
||||
fields.insert(0, ('count(*) as column_count'))
|
||||
continue
|
||||
t = self.pool.get(f.field_id.model_id.model)._table
|
||||
if f.group_method == 'group':
|
||||
|
@ -340,11 +374,11 @@ class report_creator(osv.osv):
|
|||
else:
|
||||
fields.append('\t'+f.group_method+'('+t+'.'+f.field_id.name+')'+' as field'+str(i))
|
||||
groupby.append(t+'.'+f.field_id.name)
|
||||
i+=1
|
||||
i += 1
|
||||
models = self._path_get(cr, uid, obj.model_ids, obj.filter_ids)
|
||||
check = self._id_get(cr, uid, ids[0], context)
|
||||
if check<>False:
|
||||
fields.insert(0,(check+' as id'))
|
||||
fields.insert(0, (check + ' as id'))
|
||||
|
||||
if models:
|
||||
result[obj.id] = """select
|
||||
|
@ -365,36 +399,58 @@ class report_creator(osv.osv):
|
|||
return result
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Report Name',size=64, required=True),
|
||||
'type': fields.selection([('list','Rows And Columns Report'),], 'Report Type',required=True),#('sum','Summation Report')
|
||||
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the report without removing it."),
|
||||
'view_type1': fields.selection([('form','Form'),('tree','Tree'),('graph','Graph'),('calendar','Calendar')], 'First View', required=True),
|
||||
'view_type2': fields.selection([('','/'),('form','Form'),('tree','Tree'),('graph','Graph'),('calendar','Calendar')], 'Second View'),
|
||||
'view_type3': fields.selection([('','/'),('form','Form'),('tree','Tree'),('graph','Graph'),('calendar','Calendar')], 'Third View'),
|
||||
'view_graph_type': fields.selection([('pie','Pie Chart'),('bar','Bar Chart')], 'Graph Type', required=True),
|
||||
'view_graph_orientation': fields.selection([('horz','Horizontal'),('vert','Vertical')], 'Graph Orientation', required=True),
|
||||
'model_ids': fields.many2many('ir.model', 'base_report_creator_report_model_rel', 'report_id','model_id', 'Reported Objects'),
|
||||
'field_ids': fields.one2many('base_report_creator.report.fields', 'report_id', 'Fields to Display'),
|
||||
'filter_ids': fields.one2many('base_report_creator.report.filter', 'report_id', 'Filters'),
|
||||
'name': fields.char('Report Name', size=64, required=True),
|
||||
'type': fields.selection([('list', 'Rows And Columns Report'), ], 'Report Type', required=True), #('sum','Summation Report')
|
||||
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the report without removing it."),
|
||||
'view_type1': fields.selection([('form', 'Form'),
|
||||
('tree', 'Tree'),
|
||||
('graph', 'Graph'),
|
||||
('calendar', 'Calendar')], 'First View', required=True),
|
||||
'view_type2': fields.selection([('', '/'),
|
||||
('form', 'Form'),
|
||||
('tree', 'Tree'),
|
||||
('graph', 'Graph'),
|
||||
('calendar', 'Calendar')], 'Second View'),
|
||||
'view_type3': fields.selection([('', '/'),
|
||||
('form', 'Form'),
|
||||
('tree', 'Tree'),
|
||||
('graph', 'Graph'),
|
||||
('calendar', 'Calendar')], 'Third View'),
|
||||
'view_graph_type': fields.selection([('pie', 'Pie Chart'),
|
||||
('bar', 'Bar Chart')], 'Graph Type', required=True),
|
||||
'view_graph_orientation': fields.selection([('horz', 'Horizontal'),
|
||||
('vert', 'Vertical')], 'Graph Orientation', required=True),
|
||||
'model_ids': fields.many2many('ir.model', 'base_report_creator_report_model_rel', 'report_id', 'model_id', 'Reported Objects'),
|
||||
'field_ids': fields.one2many('base_report_creator.report.fields', 'report_id', 'Fields to Display'),
|
||||
'filter_ids': fields.one2many('base_report_creator.report.filter', 'report_id', 'Filters'),
|
||||
'state': fields.selection([
|
||||
('draft','Draft'),
|
||||
('valid','Valid')],
|
||||
'State', required=True,
|
||||
('draft', 'Draft'),
|
||||
('valid', 'Valid')],
|
||||
'State', required=True,
|
||||
help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed custom report. \
|
||||
\n* The \'Valid\' state is used when user validates the custom report.'),
|
||||
'sql_query': fields.function(_sql_query_get, method=True, type="text", string='SQL Query', store=True),
|
||||
'group_ids': fields.many2many('res.groups', 'base_report_creator_group_rel','report_id','group_id','Authorized Groups'),
|
||||
\n* The \'Valid\' state is used when user validates the custom report.'),
|
||||
'sql_query': fields.function(_sql_query_get, method=True, type="text", string='SQL Query', store=True),
|
||||
'group_ids': fields.many2many('res.groups', 'base_report_creator_group_rel', 'report_id', 'group_id', 'Authorized Groups'),
|
||||
}
|
||||
_defaults = {
|
||||
'type': lambda *args: 'list',
|
||||
'state': lambda *args: 'draft',
|
||||
'active': lambda *args: True,
|
||||
'view_type1': lambda *args: 'tree',
|
||||
'view_type2': lambda *args: 'graph',
|
||||
'view_graph_type': lambda *args: 'bar',
|
||||
'view_graph_orientation': lambda *args: 'horz',
|
||||
'type': lambda *args: 'list',
|
||||
'state': lambda *args: 'draft',
|
||||
'active': lambda *args: True,
|
||||
'view_type1': lambda *args: 'tree',
|
||||
'view_type2': lambda *args: 'graph',
|
||||
'view_graph_type': lambda *args: 'bar',
|
||||
'view_graph_orientation': lambda *args: 'horz',
|
||||
}
|
||||
def _function_field(self, cr, uid, ids):
|
||||
"""
|
||||
constraints function which specify that
|
||||
not display field which are not stored in Database.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Report creator's id.
|
||||
@return: True if display field which are stored in database.
|
||||
or false if display field which are not store in dtabase.
|
||||
"""
|
||||
this_objs = self.browse(cr, uid, ids)
|
||||
for obj in this_objs:
|
||||
for fld in obj.field_ids:
|
||||
|
@ -402,13 +458,23 @@ class report_creator(osv.osv):
|
|||
if not fld.field_id.model and fld.group_method == 'count':
|
||||
continue
|
||||
model_column = self.pool.get(fld.field_id.model)._columns[fld.field_id.name]
|
||||
if (isinstance(model_column,fields.function) or isinstance(model_column,fields.related)) and not model_column.store:
|
||||
if (isinstance(model_column, fields.function) or isinstance(model_column, fields.related)) and not model_column.store:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _aggregation_error(self, cr, uid, ids):
|
||||
aggregate_columns = ('integer','float')
|
||||
apply_functions = ('sum','min','max','avg','count')
|
||||
"""
|
||||
constraints function which specify that
|
||||
aggregate function to the non calculated field..
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Report creator's id.
|
||||
@return: True if model colume type is in integer or float.
|
||||
or false model colume type is not in integer or float.
|
||||
"""
|
||||
|
||||
aggregate_columns = ('integer', 'float')
|
||||
apply_functions = ('sum', 'min', 'max', 'avg', 'count')
|
||||
this_objs = self.browse(cr, uid, ids)
|
||||
for obj in this_objs:
|
||||
for fld in obj.field_ids:
|
||||
|
@ -425,7 +491,7 @@ class report_creator(osv.osv):
|
|||
required_types = []
|
||||
this_objs = self.browse(cr, uid, ids)
|
||||
for obj in this_objs:
|
||||
if obj.view_type1=='calendar' or obj.view_type2=='calendar' or obj.view_type3=='calendar':
|
||||
if obj.view_type1 == 'calendar' or obj.view_type2 == 'calendar' or obj.view_type3 == 'calendar':
|
||||
for fld in obj.field_ids:
|
||||
# Allowing to use count(*)
|
||||
if not fld.field_id.model and fld.group_method == 'count':
|
||||
|
@ -442,43 +508,60 @@ class report_creator(osv.osv):
|
|||
return True
|
||||
|
||||
_constraints = [
|
||||
(_function_field, 'You can not display field which are not stored in Database.', ['field_ids']),
|
||||
(_aggregation_error, 'You can apply aggregate function to the non calculated field.', ['field_ids']),
|
||||
(_calander_view_error, "You must have to give calendar view's color,start date and delay.", ['field_ids']),
|
||||
(_function_field, 'You can not display field which are not stored in Database.', ['field_ids']),
|
||||
(_aggregation_error, 'You can apply aggregate function to the non calculated field.', ['field_ids']),
|
||||
(_calander_view_error, "You must have to give calendar view's color,start date and delay.", ['field_ids']),
|
||||
]
|
||||
report_creator()
|
||||
|
||||
|
||||
class report_creator_field(osv.osv):
|
||||
"""
|
||||
Report Creator Field
|
||||
"""
|
||||
_name = "base_report_creator.report.fields"
|
||||
_description = "Display Fields"
|
||||
_rec_name = 'field_id'
|
||||
_order = "sequence,id"
|
||||
_columns = {
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of fields."),
|
||||
'field_id': fields.many2one('ir.model.fields', 'Field'),
|
||||
'report_id': fields.many2one('base_report_creator.report','Report', on_delete='cascade'),
|
||||
'group_method': fields.selection([('group','Grouped'),('sum','Sum'),('min','Minimum'),('count','Count'),('max','Maximum'),('avg','Average')], 'Grouping Method', required=True),
|
||||
'graph_mode': fields.selection([('','/'),('x','X Axis'),('y','Y Axis')], 'Graph Mode'),
|
||||
'calendar_mode': fields.selection([('','/'),('date_start','Starting Date'),('date_end','Ending Date'),('date_delay','Delay'),('date_stop','End Date'),('color','Unique Colors')], 'Calendar Mode'),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of fields."),
|
||||
'field_id': fields.many2one('ir.model.fields', 'Field'),
|
||||
'report_id': fields.many2one('base_report_creator.report', 'Report', on_delete='cascade'),
|
||||
'group_method': fields.selection([('group', 'Grouped'),
|
||||
('sum', 'Sum'),
|
||||
('min', 'Minimum'),
|
||||
('count', 'Count'),
|
||||
('max', 'Maximum'),
|
||||
('avg', 'Average')], 'Grouping Method', required=True),
|
||||
'graph_mode': fields.selection([('', '/'),
|
||||
('x', 'X Axis'),
|
||||
('y', 'Y Axis')], 'Graph Mode'),
|
||||
'calendar_mode': fields.selection([('', '/'),
|
||||
('date_start', 'Starting Date'),
|
||||
('date_end', 'Ending Date'), ('date_delay', 'Delay'), ('date_stop', 'End Date'), ('color', 'Unique Colors')], 'Calendar Mode'),
|
||||
}
|
||||
_defaults = {
|
||||
'group_method': lambda *args: 'group',
|
||||
'graph_mode': lambda *args: '',
|
||||
'group_method': lambda *args: 'group',
|
||||
'graph_mode': lambda *args: '',
|
||||
}
|
||||
report_creator_field()
|
||||
|
||||
|
||||
class report_creator_filter(osv.osv):
|
||||
"""
|
||||
Report Creator Filter
|
||||
"""
|
||||
_name = "base_report_creator.report.filter"
|
||||
_description = "Report Filters"
|
||||
_columns = {
|
||||
'name': fields.char('Filter Name',size=64, required=True),
|
||||
'expression': fields.text('Value', required=True,help='Provide an expression for the field based on which you want to filter the records.\n e.g. res_partner.id=3'),
|
||||
'report_id': fields.many2one('base_report_creator.report','Report', on_delete='cascade'),
|
||||
'condition' : fields.selection([('and','AND'),('or','OR')], 'Condition')
|
||||
'name': fields.char('Filter Name', size=64, required=True),
|
||||
'expression': fields.text('Value', required=True, help='Provide an expression for the field based on which you want to filter the records.\n e.g. res_partner.id=3'),
|
||||
'report_id': fields.many2one('base_report_creator.report', 'Report', on_delete='cascade'),
|
||||
'condition': fields.selection([('and', 'AND'),
|
||||
('or', 'OR')], 'Condition')
|
||||
}
|
||||
_defaults = {
|
||||
'condition': lambda *args: 'and',
|
||||
'condition': lambda *args: 'and',
|
||||
}
|
||||
report_creator_filter()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Report Creator form -->
|
||||
|
||||
<record model="ir.ui.view" id="base_report_creator_form">
|
||||
<field name="name">base_report_creator.report.form</field>
|
||||
<field name="model">base_report_creator.report</field>
|
||||
|
@ -38,10 +41,13 @@
|
|||
<field name="active" select="2"/>
|
||||
<notebook colspan="4">
|
||||
<page string="General Configuration">
|
||||
<field name="model_ids" colspan="4" context="{'model_ids':model_ids}"/>
|
||||
<field name="model_ids" colspan="4"
|
||||
context="{'model_ids':model_ids}" />
|
||||
<separator string="State" colspan="4"/>
|
||||
<field name="state"/>
|
||||
<button string="Create Menu" name="%(wizard_menu_create)d" type="action" colspan="2" icon="gtk-justify-fill"/>
|
||||
<button string="Create Menu"
|
||||
name="%(action_report_menu_create)d" type="action"
|
||||
colspan="2" icon="gtk-justify-fill" />
|
||||
</page><page string="View parameters">
|
||||
<separator string="Used View" colspan="4"/>
|
||||
<field name="view_type1"/>
|
||||
|
@ -54,12 +60,13 @@
|
|||
<field name="field_ids" nolabel="1" colspan="4">
|
||||
<form string="Fields">
|
||||
<field name="sequence"/>
|
||||
<field name="field_id" domain="parent.model_ids and [('model_id','in',parent.model_ids[0][2]),('ttype','<>','many2many'),('ttype','<>','one2many')] or []">
|
||||
<tree string="Field List">
|
||||
<field name="model_id"/>
|
||||
<field name="name"/>
|
||||
<field name="field_description"/>
|
||||
</tree>
|
||||
<field name="field_id"
|
||||
domain="parent.model_ids and [('model_id','in',parent.model_ids[0][2]),('ttype','<>','many2many'),('ttype','<>','one2many')] or []">
|
||||
<tree string="Field List">
|
||||
<field name="model_id" />
|
||||
<field name="name" />
|
||||
<field name="field_description" />
|
||||
</tree>
|
||||
</field>
|
||||
<field name="group_method"/>
|
||||
<field name="graph_mode"/>
|
||||
|
@ -67,14 +74,18 @@
|
|||
</form>
|
||||
<tree editable="bottom" string="Fields to Display">
|
||||
<field name="sequence"/>
|
||||
<field name="field_id" domain="parent.model_ids and [('model_id','in',parent.model_ids[0][2]),('ttype','<>','many2many'),('ttype','<>','one2many')] or []" attrs="{'required':[('group_method','!=','count')]}"/>
|
||||
<field name="field_id"
|
||||
domain="parent.model_ids and [('model_id','in',parent.model_ids[0][2]),('ttype','<>','many2many'),('ttype','<>','one2many')] or []"
|
||||
attrs="{'required':[('group_method','!=','count')]}" />
|
||||
<field name="group_method"/>
|
||||
<field name="graph_mode"/>
|
||||
<field name="calendar_mode"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page><page string="Filters on Fields">
|
||||
<button string="Add filter" name="%(wizard_set_filter_fields)d" type="action" icon="gtk-add"/>
|
||||
<button string="Add filter"
|
||||
name="%(wizard_set_filter_fields)d" type="action"
|
||||
icon="gtk-add" />
|
||||
<field name="filter_ids" nolabel="1" colspan="4">
|
||||
<tree string="Filters">
|
||||
<field name="name"/>
|
||||
|
@ -87,8 +98,10 @@
|
|||
</form>
|
||||
</field>
|
||||
<separator string="Legend" colspan="4"/>
|
||||
<label string="Use %%(uid)s to filter by the connected user" align="0.0"/>
|
||||
</page><page string="Security">
|
||||
<label
|
||||
string="Use %%(uid)s to filter by the connected user"
|
||||
align="0.0" />
|
||||
</page><page string="Security">
|
||||
<separator string="Authorized Groups (empty for all)" colspan="4"/>
|
||||
<field name="group_ids" colspan="4" nolabel="1"/>
|
||||
</page><page string="SQL Query">
|
||||
|
@ -98,15 +111,20 @@
|
|||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action for Report creator form -->
|
||||
|
||||
<record model="ir.actions.act_window" id="base_report_creator_action">
|
||||
<field name="name">Custom Report</field>
|
||||
<field name="res_model">base_report_creator.report</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Custom Reports" id="base.menu_custom_reports"
|
||||
action="base_report_creator_action" parent="base.reporting_menu" sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
name="Custom Reports" parent="base.next_id_50"
|
||||
id="menu_base_report_creator_action_config"
|
||||
|
@ -122,36 +140,22 @@
|
|||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="base_report_creator_action_tree">
|
||||
<field name="res_model">base_report_creator.report</field>
|
||||
<field name="view_type">tree</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Custom Reports" parent="base.menu_custom_reports"
|
||||
id="menu_base_report_creator_action"
|
||||
action="base_report_creator_action_tree"/>
|
||||
|
||||
<wizard
|
||||
id="wizard_report_open"
|
||||
string="Open Report"
|
||||
name="base_report_creator.report.open"/>
|
||||
|
||||
<record model="ir.values" id="ir_open_report">
|
||||
<field name="key2" eval="'tree_but_open'"/>
|
||||
<field name="model" eval="'base_report_creator.report'"/>
|
||||
<field name="name">Browse Report</field>
|
||||
<field name="value" eval="'ir.actions.wizard,%d'%wizard_report_open"/>
|
||||
<field name="object" eval="True"/>
|
||||
</record>
|
||||
<record model="ir.values" id="ir_open_report_multi">
|
||||
<field name="key2" eval="'client_action_multi'"/>
|
||||
<field name="model" eval="'base_report_creator.report'"/>
|
||||
<field name="name">Browse Report</field>
|
||||
<field name="value" eval="'ir.actions.wizard,%d'%wizard_report_open"/>
|
||||
<field name="object" eval="True"/>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<act_window id="action_report_open"
|
||||
key2="client_action_multi" name="Open Report"
|
||||
res_model="report.open" src_model="base_report_creator.report"
|
||||
view_mode="form" target="new" view_type="form" />
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<wizard
|
||||
id="wizard_set_filter_fields"
|
||||
string="Set Filter Fields"
|
||||
name="base_report_creator.report_filter.fields"/>
|
||||
<wizard
|
||||
id="wizard_menu_create"
|
||||
string="Create Menu for Report"
|
||||
name="base_report_creator.report.menu.create"/>
|
||||
</data>
|
||||
<data>
|
||||
<wizard id="wizard_set_filter_fields" string="Set Filter Fields"
|
||||
name="base_report_creator.report_filter.fields" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_base_report_creator_report,base_report_creator.report,model_base_report_creator_report,base.group_system,1,1,1,1
|
||||
access_base_report_creator_report_fields,base_report_creator.report.fields,model_base_report_creator_report_fields,base.group_system,1,1,1,1
|
||||
access_base_report_creator_report_filter,base_report_creator.report.filter,model_base_report_creator_report_filter,base.group_system,1,1,1,1
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_base_report_creator_report","base_report_creator.report","model_base_report_creator_report","base.group_system",1,1,1,1
|
||||
"access_base_report_creator_report_fields","base_report_creator.report.fields","model_base_report_creator_report_fields","base.group_system",1,1,1,1
|
||||
"access_base_report_creator_report_filter","base_report_creator.report.filter","model_base_report_creator_report_filter","base.group_system",1,1,1,1
|
||||
"access_report_menu_create","report.menu.create","model_report_menu_create","base.group_system",1,1,1,1
|
||||
"access_report_open","report.open","model_report_open","base.group_system",1,1,1,1
|
||||
|
|
|
|
@ -20,7 +20,7 @@
|
|||
##############################################################################
|
||||
|
||||
import wiz_set_filter_fields
|
||||
import base_report_creator_open
|
||||
import report_menu_create
|
||||
import report_open
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -19,63 +19,56 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields, osv
|
||||
|
||||
import time
|
||||
import wizard
|
||||
import osv
|
||||
import pooler
|
||||
|
||||
section_form = '''<?xml version="1.0"?>
|
||||
<form string="Create Menu For This Report">
|
||||
<separator string="Menu Information" colspan="4"/>
|
||||
<field name="menu_name"/>
|
||||
<field name="menu_parent_id"/>
|
||||
</form>'''
|
||||
|
||||
section_fields = {
|
||||
'menu_name': {'string':'Menu Name', 'type':'char', 'required':True, 'size':64},
|
||||
'menu_parent_id': {'string':'Parent Menu', 'type':'many2one', 'relation':'ir.ui.menu', 'required':True},
|
||||
}
|
||||
|
||||
def report_menu_create(self, cr, uid, data, context):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
board = pool.get('base_report_creator.report').browse(cr, uid, data['id'])
|
||||
|
||||
view = board.view_type1
|
||||
if board.view_type2:
|
||||
view+=','+board.view_type2
|
||||
if board.view_type3:
|
||||
view+=','+board.view_type3
|
||||
action_id = pool.get('ir.actions.act_window').create(cr, uid, {
|
||||
'name': board.name,
|
||||
'view_type':'form',
|
||||
'view_mode':view,
|
||||
'context': "{'report_id':%d}" % (board.id,),
|
||||
'res_model': 'base_report_creator.report'
|
||||
})
|
||||
pool.get('ir.ui.menu').create(cr, uid, {
|
||||
'name': data['form']['menu_name'],
|
||||
'parent_id': data['form']['menu_parent_id'],
|
||||
'icon': 'STOCK_SELECT_COLOR',
|
||||
'action': 'ir.actions.act_window,'+str(action_id)
|
||||
}, context)
|
||||
return {}
|
||||
|
||||
class wizard_section_menu_create(wizard.interface):
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type':'form', 'arch':section_form, 'fields':section_fields, 'state':[('end','Cancel'),('create_menu','Create Menu')]}
|
||||
},
|
||||
'create_menu': {
|
||||
'actions': [report_menu_create],
|
||||
'result': {
|
||||
'type':'state',
|
||||
'state':'end'
|
||||
}
|
||||
}
|
||||
}
|
||||
wizard_section_menu_create('base_report_creator.report.menu.create')
|
||||
class report_menu_create(osv.osv_memory):
|
||||
"""
|
||||
Create Menu
|
||||
"""
|
||||
_name = "report.menu.create"
|
||||
_description = "Menu Create"
|
||||
_columns = {
|
||||
'menu_name':fields.char('Menu Name', size=64, required=True),
|
||||
'menu_parent_id':fields.many2one('ir.ui.menu', 'Parent Menu', required=True),
|
||||
}
|
||||
|
||||
def report_menu_create(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Create Menu.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Report Menu Create's IDs
|
||||
@return: Dictionary {}.
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
context_id = context and context.get('active_id', False) or False
|
||||
if context_id:
|
||||
board = self.pool.get('base_report_creator.report').browse(cr, uid, context_id)
|
||||
view = board.view_type1
|
||||
if board.view_type2:
|
||||
view += ',' + board.view_type2
|
||||
if board.view_type3:
|
||||
view += ',' + board.view_type3
|
||||
action_id = self.pool.get('ir.actions.act_window').create(cr, uid, {
|
||||
'name': board.name,
|
||||
'view_type':'form',
|
||||
'view_mode':view,
|
||||
'context': "{'report_id':%d}" % (board.id,),
|
||||
'res_model': 'base_report_creator.report'
|
||||
})
|
||||
obj_menu = self.pool.get('ir.ui.menu')
|
||||
#start Loop
|
||||
for data in self.read(cr, uid, ids):
|
||||
obj_menu.create(cr, uid, {
|
||||
'name': data.get('menu_name'),
|
||||
'parent_id': data.get('menu_parent_id'),
|
||||
'icon': 'STOCK_SELECT_COLOR',
|
||||
'action': 'ir.actions.act_window, ' + str(action_id)
|
||||
}, context=context)
|
||||
return {}
|
||||
#End Loop
|
||||
report_menu_create()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Create Menu For report -->
|
||||
|
||||
<record id="view_report_menu_create" model="ir.ui.view">
|
||||
<field name="name">report.menu.create.form</field>
|
||||
<field name="model">report.menu.create</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Create Menu For This Report">
|
||||
<group colspan="4" >
|
||||
<separator string="Menu Information" colspan="4"/>
|
||||
<field name="menu_name"/>
|
||||
<field name="menu_parent_id"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<button icon="gtk-cancel" special="cancel"
|
||||
string="Cancel" />
|
||||
<button icon="gtk-save" string="Create Menu"
|
||||
name="report_menu_create" type="object" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_report_menu_create" model="ir.actions.act_window">
|
||||
<field name="name">Create Menu for Report</field>
|
||||
<field name="res_model">report.menu.create</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_report_menu_create"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,71 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
|
||||
class report_open(osv.osv_memory):
|
||||
"""
|
||||
Open report
|
||||
"""
|
||||
_name = "report.open"
|
||||
_description = __doc__
|
||||
|
||||
def open_report(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This Function opens base creator report view
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of report open's IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
@return : Dictionary value for base creator report form
|
||||
"""
|
||||
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
context_id = context and context.get('active_id', False) or False
|
||||
|
||||
if context.get('report_id', False):
|
||||
raise osv.except_osv(_('UserError'), _('No Wizards available for this object!'))
|
||||
|
||||
rep = self.pool.get('base_report_creator.report').browse(cr, uid, context_id, context)
|
||||
view_mode = rep.view_type1
|
||||
|
||||
if rep.view_type2:
|
||||
view_mode += ',' + rep.view_type2
|
||||
if rep.view_type3:
|
||||
view_mode += ',' + rep.view_type3
|
||||
value = {
|
||||
'name': rep.name,
|
||||
'view_type': 'form',
|
||||
'view_mode': view_mode,
|
||||
'res_model': 'base_report_creator.report',
|
||||
'context': {'report_id': context_id},
|
||||
'view_id': False,
|
||||
'type': 'ir.actions.act_window'
|
||||
}
|
||||
|
||||
return value
|
||||
|
||||
report_open()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Report Open wizard -->
|
||||
|
||||
<record id="view_report_open" model="ir.ui.view">
|
||||
<field name="name">report.open.form</field>
|
||||
<field name="model">report.open</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Report open">
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<button icon="gtk-cancel" special="cancel"
|
||||
string="Cancel" />
|
||||
<button icon="gtk-open" string="Open Report"
|
||||
name="open_report" type="object" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_report_open" model="ir.actions.act_window">
|
||||
<field name="name">Open Report</field>
|
||||
<field name="res_model">report.open</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_report_open"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -23,4 +23,3 @@ import board
|
|||
import wizard
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
{
|
||||
'name': 'Dashboard main module',
|
||||
'version': '1.0',
|
||||
|
@ -27,7 +26,7 @@
|
|||
'description': """Base module for all dashboards.""",
|
||||
'author': 'Tiny',
|
||||
'depends': ['base'],
|
||||
'update_xml': ['security/ir.model.access.csv', 'board_view.xml'],
|
||||
'update_xml': ['security/ir.model.access.csv', 'wizard/board_menu_create_view.xml', 'board_view.xml'],
|
||||
'demo_xml': [],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
|
|
|
@ -19,28 +19,42 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields, osv
|
||||
import time
|
||||
from osv import fields,osv
|
||||
|
||||
class board_board(osv.osv):
|
||||
"""
|
||||
Board
|
||||
"""
|
||||
_name = 'board.board'
|
||||
_description = "Board"
|
||||
|
||||
def create_view(self, cr, uid, ids, context):
|
||||
|
||||
board = self.pool.get('board.board').browse(cr, uid, ids, context)
|
||||
def create_view(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Create view
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Board's IDs
|
||||
@return: arch of xml view.
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
board = self.pool.get('board.board').browse(cr, uid, ids, context=context)
|
||||
left = []
|
||||
right = []
|
||||
#start Loop
|
||||
for line in board.line_ids:
|
||||
linestr = '<action string="%s" name="%d" colspan="4"' % (line.name, line.action_id.id)
|
||||
if line.height:
|
||||
linestr+=(' height="%d"' % (line.height,))
|
||||
linestr += (' height="%d"' % (line.height, ))
|
||||
if line.width:
|
||||
linestr+=(' width="%d"' % (line.width,))
|
||||
linestr += (' width="%d"' % (line.width, ))
|
||||
linestr += '/>'
|
||||
if line.position=='left':
|
||||
if line.position == 'left':
|
||||
left.append(linestr)
|
||||
else:
|
||||
right.append(linestr)
|
||||
#End Loop
|
||||
arch = """<?xml version="1.0"?>
|
||||
<form string="My Board">
|
||||
<hpaned>
|
||||
|
@ -55,24 +69,45 @@ class board_board(osv.osv):
|
|||
|
||||
return arch
|
||||
|
||||
def write(self, cr, uid, ids, vals, context={}):
|
||||
def write(self, cr, uid, ids, vals, context = {}):
|
||||
|
||||
"""
|
||||
Writes values in one or several fields.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Board's IDs
|
||||
@param vals: dictionary with values to update.
|
||||
dictionary must be with the form: {‘name_of_the_field’: value, ...}.
|
||||
@return: True
|
||||
"""
|
||||
result = super(board_board, self).write(cr, uid, ids, vals, context)
|
||||
|
||||
board = self.pool.get('board.board').browse(cr, uid, ids[0])
|
||||
|
||||
view = self.create_view(cr, uid, ids[0], context)
|
||||
id = board.view_id.id
|
||||
cr.execute("update ir_ui_view set arch=%s where id=%s" , (view, id))
|
||||
cr.execute("update ir_ui_view set arch=%s where id=%s", (view, id))
|
||||
return result
|
||||
|
||||
def create(self, cr, user, vals, context=None):
|
||||
"""
|
||||
create new record.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param vals: dictionary of values for every field.
|
||||
dictionary must use this form: {‘name_of_the_field’: value, ...}
|
||||
@return: id of new created record of board.board.
|
||||
"""
|
||||
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
if not 'name' in vals:
|
||||
return False
|
||||
id = super(board_board, self).create(cr, user, vals, context)
|
||||
view_id = self.pool.get('ir.ui.view').create(cr, user, {
|
||||
'name': vals['name'],
|
||||
'model':'board.board',
|
||||
'priority':16,
|
||||
'model': 'board.board',
|
||||
'priority': 16,
|
||||
'type': 'form',
|
||||
'arch': self.create_view(cr, user, id, context),
|
||||
})
|
||||
|
@ -81,17 +116,28 @@ class board_board(osv.osv):
|
|||
|
||||
return id
|
||||
|
||||
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
|
||||
res = {}
|
||||
res = super(board_board, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
|
||||
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None,\
|
||||
toolbar=False, submenu=False):
|
||||
"""
|
||||
Overrides orm field_view_get.
|
||||
@return: Dictionary of Fields, arch and toolbar.
|
||||
"""
|
||||
|
||||
vids = self.pool.get('ir.ui.view.custom').search(cr, user, [('user_id','=',user), ('ref_id','=',view_id)])
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
res = {}
|
||||
res = super(board_board, self).fields_view_get(cr, user, view_id, view_type,\
|
||||
context, toolbar=toolbar, submenu=submenu)
|
||||
|
||||
vids = self.pool.get('ir.ui.view.custom').search(cr, user,\
|
||||
[('user_id', '=', user), ('ref_id' ,'=', view_id)])
|
||||
if vids:
|
||||
view_id = vids[0]
|
||||
arch = self.pool.get('ir.ui.view.custom').browse(cr, user, view_id)
|
||||
res['arch'] = arch.arch
|
||||
|
||||
res['toolbar'] = {'print':[],'action':[],'relate':[]}
|
||||
res['toolbar'] = {'print': [], 'action': [], 'relate': []}
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
|
@ -102,44 +148,67 @@ class board_board(osv.osv):
|
|||
|
||||
# the following lines added to let the button on dashboard work.
|
||||
_defaults = {
|
||||
'name': lambda *args: 'Dashboard'
|
||||
'name':lambda *args: 'Dashboard'
|
||||
}
|
||||
|
||||
board_board()
|
||||
|
||||
|
||||
class board_line(osv.osv):
|
||||
"""
|
||||
Board Line
|
||||
"""
|
||||
_name = 'board.board.line'
|
||||
_description = "Board Line"
|
||||
_order = 'position,sequence'
|
||||
_columns = {
|
||||
'name': fields.char('Title', size=64, required=True),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of board lines."),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order\
|
||||
when displaying a list of board lines."),
|
||||
'height': fields.integer('Height'),
|
||||
'width': fields.integer('Width'),
|
||||
'board_id': fields.many2one('board.board', 'Dashboard', required=True, ondelete='cascade'),
|
||||
'action_id': fields.many2one('ir.actions.act_window', 'Action', required=True),
|
||||
'position': fields.selection([('left','Left'),('right','Right')], 'Position', required=True)
|
||||
'position': fields.selection([('left','Left'),
|
||||
('right','Right')], 'Position', required=True)
|
||||
}
|
||||
_defaults = {
|
||||
'position': lambda *args: 'left'
|
||||
}
|
||||
|
||||
board_line()
|
||||
|
||||
|
||||
class board_note_type(osv.osv):
|
||||
"""
|
||||
Board note Type
|
||||
"""
|
||||
_name = 'board.note.type'
|
||||
_description = "NOte Type"
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Note Type', size=64, required=True),
|
||||
}
|
||||
|
||||
board_note_type()
|
||||
|
||||
def _type_get(self, cr, uid, context={}):
|
||||
"""
|
||||
Get by default Note type.
|
||||
"""
|
||||
obj = self.pool.get('board.note.type')
|
||||
ids = obj.search(cr, uid, [])
|
||||
res = obj.read(cr, uid, ids, ['name'], context)
|
||||
res = [(r['name'], r['name']) for r in res]
|
||||
return res
|
||||
|
||||
|
||||
class board_note(osv.osv):
|
||||
"""
|
||||
Board Note
|
||||
"""
|
||||
_name = 'board.note'
|
||||
_description = "Note"
|
||||
_columns = {
|
||||
'name': fields.char('Subject', size=128, required=True),
|
||||
'note': fields.text('Note'),
|
||||
|
@ -148,10 +217,10 @@ class board_note(osv.osv):
|
|||
'type': fields.selection(_type_get, 'Note type', size=64),
|
||||
}
|
||||
_defaults = {
|
||||
'user_id': lambda object,cr,uid,context: uid,
|
||||
'date': lambda object,cr,uid,context: time.strftime('%Y-%m-%d'),
|
||||
'user_id': lambda object, cr, uid, context: uid,
|
||||
'date': lambda object, cr, uid, context: time.strftime('%Y-%m-%d'),
|
||||
}
|
||||
|
||||
board_note()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<menuitem icon="terp-graph" id="base.reporting_menu" name="Reporting" sequence="8"/>
|
||||
<!-- <menuitem icon="terp-graph" id="dashboard" name="Dashboards" sequence="2" parent="base.reporting_menu"/>-->
|
||||
<menuitem icon="terp-graph" id="base.reporting_menu"
|
||||
name="Reporting" sequence="8" />
|
||||
|
||||
<!--Board Note Tree View -->
|
||||
|
||||
<record id="view_board_note_tree" model="ir.ui.view">
|
||||
<field name="name">board.note.tree</field>
|
||||
<field name="model">board.note</field>
|
||||
|
@ -13,6 +16,9 @@
|
|||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--Board Note Form View -->
|
||||
|
||||
<record id="view_board_note_form" model="ir.ui.view">
|
||||
<field name="name">board.note.form</field>
|
||||
<field name="model">board.note</field>
|
||||
|
@ -27,6 +33,9 @@
|
|||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action for Publish note Form -->
|
||||
|
||||
<record id="action_view_board_note_form" model="ir.actions.act_window">
|
||||
<field name="name">Publish a note</field>
|
||||
<field name="res_model">board.note</field>
|
||||
|
@ -34,7 +43,7 @@
|
|||
<field name="view_mode">form,tree</field>
|
||||
</record>
|
||||
|
||||
<wizard id="wizard_board_create_menu" model="board.board" multi="True" name="board.board.menu.create" string="Create Board Menu" />
|
||||
<!-- Board Tree View -->
|
||||
|
||||
<record id="view_board_tree" model="ir.ui.view">
|
||||
<field name="name">board.board.tree</field>
|
||||
|
@ -46,6 +55,9 @@
|
|||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Dashboard Definition Form View -->
|
||||
|
||||
<record id="view_board_form" model="ir.ui.view">
|
||||
<field name="name">board.board.form</field>
|
||||
<field name="model">board.board</field>
|
||||
|
@ -54,7 +66,10 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Dashboard">
|
||||
<field name="name" select="1"/>
|
||||
<button colspan="2" name="%(wizard_board_create_menu)d" string="Create Menu" type="action" icon="gtk-justify-fill"/>
|
||||
<button colspan="2"
|
||||
name="%(action_board_menu_create)d"
|
||||
string="Create Menu" type="action"
|
||||
icon="gtk-justify-fill" />
|
||||
<field colspan="4" name="line_ids">
|
||||
<tree string="Dashboard View">
|
||||
<field name="name"/>
|
||||
|
@ -67,19 +82,24 @@
|
|||
<field name="sequence"/>
|
||||
<field name="width"/>
|
||||
<field name="height"/>
|
||||
<field name="action_id" domain="[('view_type','!=','tree')]"/>
|
||||
<field name="action_id"
|
||||
domain="[('view_type','!=','tree')]" />
|
||||
<field name="position"/>
|
||||
</form>
|
||||
</field>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action for DashBoard Definition form -->
|
||||
|
||||
<record id="action_view_board_list_form" model="ir.actions.act_window">
|
||||
<field name="name">Dashboard Definition</field>
|
||||
<field name="res_model">board.board</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="base.next_id_50"
|
||||
name="Configuration"
|
||||
|
@ -90,10 +110,14 @@
|
|||
action="action_view_board_list_form"
|
||||
id="menu_view_board_form"
|
||||
parent="base.next_id_50" sequence="1"/>
|
||||
<menuitem action="action_view_board_note_form" id="menu_view_board_note_form" parent="base.next_id_50"
|
||||
sequence="3"
|
||||
groups="base.group_system" />
|
||||
<act_window context="{'view': active_id}" id="dashboard_open" multi="True" name="Open Dashboard" res_model="board.board" src_model="board.board"/>
|
||||
|
||||
<menuitem action="action_view_board_note_form"
|
||||
id="menu_view_board_note_form" parent="base.next_id_50"
|
||||
sequence="3" groups="base.group_system" />
|
||||
|
||||
<act_window context="{'view': active_id}" id="dashboard_open"
|
||||
multi="True" name="Open Dashboard" res_model="board.board"
|
||||
src_model="board.board" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_board_board,board.board,model_board_board,base.group_user,1,1,1,1
|
||||
access_board_board_line,board.board.line,model_board_board_line,base.group_user,1,1,1,1
|
||||
access_board_note_type,board.note.type,model_board_note_type,base.group_user,1,1,1,1
|
||||
access_board_note,board.note,model_board_note,base.group_user,1,1,1,1
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_board_board","board.board","model_board_board","base.group_user",1,1,1,1
|
||||
"access_board_board_line","board.board.line","model_board_board_line","base.group_user",1,1,1,1
|
||||
"access_board_note_type","board.note.type","model_board_note_type","base.group_user",1,1,1,1
|
||||
"access_board_note","board.note","model_board_note","base.group_user",1,1,1,1
|
||||
"access_board_menu_create","board.menu.create","model_board_menu_create","base.group_user",1,1,1,1
|
||||
|
|
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import board_wizard
|
||||
import board_menu_create
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 osv import fields, osv
|
||||
from tools.translate import _
|
||||
|
||||
class board_menu_create(osv.osv_memory):
|
||||
"""
|
||||
Create Menu
|
||||
"""
|
||||
def view_init(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function checks for precondition before wizard executes
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param fields: List of fields for default value
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
check dashboard view on menu name field.
|
||||
@return: False
|
||||
"""
|
||||
data = context and context.get('active_id', False) or False
|
||||
if data:
|
||||
board = self.pool.get('board.board').browse(cr, uid, data)
|
||||
if not board.line_ids:
|
||||
raise osv.except_osv(_('User Error!'),
|
||||
_('Please Insert Dashboard View(s) !'))
|
||||
return False
|
||||
|
||||
|
||||
def board_menu_create(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Create Menu.
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Board Menu Create's IDs
|
||||
@return: Dictionary {}.
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
context_id = context and context.get('active_id', False) or False
|
||||
if context_id:
|
||||
board = self.pool.get('board.board').browse(cr, uid, context_id)
|
||||
action_id = self.pool.get('ir.actions.act_window').create(cr, uid, {
|
||||
'name': board.name,
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'board.board',
|
||||
'view_id': board.view_id.id,
|
||||
})
|
||||
obj_menu = self.pool.get('ir.ui.menu')
|
||||
#start Loop
|
||||
for data in self.read(cr, uid, ids):
|
||||
obj_menu.create(cr, uid, {
|
||||
'name': data.get('menu_name'),
|
||||
'parent_id': data.get('menu_parent_id'),
|
||||
'icon': 'STOCK_SELECT_COLOR',
|
||||
'action': 'ir.actions.act_window,' + str(action_id)
|
||||
}, context=context)
|
||||
#End Loop
|
||||
return {}
|
||||
|
||||
_name = "board.menu.create"
|
||||
_description = "Menu Create"
|
||||
|
||||
_columns = {
|
||||
'menu_name': fields.char('Menu Name', size=64, required=True),
|
||||
'menu_parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True),
|
||||
}
|
||||
|
||||
board_menu_create()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!--Board menu create wizard -->
|
||||
|
||||
<record id="view_board_menu_create" model="ir.ui.view">
|
||||
<field name="name">board.menu.create.form</field>
|
||||
<field name="model">board.menu.create</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Create Menu For Dashboard">
|
||||
<group colspan="4" >
|
||||
<separator string="Menu Information" colspan="4"/>
|
||||
<field name="menu_name"/>
|
||||
<field name="menu_parent_id"/>
|
||||
</group>
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<button icon="gtk-cancel" special="cancel"
|
||||
string="Cancel" />
|
||||
<button icon="gtk-save" string="Create Menu"
|
||||
name="board_menu_create" type="object" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action for Board Menu create wizard. -->
|
||||
|
||||
<record id="action_board_menu_create" model="ir.actions.act_window">
|
||||
<field name="name">Create Board Menu</field>
|
||||
<field name="res_model">board.menu.create</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_board_menu_create"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,86 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 wizard
|
||||
import osv
|
||||
import pooler
|
||||
from tools.translate import _
|
||||
|
||||
section_form = '''<?xml version="1.0"?>
|
||||
<form string="Create Menu For Dashboard">
|
||||
<separator string="Menu Information" colspan="4"/>
|
||||
<field name="menu_name"/>
|
||||
<field name="menu_parent_id"/>
|
||||
</form>'''
|
||||
|
||||
section_fields = {
|
||||
'menu_name': {'string':'Menu Name', 'type':'char', 'required':True, 'size':64},
|
||||
'menu_parent_id': {'string':'Parent Menu', 'type':'many2one', 'relation':'ir.ui.menu', 'required':True},
|
||||
}
|
||||
|
||||
def check_views(self, cr, uid, data, context):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
board = pool.get('board.board').browse(cr, uid, data['id'])
|
||||
if not board.line_ids:
|
||||
raise wizard.except_wizard(_('User Error!'),_('Please Insert Dashboard View(s) !'))
|
||||
return data['form']
|
||||
|
||||
def board_menu_create(self, cr, uid, data, context):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
board = pool.get('board.board').browse(cr, uid, data['id'])
|
||||
|
||||
action_id = pool.get('ir.actions.act_window').create(cr, uid, {
|
||||
'name': board.name,
|
||||
'view_type':'form',
|
||||
'view_mode':'form',
|
||||
'res_model': 'board.board',
|
||||
'view_id': board.view_id.id,
|
||||
})
|
||||
pool.get('ir.ui.menu').create(cr, uid, {
|
||||
'name': data['form']['menu_name'],
|
||||
'parent_id': data['form']['menu_parent_id'],
|
||||
'icon': 'STOCK_SELECT_COLOR',
|
||||
'action': 'ir.actions.act_window,'+str(action_id)
|
||||
}, context)
|
||||
|
||||
return {}
|
||||
|
||||
class wizard_section_menu_create(wizard.interface):
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [check_views],
|
||||
'result': {'type':'form', 'arch':section_form, 'fields':section_fields, 'state':[('end','Cancel'),('create_menu','Create Menu')]}
|
||||
},
|
||||
'create_menu': {
|
||||
'actions': [board_menu_create],
|
||||
'result': {
|
||||
'type':'state',
|
||||
'state':'end'
|
||||
}
|
||||
}
|
||||
}
|
||||
wizard_section_menu_create('board.board.menu.create')
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -27,6 +27,7 @@ __author__ = AUTHOR
|
|||
|
||||
from BaseHTTPServer import BaseHTTPRequestHandler
|
||||
import os
|
||||
|
||||
class BufferedHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
"""
|
||||
Buffering HTTP Request Handler
|
||||
|
@ -47,12 +48,12 @@ class BufferedHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||
If you override the handle() method remember to call
|
||||
this (see below)
|
||||
"""
|
||||
self.__buffer=""
|
||||
self.__outfp=os.tmpfile()
|
||||
self.__buffer = ""
|
||||
self.__outfp = os.tmpfile()
|
||||
|
||||
def _append(self,s):
|
||||
""" append a string to the buffer """
|
||||
self.__buffer=self.__buffer+s
|
||||
self.__buffer = self.__buffer+s
|
||||
|
||||
def _flush(self):
|
||||
""" flush the buffer to wfile """
|
||||
|
@ -60,7 +61,7 @@ class BufferedHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||
self.__outfp.write(self.__buffer)
|
||||
self.__outfp.flush()
|
||||
self.wfile.flush()
|
||||
self.__buffer=""
|
||||
self.__buffer = ""
|
||||
|
||||
def handle(self):
|
||||
""" Handle a HTTP request """
|
||||
|
@ -97,3 +98,4 @@ class BufferedHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||
|
||||
protocol_version="HTTP/1.1"
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,3 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Python WebDAV Server.
|
||||
Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
|
||||
|
@ -23,12 +25,20 @@ Subclass this class and specify an IFACE_CLASS. See example.
|
|||
|
||||
"""
|
||||
|
||||
DEBUG=None
|
||||
DEBUG = None
|
||||
|
||||
from utils import VERSION, AUTHOR
|
||||
__version__ = VERSION
|
||||
__author__ = AUTHOR
|
||||
|
||||
from propfind import PROPFIND
|
||||
from delete import DELETE
|
||||
from davcopy import COPY
|
||||
from davmove import MOVE
|
||||
|
||||
from string import atoi, split
|
||||
from status import STATUS_CODES
|
||||
from errors import *
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
@ -39,16 +49,6 @@ import posixpath
|
|||
import base64
|
||||
import urlparse
|
||||
import urllib
|
||||
|
||||
from propfind import PROPFIND
|
||||
from delete import DELETE
|
||||
from davcopy import COPY
|
||||
from davmove import MOVE
|
||||
|
||||
from string import atoi,split
|
||||
from status import STATUS_CODES
|
||||
from errors import *
|
||||
|
||||
import BaseHTTPServer
|
||||
|
||||
class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
|
@ -74,21 +74,21 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
def _log(self, message):
|
||||
pass
|
||||
|
||||
def _append(self,s):
|
||||
def _append(self, s):
|
||||
""" write the string to wfile """
|
||||
self.wfile.write(s)
|
||||
|
||||
def send_body(self,DATA,code,msg,desc,ctype='application/octet-stream',headers=None):
|
||||
def send_body(self, DATA, code, msg, desc, ctype='application/octet-stream', headers=None):
|
||||
""" send a body in one part """
|
||||
|
||||
if not headers:
|
||||
headers = {}
|
||||
self.send_response(code,message=msg)
|
||||
self.send_response(code, message=msg)
|
||||
self.send_header("Connection", "keep-alive")
|
||||
self.send_header("Accept-Ranges", "bytes")
|
||||
|
||||
for a,v in headers.items():
|
||||
self.send_header(a,v)
|
||||
for a, v in headers.items():
|
||||
self.send_header(a, v)
|
||||
|
||||
if DATA:
|
||||
self.send_header("Content-Length", str(len(DATA)))
|
||||
|
@ -100,11 +100,11 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
if DATA:
|
||||
self._append(DATA)
|
||||
|
||||
def send_body_chunks(self,DATA,code,msg,desc,ctype='text/xml; encoding="utf-8"'):
|
||||
def send_body_chunks(self, DATA, code, msg, desc, ctype='text/xml; encoding="utf-8"'):
|
||||
""" send a body in chunks """
|
||||
|
||||
self.responses[207]=(msg,desc)
|
||||
self.send_response(code,message=msg)
|
||||
self.responses[207]=(msg, desc)
|
||||
self.send_response(code, message=msg)
|
||||
self.send_header("Content-type", ctype)
|
||||
self.send_header("Connection", "keep-alive")
|
||||
self.send_header("Transfer-Encoding", "chunked")
|
||||
|
@ -128,12 +128,12 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
|
||||
def do_PROPFIND(self):
|
||||
|
||||
dc=self.IFACE_CLASS
|
||||
dc = self.IFACE_CLASS
|
||||
# read the body
|
||||
body=None
|
||||
body = None
|
||||
if self.headers.has_key("Content-Length"):
|
||||
l=self.headers['Content-Length']
|
||||
body=self.rfile.read(atoi(l))
|
||||
l = self.headers['Content-Length']
|
||||
body = self.rfile.read(atoi(l))
|
||||
alt_body = """<?xml version="1.0" encoding="utf-8"?>
|
||||
<propfind xmlns="DAV:"><prop>
|
||||
<getcontentlength xmlns="DAV:"/>
|
||||
|
@ -149,26 +149,26 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
|
||||
# which Depth?
|
||||
if self.headers.has_key('Depth'):
|
||||
d=self.headers['Depth']
|
||||
d = self.headers['Depth']
|
||||
else:
|
||||
d="infinity"
|
||||
d = "infinity"
|
||||
|
||||
uri=self.geturi()
|
||||
pf=PROPFIND(uri,dc,d)
|
||||
uri = self.geturi()
|
||||
pf = PROPFIND(uri, dc, d)
|
||||
|
||||
if body:
|
||||
pf.read_propfind(body)
|
||||
|
||||
try:
|
||||
DATA=pf.createResponse()
|
||||
DATA=DATA+"\n"
|
||||
DATA = pf.createResponse()
|
||||
DATA = DATA+"\n"
|
||||
# print "Data:", DATA
|
||||
except DAV_NotFound,(ec,dd):
|
||||
except DAV_NotFound, (ec, dd):
|
||||
return self.send_notFound(dd, uri)
|
||||
except DAV_Error, (ec,dd):
|
||||
return self.send_error(ec,dd)
|
||||
except DAV_Error, (ec, dd):
|
||||
return self.send_error(ec, dd)
|
||||
|
||||
self.send_body_chunks(DATA,207,"Multi-Status","Multiple responses")
|
||||
self.send_body_chunks(DATA, 207, "Multi-Status", "Multiple responses")
|
||||
|
||||
def geturi(self):
|
||||
buri = self.IFACE_CLASS.baseuri
|
||||
|
@ -179,110 +179,110 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
|
||||
def do_GET(self):
|
||||
"""Serve a GET request."""
|
||||
dc=self.IFACE_CLASS
|
||||
uri=self.geturi()
|
||||
dc = self.IFACE_CLASS
|
||||
uri = self.geturi()
|
||||
|
||||
# get the last modified date
|
||||
try:
|
||||
lm=dc.get_prop(uri,"DAV:","getlastmodified")
|
||||
lm = dc.get_prop(uri, "DAV:", "getlastmodified")
|
||||
except:
|
||||
lm="Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
|
||||
headers={"Last-Modified":lm , "Connection": "keep-alive"}
|
||||
lm = "Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
|
||||
headers = {"Last-Modified":lm , "Connection": "keep-alive"}
|
||||
|
||||
# get the content type
|
||||
try:
|
||||
ct=dc.get_prop(uri,"DAV:","getcontenttype")
|
||||
ct = dc.get_prop(uri, "DAV:", "getcontenttype")
|
||||
except:
|
||||
ct="application/octet-stream"
|
||||
ct = "application/octet-stream"
|
||||
|
||||
# get the data
|
||||
try:
|
||||
data=dc.get_data(uri)
|
||||
except DAV_Error, (ec,dd):
|
||||
data = dc.get_data(uri)
|
||||
except DAV_Error, (ec, dd):
|
||||
self.send_status(ec)
|
||||
return
|
||||
|
||||
# send the data
|
||||
self.send_body(data,200,"OK","OK",ct,headers)
|
||||
self.send_body(data, 200, "OK", "OK", ct, headers)
|
||||
|
||||
def do_HEAD(self):
|
||||
""" Send a HEAD response """
|
||||
dc=self.IFACE_CLASS
|
||||
uri=self.geturi()
|
||||
|
||||
dc = self.IFACE_CLASS
|
||||
uri = self.geturi()
|
||||
|
||||
# get the last modified date
|
||||
try:
|
||||
lm=dc.get_prop(uri,"DAV:","getlastmodified")
|
||||
lm = dc.get_prop(uri, "DAV:", "getlastmodified")
|
||||
except:
|
||||
lm="Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
|
||||
lm = "Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
|
||||
|
||||
headers={"Last-Modified":lm, "Connection": "keep-alive"}
|
||||
headers = {"Last-Modified":lm, "Connection": "keep-alive"}
|
||||
|
||||
# get the content type
|
||||
try:
|
||||
ct=dc.get_prop(uri,"DAV:","getcontenttype")
|
||||
ct = dc.get_prop(uri, "DAV:", "getcontenttype")
|
||||
except:
|
||||
ct="application/octet-stream"
|
||||
ct = "application/octet-stream"
|
||||
|
||||
try:
|
||||
data=dc.get_data(uri)
|
||||
headers["Content-Length"]=str(len(data))
|
||||
data = dc.get_data(uri)
|
||||
headers["Content-Length"] = str(len(data))
|
||||
except DAV_NotFound:
|
||||
self.send_body(None,404,"Not Found","")
|
||||
self.send_body(None, 404, "Not Found", "")
|
||||
return
|
||||
|
||||
self.send_body(None,200,"OK","OK",ct,headers)
|
||||
self.send_body(None, 200, "OK", "OK", ct, headers)
|
||||
|
||||
def do_POST(self):
|
||||
self.send_error(404,"File not found")
|
||||
self.send_error(404, "File not found")
|
||||
|
||||
def do_MKCOL(self):
|
||||
""" create a new collection """
|
||||
|
||||
dc=self.IFACE_CLASS
|
||||
uri=self.geturi()
|
||||
dc = self.IFACE_CLASS
|
||||
uri = self.geturi()
|
||||
try:
|
||||
res = dc.mkcol(uri)
|
||||
if res:
|
||||
self.send_body(None,201,"Created",'')
|
||||
self.send_body(None, 201, "Created", '')
|
||||
else:
|
||||
self.send_body(None,415,"Cannot create",'')
|
||||
self.send_body(None, 415, "Cannot create", '')
|
||||
#self.send_header("Connection", "keep-alive")
|
||||
# Todo: some content, too
|
||||
except DAV_Error, (ec,dd):
|
||||
self.send_body(None,int(ec),dd,dd)
|
||||
except DAV_Error, (ec, dd):
|
||||
self.send_body(None, int(ec), dd, dd)
|
||||
|
||||
def do_DELETE(self):
|
||||
""" delete an resource """
|
||||
dc=self.IFACE_CLASS
|
||||
uri=self.geturi()
|
||||
dl=DELETE(uri,dc)
|
||||
dc = self.IFACE_CLASS
|
||||
uri = self.geturi()
|
||||
dl = DELETE(uri, dc)
|
||||
if dc.is_collection(uri):
|
||||
res=dl.delcol()
|
||||
res = dl.delcol()
|
||||
else:
|
||||
res=dl.delone()
|
||||
res = dl.delone()
|
||||
|
||||
if res:
|
||||
self.send_status(207,body=res)
|
||||
self.send_status(207, body=res)
|
||||
else:
|
||||
self.send_status(204)
|
||||
|
||||
def do_PUT(self):
|
||||
dc=self.IFACE_CLASS
|
||||
dc = self.IFACE_CLASS
|
||||
|
||||
# read the body
|
||||
body=None
|
||||
body = None
|
||||
if self.headers.has_key("Content-Length"):
|
||||
l=self.headers['Content-Length']
|
||||
body=self.rfile.read(atoi(l))
|
||||
uri=self.geturi()
|
||||
l = self.headers['Content-Length']
|
||||
body = self.rfile.read(atoi(l))
|
||||
uri = self.geturi()
|
||||
|
||||
ct=None
|
||||
ct = None
|
||||
if self.headers.has_key("Content-Type"):
|
||||
ct=self.headers['Content-Type']
|
||||
ct = self.headers['Content-Type']
|
||||
try:
|
||||
dc.put(uri,body,ct)
|
||||
except DAV_Error, (ec,dd):
|
||||
dc.put(uri, body, ct)
|
||||
except DAV_Error, (ec, dd):
|
||||
self.send_status(ec)
|
||||
return
|
||||
self.send_status(201)
|
||||
|
@ -291,84 +291,84 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
""" copy one resource to another """
|
||||
try:
|
||||
self.copymove(COPY)
|
||||
except DAV_Error, (ec,dd):
|
||||
except DAV_Error, (ec, dd):
|
||||
self.send_status(ec)
|
||||
|
||||
def do_MOVE(self):
|
||||
""" move one resource to another """
|
||||
try:
|
||||
self.copymove(MOVE)
|
||||
except DAV_Error, (ec,dd):
|
||||
except DAV_Error, (ec, dd):
|
||||
self.send_status(ec)
|
||||
|
||||
def copymove(self,CLASS):
|
||||
def copymove(self, CLASS):
|
||||
""" common method for copying or moving objects """
|
||||
dc=self.IFACE_CLASS
|
||||
dc = self.IFACE_CLASS
|
||||
|
||||
# get the source URI
|
||||
source_uri=self.geturi()
|
||||
source_uri = self.geturi()
|
||||
|
||||
# get the destination URI
|
||||
dest_uri=self.headers['Destination']
|
||||
dest_uri=urllib.unquote(dest_uri)
|
||||
dest_uri = self.headers['Destination']
|
||||
dest_uri = urllib.unquote(dest_uri)
|
||||
|
||||
# Overwrite?
|
||||
overwrite=1
|
||||
result_code=204
|
||||
overwrite = 1
|
||||
result_code = 204
|
||||
if self.headers.has_key("Overwrite"):
|
||||
if self.headers['Overwrite']=="F":
|
||||
overwrite=None
|
||||
result_code=201
|
||||
|
||||
# instanciate ACTION class
|
||||
cp=CLASS(dc,source_uri,dest_uri,overwrite)
|
||||
cp = CLASS(dc, source_uri, dest_uri, overwrite)
|
||||
|
||||
# Depth?
|
||||
d="infinity"
|
||||
d = "infinity"
|
||||
if self.headers.has_key("Depth"):
|
||||
d=self.headers['Depth']
|
||||
d = self.headers['Depth']
|
||||
|
||||
if d!="0" and d!="infinity":
|
||||
self.send_status(400)
|
||||
return
|
||||
|
||||
if d=="0":
|
||||
res=cp.single_action()
|
||||
res = cp.single_action()
|
||||
self.send_status(res)
|
||||
return
|
||||
|
||||
# now it only can be "infinity" but we nevertheless check for a collection
|
||||
if dc.is_collection(source_uri):
|
||||
try:
|
||||
res=cp.tree_action()
|
||||
except DAV_Error, (ec,dd):
|
||||
res = cp.tree_action()
|
||||
except DAV_Error, (ec, dd):
|
||||
self.send_status(ec)
|
||||
return
|
||||
else:
|
||||
try:
|
||||
res=cp.single_action()
|
||||
except DAV_Error, (ec,dd):
|
||||
res = cp.single_action()
|
||||
except DAV_Error, (ec, dd):
|
||||
self.send_status(ec)
|
||||
return
|
||||
|
||||
if res:
|
||||
self.send_body_chunks(res,207,STATUS_CODES[207],STATUS_CODES[207],
|
||||
self.send_body_chunks(res, 207, STATUS_CODES[207], STATUS_CODES[207],
|
||||
ctype='text/xml; charset="utf-8"')
|
||||
else:
|
||||
self.send_status(result_code)
|
||||
|
||||
def get_userinfo(self,user,pw):
|
||||
def get_userinfo(self, user, pw):
|
||||
""" Dummy method which lets all users in """
|
||||
|
||||
return 1
|
||||
|
||||
def send_status(self,code=200,mediatype='text/xml; charset="utf-8"', \
|
||||
msg=None,body=None):
|
||||
def send_status(self, code=200, mediatype='text/xml; charset="utf-8"', \
|
||||
msg=None, body=None):
|
||||
|
||||
if not msg: msg=STATUS_CODES[code]
|
||||
self.send_body(body,code,STATUS_CODES[code],msg,mediatype)
|
||||
if not msg: msg = STATUS_CODES[code]
|
||||
self.send_body(body, code, STATUS_CODES[code], msg, mediatype)
|
||||
|
||||
def send_notFound(self,descr,uri):
|
||||
def send_notFound(self, descr, uri):
|
||||
body = """<?xml version="1.0" encoding="utf-8" ?>
|
||||
<D:response xmlns:D="DAV:">
|
||||
<D:href>%s</D:href>
|
||||
|
@ -376,4 +376,6 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
<D:responsedescription>%s</D:responsedescription>
|
||||
</D:response>
|
||||
"""
|
||||
return self.send_status(404,descr, body=body % (uri,descr))
|
||||
return self.send_status(404, descr, body=body % (uri, descr))
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -14,8 +14,8 @@ import urlparse
|
|||
from utils import create_treelist, is_prefix
|
||||
from errors import *
|
||||
|
||||
def deltree(dc,uri,exclude={}):
|
||||
""" delete a tree of resources
|
||||
def deltree(dc, uri, exclude={}):
|
||||
""" delete a tree of resources
|
||||
|
||||
dc -- dataclass to use
|
||||
uri -- root uri to delete
|
||||
|
@ -30,43 +30,43 @@ def deltree(dc,uri,exclude={}):
|
|||
|
||||
"""
|
||||
|
||||
tlist=create_treelist(dc,uri)
|
||||
result={}
|
||||
tlist = create_treelist(dc,uri)
|
||||
result = {}
|
||||
|
||||
for i in range(len(tlist),0,-1):
|
||||
problem_uris=result.keys()
|
||||
element=tlist[i-1]
|
||||
|
||||
problem_uris = result.keys()
|
||||
element = tlist[i-1]
|
||||
|
||||
# test here, if an element is a prefix of an uri which
|
||||
# generated an error before.
|
||||
# note that we walk here from childs to parents, thus
|
||||
# we cannot delete a parent if a child made a problem.
|
||||
# (see example in 8.6.2.1)
|
||||
ok=1
|
||||
ok = 1
|
||||
for p in problem_uris:
|
||||
if is_prefix(element,p):
|
||||
ok=None
|
||||
ok = None
|
||||
break
|
||||
|
||||
if not ok: continue
|
||||
|
||||
|
||||
if not ok: continue
|
||||
|
||||
# here we test for the exclude list which is the other way round!
|
||||
for p in exclude.keys():
|
||||
if is_prefix(p,element):
|
||||
ok=None
|
||||
ok = None
|
||||
break
|
||||
|
||||
if not ok: continue
|
||||
|
||||
|
||||
if not ok: continue
|
||||
|
||||
# now delete stuff
|
||||
try:
|
||||
delone(dc,element)
|
||||
except DAV_Error, (ec,dd):
|
||||
result[element]=ec
|
||||
|
||||
except DAV_Error, (ec,dd):
|
||||
result[element] = ec
|
||||
|
||||
return result
|
||||
|
||||
def delone(dc,uri):
|
||||
def delone(dc, uri):
|
||||
""" delete a single object """
|
||||
if dc.is_collection(uri):
|
||||
dc.rmcol(uri) # should be empty
|
||||
|
@ -79,12 +79,12 @@ def delone(dc,uri):
|
|||
|
||||
# helper function
|
||||
|
||||
def copy(dc,src,dst):
|
||||
""" only copy the element
|
||||
def copy(dc, src, dst):
|
||||
""" only copy the element
|
||||
|
||||
This is just a helper method factored out from copy and
|
||||
copytree. It will not handle the overwrite or depth header.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
# destination should have been deleted before
|
||||
|
@ -101,28 +101,28 @@ def copy(dc,src,dst):
|
|||
|
||||
# the main functions
|
||||
|
||||
def copyone(dc,src,dst,overwrite=None):
|
||||
def copyone(dc, src, dst, overwrite=None):
|
||||
""" copy one resource to a new destination """
|
||||
|
||||
if overwrite and dc.exists(dst):
|
||||
delres=deltree(dc,dst)
|
||||
delres = deltree(dc,dst)
|
||||
else:
|
||||
delres={}
|
||||
delres = {}
|
||||
|
||||
# if we cannot delete everything, then do not copy!
|
||||
if delres: return delres
|
||||
|
||||
|
||||
try:
|
||||
copy(dc,src,dst) # pass thru exceptions
|
||||
except DAV_Error, (ec,dd):
|
||||
return ec
|
||||
|
||||
def copytree(dc,src,dst,overwrite=None):
|
||||
def copytree(dc, src, dst, overwrite=None):
|
||||
""" copy a tree of resources to another location
|
||||
|
||||
dc -- dataclass to use
|
||||
src -- src uri from where to copy
|
||||
dst -- dst uri
|
||||
dst -- dst uri
|
||||
overwrite -- if 1 then delete dst uri before
|
||||
|
||||
returns dict of uri:error_code tuples from which
|
||||
|
@ -133,59 +133,59 @@ def copytree(dc,src,dst,overwrite=None):
|
|||
|
||||
# first delete the destination resource
|
||||
if overwrite and dc.exists(dst):
|
||||
delres=deltree(dc,dst)
|
||||
delres = deltree(dc,dst)
|
||||
else:
|
||||
delres={}
|
||||
delres = {}
|
||||
|
||||
# if we cannot delete everything, then do not copy!
|
||||
if delres: return delres
|
||||
|
||||
# get the tree we have to copy
|
||||
tlist=create_treelist(dc,src)
|
||||
result={}
|
||||
tlist = create_treelist(dc,src)
|
||||
result = {}
|
||||
|
||||
# prepare destination URIs (get the prefix)
|
||||
dpath=urlparse.urlparse(dst)[2]
|
||||
dpath = urlparse.urlparse(dst)[2]
|
||||
|
||||
for element in tlist:
|
||||
problem_uris=result.keys()
|
||||
|
||||
problem_uris = result.keys()
|
||||
|
||||
# now URIs get longer and longer thus we have
|
||||
# to test if we had a parent URI which we were not
|
||||
# able to copy in problem_uris which is the prefix
|
||||
# of the actual element. If it is, then we cannot
|
||||
# copy this as well but do not generate another error.
|
||||
ok=1
|
||||
ok = 1
|
||||
for p in problem_uris:
|
||||
if is_prefix(p,element):
|
||||
ok=None
|
||||
ok = None
|
||||
break
|
||||
|
||||
if not ok: continue
|
||||
|
||||
if not ok: continue
|
||||
|
||||
# now create the destination URI which corresponds to
|
||||
# the actual source URI. -> actual_dst
|
||||
# ("subtract" the base src from the URI and prepend the
|
||||
# dst prefix to it.)
|
||||
esrc=replace(element,src,"")
|
||||
actual_dst=dpath+esrc
|
||||
esrc = replace(element,src,"")
|
||||
actual_dst = dpath+esrc
|
||||
|
||||
# now copy stuff
|
||||
try:
|
||||
copy(dc,element,actual_dst)
|
||||
except DAV_Error, (ec,dd):
|
||||
result[element]=ec
|
||||
except DAV_Error, (ec,dd):
|
||||
result[element] = ec
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
###
|
||||
### MOVE
|
||||
###
|
||||
|
||||
|
||||
def moveone(dc,src,dst,overwrite=None):
|
||||
def moveone(dc, src, dst, overwrite=None):
|
||||
""" move a single resource
|
||||
|
||||
This is done by first copying it and then deleting
|
||||
|
@ -197,8 +197,8 @@ def moveone(dc,src,dst,overwrite=None):
|
|||
|
||||
# then delete it
|
||||
dc.rm(src)
|
||||
|
||||
def movetree(dc,src,dst,overwrite=None):
|
||||
|
||||
def movetree(dc, src, dst, overwrite=None):
|
||||
""" move a collection
|
||||
|
||||
This is done by first copying it and then deleting
|
||||
|
@ -209,10 +209,11 @@ def movetree(dc,src,dst,overwrite=None):
|
|||
"""
|
||||
|
||||
# first copy it
|
||||
res=copytree(dc,src,dst,overwrite)
|
||||
res = copytree(dc,src,dst,overwrite)
|
||||
|
||||
# then delete it
|
||||
res=deltree(dc,src,exclude=res)
|
||||
res = deltree(dc,src,exclude=res)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -47,11 +47,11 @@ class COPY:
|
|||
"""
|
||||
|
||||
|
||||
def __init__(self,dataclass,src_uri,dst_uri,overwrite):
|
||||
self.__dataclass=dataclass
|
||||
self.__src=src_uri
|
||||
self.__dst=dst_uri
|
||||
self.__overwrite=overwrite
|
||||
def __init__(self, dataclass, src_uri, dst_uri, overwrite):
|
||||
self.__dataclass = dataclass
|
||||
self.__src = src_uri
|
||||
self.__dst = dst_uri
|
||||
self.__overwrite = overwrite
|
||||
|
||||
|
||||
def single_action(self):
|
||||
|
@ -62,16 +62,16 @@ class COPY:
|
|||
|
||||
"""
|
||||
|
||||
dc=self.__dataclass
|
||||
base=self.__src
|
||||
dc = self.__dataclass
|
||||
base = self.__src
|
||||
|
||||
### some basic tests
|
||||
# test if dest exists and overwrite is false
|
||||
if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
|
||||
# test if src and dst are the same
|
||||
# (we assume that both uris are on the same server!)
|
||||
ps=urlparse.urlparse(self.__src)[2]
|
||||
pd=urlparse.urlparse(self.__dst)[2]
|
||||
ps = urlparse.urlparse(self.__src)[2]
|
||||
pd = urlparse.urlparse(self.__dst)[2]
|
||||
if ps==pd: raise DAV_Error, 403
|
||||
|
||||
return dc.copyone(self.__src,self.__dst,self.__overwrite)
|
||||
|
@ -84,20 +84,20 @@ class COPY:
|
|||
Here we return a multistatus xml element.
|
||||
|
||||
"""
|
||||
dc=self.__dataclass
|
||||
base=self.__src
|
||||
dc = self.__dataclass
|
||||
base = self.__src
|
||||
|
||||
### some basic tests
|
||||
# test if dest exists and overwrite is false
|
||||
if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
|
||||
# test if src and dst are the same
|
||||
# (we assume that both uris are on the same server!)
|
||||
ps=urlparse.urlparse(self.__src)[2]
|
||||
pd=urlparse.urlparse(self.__dst)[2]
|
||||
ps = urlparse.urlparse(self.__src)[2]
|
||||
pd = urlparse.urlparse(self.__dst)[2]
|
||||
if ps==pd: raise DAV_Error, 403
|
||||
|
||||
|
||||
result=dc.copytree(self.__src,self.__dst,self.__overwrite)
|
||||
|
||||
|
||||
result = dc.copytree(self.__src,self.__dst,self.__overwrite)
|
||||
#result=copytree(dc,self.__src,self.__dst,self.__overwrite)
|
||||
|
||||
if not result: return None
|
||||
|
@ -109,25 +109,26 @@ class COPY:
|
|||
###
|
||||
|
||||
doc = Document(None)
|
||||
ms=doc.createElement("D:multistatus")
|
||||
ms = doc.createElement("D:multistatus")
|
||||
ms.setAttribute("xmlns:D","DAV:")
|
||||
doc.appendChild(ms)
|
||||
|
||||
for el,ec in result.items():
|
||||
re=doc.createElement("D:response")
|
||||
hr=doc.createElement("D:href")
|
||||
st=doc.createElement("D:status")
|
||||
huri=doc.createTextNode(quote_uri(el))
|
||||
t=doc.createTextNode(gen_estring(ec))
|
||||
re = doc.createElement("D:response")
|
||||
hr = doc.createElement("D:href")
|
||||
st = doc.createElement("D:status")
|
||||
huri = doc.createTextNode(quote_uri(el))
|
||||
t = doc.createTextNode(gen_estring(ec))
|
||||
st.appendChild(t)
|
||||
hr.appendChild(huri)
|
||||
re.appendChild(hr)
|
||||
re.appendChild(st)
|
||||
ms.appendChild(re)
|
||||
|
||||
sfile=StringIO()
|
||||
ext.PrettyPrint(doc,stream=sfile)
|
||||
s=sfile.getvalue()
|
||||
|
||||
sfile = StringIO()
|
||||
ext.PrettyPrint(doc,stream = sfile)
|
||||
s = sfile.getvalue()
|
||||
sfile.close()
|
||||
return s
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -39,19 +39,19 @@ class MOVE:
|
|||
""" move resources and eventually create multistatus responses
|
||||
|
||||
This module implements the MOVE class which is responsible for
|
||||
moving resources.
|
||||
moving resources.
|
||||
|
||||
MOVE is implemented by a COPY followed by a DELETE of the old
|
||||
resource.
|
||||
resource.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self,dataclass,src_uri,dst_uri,overwrite):
|
||||
self.__dataclass=dataclass
|
||||
self.__src=src_uri
|
||||
self.__dst=dst_uri
|
||||
self.__overwrite=overwrite
|
||||
def __init__(self, dataclass, src_uri, dst_uri, overwrite):
|
||||
self.__dataclass = dataclass
|
||||
self.__src = src_uri
|
||||
self.__dst = dst_uri
|
||||
self.__overwrite = overwrite
|
||||
|
||||
|
||||
def single_action(self):
|
||||
|
@ -62,16 +62,16 @@ class MOVE:
|
|||
|
||||
"""
|
||||
|
||||
dc=self.__dataclass
|
||||
base=self.__src
|
||||
dc = self.__dataclass
|
||||
base = self.__src
|
||||
|
||||
### some basic tests
|
||||
# test if dest exists and overwrite is false
|
||||
if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
|
||||
# test if src and dst are the same
|
||||
# (we assume that both uris are on the same server!)
|
||||
ps=urlparse.urlparse(self.__src)[2]
|
||||
pd=urlparse.urlparse(self.__dst)[2]
|
||||
ps = urlparse.urlparse(self.__src)[2]
|
||||
pd = urlparse.urlparse(self.__dst)[2]
|
||||
if ps==pd: raise DAV_Error, 403
|
||||
|
||||
return dc.moveone(self.__src,self.__dst,self.__overwrite)
|
||||
|
@ -82,21 +82,22 @@ class MOVE:
|
|||
Here we return a multistatus xml element.
|
||||
|
||||
"""
|
||||
dc=self.__dataclass
|
||||
base=self.__src
|
||||
dc = self.__dataclass
|
||||
base = self.__src
|
||||
|
||||
### some basic tests
|
||||
# test if dest exists and overwrite is false
|
||||
if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
|
||||
# test if src and dst are the same
|
||||
# (we assume that both uris are on the same server!)
|
||||
ps=urlparse.urlparse(self.__src)[2]
|
||||
pd=urlparse.urlparse(self.__dst)[2]
|
||||
ps = urlparse.urlparse(self.__src)[2]
|
||||
pd = urlparse.urlparse(self.__dst)[2]
|
||||
if ps==pd: raise DAV_Error, 403
|
||||
|
||||
result=dc.movetree(self.__src,self.__dst,self.__overwrite)
|
||||
|
||||
result = dc.movetree(self.__src,self.__dst,self.__overwrite)
|
||||
if not result: return None
|
||||
|
||||
# create the multistatus XML element
|
||||
return make_xmlresponse(result)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -32,15 +32,15 @@ from davcmd import deltree
|
|||
|
||||
class DELETE:
|
||||
|
||||
def __init__(self,uri,dataclass):
|
||||
self.__dataclass=dataclass
|
||||
self.__uri=uri
|
||||
def __init__(self, uri, dataclass):
|
||||
self.__dataclass = dataclass
|
||||
self.__uri = uri
|
||||
|
||||
def delcol(self):
|
||||
""" delete a collection """
|
||||
|
||||
dc=self.__dataclass
|
||||
result=dc.deltree(self.__uri)
|
||||
dc = self.__dataclass
|
||||
result = dc.deltree(self.__uri)
|
||||
|
||||
if not len(result.items()):
|
||||
return None # everything ok
|
||||
|
@ -51,9 +51,9 @@ class DELETE:
|
|||
def delone(self):
|
||||
""" delete a resource """
|
||||
|
||||
dc=self.__dataclass
|
||||
result=dc.delone(self.__uri)
|
||||
|
||||
dc = self.__dataclass
|
||||
result = dc.delone(self.__uri)
|
||||
|
||||
if not result: return None
|
||||
if not len(result.items()):
|
||||
return None # everything ok
|
||||
|
@ -61,3 +61,4 @@ class DELETE:
|
|||
# create the result element
|
||||
return make_xmlresponse(result)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -12,15 +12,15 @@ class DAV_Error(Exception):
|
|||
2. the error result element, e.g. a <multistatus> element
|
||||
"""
|
||||
|
||||
def __init__(self,*args):
|
||||
def __init__(self, *args):
|
||||
if len(args)==1:
|
||||
self.args=(args[0],"")
|
||||
self.args = (args[0],"")
|
||||
else:
|
||||
self.args=args
|
||||
|
||||
self.args = args
|
||||
|
||||
class DAV_Secret(DAV_Error):
|
||||
""" the user is not allowed to know anything about it
|
||||
|
||||
|
||||
returning this for a property value means to exclude it
|
||||
from the response xml element.
|
||||
"""
|
||||
|
@ -31,10 +31,10 @@ class DAV_Secret(DAV_Error):
|
|||
|
||||
class DAV_NotFound(DAV_Error):
|
||||
""" a requested property was not found for a resource """
|
||||
|
||||
def __init__(self,*args):
|
||||
|
||||
def __init__(self, *args):
|
||||
if len(args):
|
||||
if isinstance(args[0],list):
|
||||
if isinstance(args[0], list):
|
||||
stre = "Path %s not found!"%('/'.join(args[0]))
|
||||
else:
|
||||
stre = args[0]
|
||||
|
@ -46,11 +46,12 @@ class DAV_NotFound(DAV_Error):
|
|||
|
||||
class DAV_Forbidden(DAV_Error):
|
||||
""" a method on a resource is not allowed """
|
||||
|
||||
def __init__(self,*args):
|
||||
|
||||
def __init__(self, *args):
|
||||
if len(args):
|
||||
DAV_Error.__init__(self,403,args[0])
|
||||
else:
|
||||
DAV_Error.__init__(self,403)
|
||||
pass
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -18,16 +18,16 @@ class dav_interface:
|
|||
### defined properties (modify this but let the DAV stuff there!)
|
||||
### the format is namespace: [list of properties]
|
||||
|
||||
PROPS={"DAV:" : ('creationdate',
|
||||
'displayname',
|
||||
'getcontentlanguage',
|
||||
'getcontentlength',
|
||||
'getcontenttype',
|
||||
'getetag',
|
||||
'getlastmodified',
|
||||
'lockdiscovery',
|
||||
'resourcetype',
|
||||
'source',
|
||||
PROPS={"DAV:" : ('creationdate',
|
||||
'displayname',
|
||||
'getcontentlanguage',
|
||||
'getcontentlength',
|
||||
'getcontenttype',
|
||||
'getetag',
|
||||
'getlastmodified',
|
||||
'lockdiscovery',
|
||||
'resourcetype',
|
||||
'source',
|
||||
'supportedlock'),
|
||||
"NS2" : ("p1","p2")
|
||||
}
|
||||
|
@ -36,28 +36,28 @@ class dav_interface:
|
|||
# the first item is the namespace URI and the second one
|
||||
# the method prefix
|
||||
# e.g. for DAV:getcontenttype we call dav_getcontenttype()
|
||||
M_NS={"DAV:" : "_get_dav",
|
||||
M_NS = {"DAV:" : "_get_dav",
|
||||
"NS2" : "ns2" }
|
||||
|
||||
def get_propnames(self,uri):
|
||||
""" return the property names allowed for the given URI
|
||||
def get_propnames(self, uri):
|
||||
""" return the property names allowed for the given URI
|
||||
|
||||
In this method we simply return the above defined properties
|
||||
assuming that they are valid for any resource.
|
||||
assuming that they are valid for any resource.
|
||||
You can override this in order to return a different set
|
||||
of property names for each resource.
|
||||
|
||||
|
||||
"""
|
||||
return self.PROPS
|
||||
|
||||
def get_prop2(self,uri,ns,pname):
|
||||
""" return the value of a property
|
||||
def get_prop2(self, uri, ns, pname):
|
||||
""" return the value of a property
|
||||
"""
|
||||
if lower(ns)=="dav:": return self.get_dav(uri,pname)
|
||||
|
||||
raise DAV_NotFound
|
||||
|
||||
def get_prop(self,uri,ns,propname):
|
||||
def get_prop(self, uri, ns, propname):
|
||||
""" return the value of a given property
|
||||
|
||||
uri -- uri of the object to get the property of
|
||||
|
@ -65,17 +65,17 @@ class dav_interface:
|
|||
pname -- name of the property
|
||||
"""
|
||||
if self.M_NS.has_key(ns):
|
||||
prefix=self.M_NS[ns]
|
||||
prefix = self.M_NS[ns]
|
||||
else:
|
||||
print "No namespace:",ns, "( for prop:", propname,")"
|
||||
raise DAV_NotFound
|
||||
mname=prefix+"_"+propname
|
||||
mname = prefix+"_"+propname
|
||||
if not hasattr(self,mname):
|
||||
raise DAV_NotFound
|
||||
|
||||
try:
|
||||
m=getattr(self,mname)
|
||||
r=m(uri)
|
||||
m = getattr(self,mname)
|
||||
r = m(uri)
|
||||
return r
|
||||
except AttributeError, e:
|
||||
print 'Property %s not supported' % propname
|
||||
|
@ -86,16 +86,16 @@ class dav_interface:
|
|||
### DATA methods (for GET and PUT)
|
||||
###
|
||||
|
||||
def get_data(self,uri):
|
||||
""" return the content of an object
|
||||
def get_data(self, uri):
|
||||
""" return the content of an object
|
||||
|
||||
return data or raise an exception
|
||||
|
||||
|
||||
"""
|
||||
raise DAV_NotFound
|
||||
|
||||
def put(self,uri,data):
|
||||
""" write an object to the repository
|
||||
def put(self, uri, data):
|
||||
""" write an object to the repository
|
||||
|
||||
return a result code or raise an exception
|
||||
"""
|
||||
|
@ -106,17 +106,17 @@ class dav_interface:
|
|||
### Methods for DAV properties
|
||||
###
|
||||
|
||||
def _get_dav_creationdate(self,uri):
|
||||
def _get_dav_creationdate(self, uri):
|
||||
""" return the creationdate of a resource """
|
||||
d=self.get_creationdate(uri)
|
||||
d = self.get_creationdate(uri)
|
||||
# format it
|
||||
if isinstance(d, int) or isinstance(d, float):
|
||||
d = time.localtimetime(d)
|
||||
return time.strftime("%Y-%m-%dT%H:%M:%S%Z",d)
|
||||
|
||||
def _get_dav_getlastmodified(self,uri):
|
||||
def _get_dav_getlastmodified(self, uri):
|
||||
""" return the last modified date of a resource """
|
||||
d=self.get_lastmodified(uri)
|
||||
d = self.get_lastmodified(uri)
|
||||
if isinstance(d, int) or isinstance(d, float):
|
||||
d = time.localtime(d)
|
||||
# format it
|
||||
|
@ -127,37 +127,37 @@ class dav_interface:
|
|||
### OVERRIDE THESE!
|
||||
###
|
||||
|
||||
def get_creationdate(self,uri):
|
||||
def get_creationdate(self, uri):
|
||||
""" return the creationdate of the resource """
|
||||
return time.time()
|
||||
|
||||
def get_lastmodified(self,uri):
|
||||
def get_lastmodified(self, uri):
|
||||
""" return the last modification date of the resource """
|
||||
return time.time()
|
||||
|
||||
|
||||
|
||||
###
|
||||
### COPY MOVE DELETE
|
||||
###
|
||||
|
||||
### methods for deleting a resource
|
||||
|
||||
def rmcol(self,uri):
|
||||
""" delete a collection
|
||||
def rmcol(self, uri):
|
||||
""" delete a collection
|
||||
|
||||
This should not delete any children! This is automatically done
|
||||
before by the DELETE class in DAV/delete.py
|
||||
|
||||
return a success code or raise an exception
|
||||
|
||||
|
||||
"""
|
||||
raise DAV_NotFound
|
||||
|
||||
def rm(self,uri):
|
||||
""" delete a single resource
|
||||
def rm(self, uri):
|
||||
""" delete a single resource
|
||||
|
||||
return a success code or raise an exception
|
||||
|
||||
|
||||
"""
|
||||
raise DAV_NotFound
|
||||
|
||||
|
@ -182,7 +182,7 @@ class dav_interface:
|
|||
1. to handle the action directly (e.g. cp or mv on filesystems)
|
||||
2. to let it handle via the copy/move methods in davcmd.
|
||||
|
||||
ad 1) The first approach can be used when we know that no error can
|
||||
ad 1) The first approach can be used when we know that no error can
|
||||
happen inside a tree or when the action can exactly tell which
|
||||
element made which error. We have to collect these and return
|
||||
it in a dict of the form {uri: error_code, ...}
|
||||
|
@ -210,28 +210,28 @@ class dav_interface:
|
|||
|
||||
### MOVE handlers
|
||||
|
||||
def moveone(self,src,dst,overwrite):
|
||||
def moveone(self, src, dst, overwrite):
|
||||
""" move one resource with Depth=0 """
|
||||
return moveone(self,src,dst,overwrite)
|
||||
return moveone(self, src, dst, overwrite)
|
||||
|
||||
def movetree(self,src,dst,overwrite):
|
||||
def movetree(self, src, dst, overwrite):
|
||||
""" move a collection with Depth=infinity """
|
||||
return movetree(self,src,dst,overwrite)
|
||||
return movetree(self, src, dst, overwrite)
|
||||
|
||||
### COPY handlers
|
||||
|
||||
def copyone(self,src,dst,overwrite):
|
||||
def copyone(self, src, dst, overwrite):
|
||||
""" copy one resource with Depth=0 """
|
||||
return copyone(self,src,dst,overwrite)
|
||||
return copyone(self, src, dst, overwrite)
|
||||
|
||||
def copytree(self,src,dst,overwrite):
|
||||
def copytree(self, src, dst, overwrite):
|
||||
""" copy a collection with Depth=infinity """
|
||||
return copytree(self,src,dst,overwrite)
|
||||
return copytree(self, src, dst, overwrite)
|
||||
|
||||
|
||||
### low level copy methods (you only need these for method 2)
|
||||
def copy(self,src,dst):
|
||||
""" copy a resource with depth==0
|
||||
def copy(self, src, dst):
|
||||
""" copy a resource with depth==0
|
||||
|
||||
You don't need to bother about overwrite or not.
|
||||
This has been done already.
|
||||
|
@ -241,8 +241,8 @@ class dav_interface:
|
|||
return 201
|
||||
|
||||
|
||||
def copycol(self,src,dst):
|
||||
""" copy a resource with depth==infinity
|
||||
def copycol(self, src, dst):
|
||||
""" copy a resource with depth==infinity
|
||||
|
||||
You don't need to bother about overwrite or not.
|
||||
This has been done already.
|
||||
|
@ -253,11 +253,12 @@ class dav_interface:
|
|||
|
||||
### some utility functions you need to implement
|
||||
|
||||
def exists(self,uri):
|
||||
def exists(self, uri):
|
||||
""" return 1 or None depending on if a resource exists """
|
||||
return None # no
|
||||
|
||||
def is_collection(self,uri):
|
||||
def is_collection(self, uri):
|
||||
""" return 1 or None depending on if a resource is a collection """
|
||||
return None # no
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -18,8 +18,8 @@
|
|||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
|
||||
from xml.dom import ext
|
||||
from xml.dom.Document import Document
|
||||
|
@ -45,9 +45,9 @@ class PROPFIND:
|
|||
|
||||
It will set the following instance vars:
|
||||
|
||||
request_class : ALLPROP | PROPNAME | PROP
|
||||
proplist : list of properties
|
||||
nsmap : map of namespaces
|
||||
request_class: ALLPROP | PROPNAME | PROP
|
||||
proplist: list of properties
|
||||
nsmap: map of namespaces
|
||||
|
||||
The list of properties will contain tuples of the form
|
||||
(element name, ns_prefix, ns_uri)
|
||||
|
@ -55,21 +55,20 @@ class PROPFIND:
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, uri, dataclass, depth):
|
||||
self.request_type = None
|
||||
self.nsmap = {}
|
||||
self.proplist = {}
|
||||
self.default_ns = None
|
||||
self.__dataclass = dataclass
|
||||
self.__depth = str(depth)
|
||||
self.__uri = uri
|
||||
self.use_full_urls = True
|
||||
self.__has_body = None # did we parse a body?
|
||||
|
||||
def __init__(self,uri,dataclass,depth):
|
||||
self.request_type=None
|
||||
self.nsmap={}
|
||||
self.proplist={}
|
||||
self.default_ns=None
|
||||
self.__dataclass=dataclass
|
||||
self.__depth=str(depth)
|
||||
self.__uri=uri
|
||||
self.use_full_urls=True
|
||||
self.__has_body=None # did we parse a body?
|
||||
def read_propfind(self, xml_doc):
|
||||
self.request_type,self.proplist,self.namespaces = utils.parse_propfind(xml_doc)
|
||||
|
||||
def read_propfind(self,xml_doc):
|
||||
self.request_type,self.proplist,self.namespaces=utils.parse_propfind(xml_doc)
|
||||
|
||||
# a violation of the expected logic: client (korganizer) will ask for DAV:resourcetype
|
||||
# but we also have to return the http://groupdav.org/:resourcetype property!
|
||||
if self.proplist.has_key('DAV:') and 'resourcetype' in self.proplist['DAV:']:
|
||||
|
@ -91,7 +90,7 @@ class PROPFIND:
|
|||
|
||||
If we get an ALLPROP we first get the list of properties and then
|
||||
we do the same as with a PROP method.
|
||||
|
||||
|
||||
If the uri doesn't exist, return an xml response with a 404 status
|
||||
|
||||
"""
|
||||
|
@ -114,41 +113,41 @@ class PROPFIND:
|
|||
def create_propname(self):
|
||||
""" create a multistatus response for the prop names """
|
||||
|
||||
dc=self.__dataclass
|
||||
dc = self.__dataclass
|
||||
# create the document generator
|
||||
doc = Document(None)
|
||||
ms=doc.createElement("D:multistatus")
|
||||
ms = doc.createElement("D:multistatus")
|
||||
ms.setAttribute("xmlns:D","DAV:")
|
||||
doc.appendChild(ms)
|
||||
|
||||
if self.__depth=="0":
|
||||
pnames=dc.get_propnames(self.__uri)
|
||||
re=self.mk_propname_response(self.__uri,pnames,doc)
|
||||
pnames = dc.get_propnames(self.__uri)
|
||||
re = self.mk_propname_response(self.__uri,pnames,doc)
|
||||
ms.appendChild(re)
|
||||
|
||||
elif self.__depth=="1":
|
||||
pnames=dc.get_propnames(self.__uri)
|
||||
re=self.mk_propname_response(self.__uri,pnames,doc)
|
||||
pnames = dc.get_propnames(self.__uri)
|
||||
re = self.mk_propname_response(self.__uri,pnames,doc)
|
||||
ms.appendChild(re)
|
||||
|
||||
for newuri in dc.get_childs(self.__uri):
|
||||
pnames=dc.get_propnames(newuri)
|
||||
re=self.mk_propname_response(newuri,pnames,doc)
|
||||
pnames = dc.get_propnames(newuri)
|
||||
re = self.mk_propname_response(newuri,pnames,doc)
|
||||
ms.appendChild(re)
|
||||
# *** depth=="infinity"
|
||||
|
||||
sfile=StringIO()
|
||||
ext.PrettyPrint(doc,stream=sfile)
|
||||
s=sfile.getvalue()
|
||||
sfile = StringIO()
|
||||
ext.PrettyPrint(doc,stream = sfile)
|
||||
s = sfile.getvalue()
|
||||
sfile.close()
|
||||
return s
|
||||
|
||||
def create_allprop(self):
|
||||
""" return a list of all properties """
|
||||
self.proplist={}
|
||||
self.namespaces=[]
|
||||
self.proplist = {}
|
||||
self.namespaces = []
|
||||
for ns,plist in self.__dataclass.get_propnames(self.__uri).items():
|
||||
self.proplist[ns]=plist
|
||||
self.proplist[ns] = plist
|
||||
self.namespaces.append(ns)
|
||||
|
||||
return self.create_prop()
|
||||
|
@ -178,32 +177,32 @@ class PROPFIND:
|
|||
|
||||
# create the document generator
|
||||
doc = Document(None)
|
||||
ms=doc.createElement("D:multistatus")
|
||||
ms = doc.createElement("D:multistatus")
|
||||
ms.setAttribute("xmlns:D","DAV:")
|
||||
doc.appendChild(ms)
|
||||
|
||||
if self.__depth=="0":
|
||||
gp,bp=self.get_propvalues(self.__uri)
|
||||
res=self.mk_prop_response(self.__uri,gp,bp,doc)
|
||||
gp,bp = self.get_propvalues(self.__uri)
|
||||
res = self.mk_prop_response(self.__uri,gp,bp,doc)
|
||||
ms.appendChild(res)
|
||||
|
||||
elif self.__depth=="1":
|
||||
gp,bp=self.get_propvalues(self.__uri)
|
||||
res=self.mk_prop_response(self.__uri,gp,bp,doc)
|
||||
gp,bp = self.get_propvalues(self.__uri)
|
||||
res = self.mk_prop_response(self.__uri,gp,bp,doc)
|
||||
ms.appendChild(res)
|
||||
|
||||
try:
|
||||
for newuri in self.__dataclass.get_childs(self.__uri):
|
||||
gp,bp=self.get_propvalues(newuri)
|
||||
res=self.mk_prop_response(newuri,gp,bp,doc)
|
||||
gp,bp = self.get_propvalues(newuri)
|
||||
res = self.mk_prop_response(newuri,gp,bp,doc)
|
||||
ms.appendChild(res)
|
||||
except DAV_NotFound:
|
||||
# If no children, never mind.
|
||||
pass
|
||||
|
||||
sfile=StringIO()
|
||||
ext.PrettyPrint(doc,stream=sfile)
|
||||
s=sfile.getvalue()
|
||||
sfile = StringIO()
|
||||
ext.PrettyPrint(doc,stream = sfile)
|
||||
s = sfile.getvalue()
|
||||
sfile.close()
|
||||
return s
|
||||
|
||||
|
@ -215,32 +214,32 @@ class PROPFIND:
|
|||
propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...}
|
||||
|
||||
"""
|
||||
re=doc.createElement("D:response")
|
||||
re = doc.createElement("D:response")
|
||||
|
||||
# write href information
|
||||
href=doc.createElement("D:href")
|
||||
href = doc.createElement("D:href")
|
||||
if self.use_full_urls:
|
||||
huri=doc.createTextNode(uri)
|
||||
huri = doc.createTextNode(uri)
|
||||
else:
|
||||
uparts=urlparse.urlparse(uri)
|
||||
fileloc=uparts[2]
|
||||
huri=doc.createTextNode(urllib.quote(fileloc.encode('utf8')))
|
||||
uparts = urlparse.urlparse(uri)
|
||||
fileloc = uparts[2]
|
||||
huri = doc.createTextNode(urllib.quote(fileloc.encode('utf8')))
|
||||
href.appendChild(huri)
|
||||
re.appendChild(href)
|
||||
|
||||
ps=doc.createElement("D:propstat")
|
||||
nsnum=0
|
||||
ps = doc.createElement("D:propstat")
|
||||
nsnum = 0
|
||||
|
||||
for ns,plist in propnames.items():
|
||||
# write prop element
|
||||
pr=doc.createElement("D:prop")
|
||||
nsp="ns"+str(nsnum)
|
||||
pr = doc.createElement("D:prop")
|
||||
nsp = "ns"+str(nsnum)
|
||||
pr.setAttribute("xmlns:"+nsp,ns)
|
||||
nsnum=nsnum+1
|
||||
nsnum = nsnum+1
|
||||
|
||||
# write propertynames
|
||||
for p in plist:
|
||||
pe=doc.createElement(nsp+":"+p)
|
||||
pe = doc.createElement(nsp+":"+p)
|
||||
pr.appendChild(pe)
|
||||
|
||||
ps.appendChild(pr)
|
||||
|
@ -257,33 +256,33 @@ class PROPFIND:
|
|||
one, that means).
|
||||
|
||||
"""
|
||||
re=doc.createElement("D:response")
|
||||
re = doc.createElement("D:response")
|
||||
# append namespaces to response
|
||||
nsnum=0
|
||||
nsnum = 0
|
||||
for nsname in self.namespaces:
|
||||
re.setAttribute("xmlns:ns"+str(nsnum),nsname)
|
||||
nsnum=nsnum+1
|
||||
nsnum = nsnum+1
|
||||
|
||||
# write href information
|
||||
href=doc.createElement("D:href")
|
||||
href = doc.createElement("D:href")
|
||||
if self.use_full_urls:
|
||||
huri=doc.createTextNode(uri)
|
||||
huri = doc.createTextNode(uri)
|
||||
else:
|
||||
uparts=urlparse.urlparse(uri)
|
||||
fileloc=uparts[2]
|
||||
huri=doc.createTextNode(urllib.quote(fileloc.encode('utf8')))
|
||||
uparts = urlparse.urlparse(uri)
|
||||
fileloc = uparts[2]
|
||||
huri = doc.createTextNode(urllib.quote(fileloc.encode('utf8')))
|
||||
href.appendChild(huri)
|
||||
re.appendChild(href)
|
||||
|
||||
# write good properties
|
||||
if good_props and len(good_props.items()):
|
||||
ps=doc.createElement("D:propstat")
|
||||
ps = doc.createElement("D:propstat")
|
||||
|
||||
gp=doc.createElement("D:prop")
|
||||
gp = doc.createElement("D:prop")
|
||||
for ns in good_props.keys():
|
||||
ns_prefix="ns"+str(self.namespaces.index(ns))+":"
|
||||
for p,v in good_props[ns].items():
|
||||
pe=doc.createElement(ns_prefix+str(p))
|
||||
pe = doc.createElement(ns_prefix+str(p))
|
||||
if v == None:
|
||||
pass
|
||||
elif ns=='DAV:' and p=="resourcetype":
|
||||
|
@ -294,15 +293,15 @@ class PROPFIND:
|
|||
ve=doc.createElement(ns_prefix+v[0])
|
||||
pe.appendChild(ve)
|
||||
else:
|
||||
ve=doc.createTextNode(utf8str(v))
|
||||
ve = doc.createTextNode(utf8str(v))
|
||||
pe.appendChild(ve)
|
||||
|
||||
gp.appendChild(pe)
|
||||
if gp.hasChildNodes():
|
||||
re.appendChild(ps)
|
||||
ps.appendChild(gp)
|
||||
s=doc.createElement("D:status")
|
||||
t=doc.createTextNode("HTTP/1.1 200 OK")
|
||||
s = doc.createElement("D:status")
|
||||
t = doc.createTextNode("HTTP/1.1 200 OK")
|
||||
s.appendChild(t)
|
||||
ps.appendChild(s)
|
||||
re.appendChild(ps)
|
||||
|
@ -312,20 +311,20 @@ class PROPFIND:
|
|||
|
||||
# write a propstat for each error code
|
||||
for ecode in bad_props.keys():
|
||||
ps=doc.createElement("D:propstat")
|
||||
ps = doc.createElement("D:propstat")
|
||||
re.appendChild(ps)
|
||||
bp=doc.createElement("D:prop")
|
||||
bp = doc.createElement("D:prop")
|
||||
ps.appendChild(bp)
|
||||
|
||||
for ns in bad_props[ecode].keys():
|
||||
ns_prefix="ns"+str(self.namespaces.index(ns))+":"
|
||||
ns_prefix = "ns"+str(self.namespaces.index(ns))+":"
|
||||
|
||||
for p in bad_props[ecode][ns]:
|
||||
pe=doc.createElement(ns_prefix+str(p))
|
||||
pe = doc.createElement(ns_prefix+str(p))
|
||||
bp.appendChild(pe)
|
||||
|
||||
s=doc.createElement("D:status")
|
||||
t=doc.createTextNode(utils.gen_estring(ecode))
|
||||
s = doc.createElement("D:status")
|
||||
t = doc.createTextNode(utils.gen_estring(ecode))
|
||||
s.appendChild(t)
|
||||
ps.appendChild(s)
|
||||
re.appendChild(ps)
|
||||
|
@ -342,20 +341,20 @@ class PROPFIND:
|
|||
found or the user is not allowed to read them.
|
||||
|
||||
"""
|
||||
good_props={}
|
||||
bad_props={}
|
||||
good_props = {}
|
||||
bad_props = {}
|
||||
|
||||
for (ns,plist) in self.proplist.items():
|
||||
good_props[ns]={}
|
||||
bad_props={}
|
||||
good_props[ns] = {}
|
||||
bad_props = {}
|
||||
ec = 0
|
||||
for prop in plist:
|
||||
try:
|
||||
ec = 0
|
||||
r=self.__dataclass.get_prop(uri,ns,prop)
|
||||
good_props[ns][prop]=r
|
||||
r = self.__dataclass.get_prop(uri,ns,prop)
|
||||
good_props[ns][prop] = r
|
||||
except DAV_Error, error_code:
|
||||
ec=error_code[0]
|
||||
ec = error_code[0]
|
||||
|
||||
# ignore props with error_code if 0 (invisible)
|
||||
if ec==0: continue
|
||||
|
@ -364,9 +363,11 @@ class PROPFIND:
|
|||
if bad_props[ec].has_key(ns):
|
||||
bad_props[ec][ns].append(prop)
|
||||
else:
|
||||
bad_props[ec][ns]=[prop]
|
||||
bad_props[ec][ns] = [prop]
|
||||
else:
|
||||
bad_props[ec]={ns:[prop]}
|
||||
bad_props[ec] = {ns:[prop]}
|
||||
|
||||
return good_props, bad_props
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -27,7 +27,7 @@ AUTHOR = 'Simon Pamies <s.pamies@banality.de>'
|
|||
|
||||
def gen_estring(ecode):
|
||||
""" generate an error string from the given code """
|
||||
ec=atoi(str(ecode))
|
||||
ec = atoi(str(ecode))
|
||||
if STATUS_CODES.has_key(ec):
|
||||
return "HTTP/1.1 %s %s" %(ec,STATUS_CODES[ec])
|
||||
else:
|
||||
|
@ -46,20 +46,20 @@ def parse_propfind(xml_doc):
|
|||
doc = PyExpat.Reader().fromString(xml_doc)
|
||||
snit = doc.createNodeIterator(doc, NodeFilter.NodeFilter.SHOW_ELEMENT, None, None)
|
||||
|
||||
request_type=None
|
||||
props={}
|
||||
namespaces=[]
|
||||
request_type = None
|
||||
props = {}
|
||||
namespaces = []
|
||||
|
||||
while 1:
|
||||
curr_elem = snit.nextNode()
|
||||
if not curr_elem: break
|
||||
ename=fname=lower(curr_elem.nodeName)
|
||||
ename=fname = lower(curr_elem.nodeName)
|
||||
if ":" in fname:
|
||||
ename=split(fname,":")[1]
|
||||
if ename=="prop": request_type=RT_PROP; continue
|
||||
ename = split(fname,":")[1]
|
||||
if ename=="prop": request_type = RT_PROP; continue
|
||||
if ename=="propfind": continue
|
||||
if ename=="allprop": request_type=RT_ALLPROP; continue
|
||||
if ename=="propname": request_type=RT_PROPNAME; continue
|
||||
if ename=="allprop": request_type = RT_ALLPROP; continue
|
||||
if ename=="propname": request_type = RT_PROPNAME; continue
|
||||
|
||||
# rest should be names of attributes
|
||||
|
||||
|
@ -67,13 +67,13 @@ def parse_propfind(xml_doc):
|
|||
if props.has_key(ns):
|
||||
props[ns].append(ename)
|
||||
else:
|
||||
props[ns]=[ename]
|
||||
props[ns] = [ename]
|
||||
namespaces.append(ns)
|
||||
|
||||
return request_type,props,namespaces
|
||||
|
||||
|
||||
def create_treelist(dataclass,uri):
|
||||
def create_treelist(dataclass, uri):
|
||||
""" create a list of resources out of a tree
|
||||
|
||||
This function is used for the COPY, MOVE and DELETE methods
|
||||
|
@ -83,23 +83,23 @@ def create_treelist(dataclass,uri):
|
|||
It will return the flattened tree as list
|
||||
|
||||
"""
|
||||
queue=[uri]
|
||||
list=[uri]
|
||||
queue = [uri]
|
||||
list = [uri]
|
||||
while len(queue):
|
||||
element=queue[-1]
|
||||
element = queue[-1]
|
||||
if dataclass.is_collection(element):
|
||||
childs=dataclass.get_childs(element)
|
||||
childs = dataclass.get_childs(element)
|
||||
else:
|
||||
childs=[]
|
||||
childs = []
|
||||
if len(childs):
|
||||
list=list+childs
|
||||
list = list+childs
|
||||
# update queue
|
||||
del queue[-1]
|
||||
if len(childs):
|
||||
queue=queue+childs
|
||||
queue = queue+childs
|
||||
return list
|
||||
|
||||
def is_prefix(uri1,uri2):
|
||||
def is_prefix(uri1, uri2):
|
||||
""" returns 1 of uri1 is a prefix of uri2 """
|
||||
if uri2[:len(uri1)]==uri1:
|
||||
return 1
|
||||
|
@ -111,50 +111,51 @@ def quote_uri(uri):
|
|||
import urlparse
|
||||
import urllib
|
||||
|
||||
up=urlparse.urlparse(uri)
|
||||
np=urllib.quote(up[2])
|
||||
return urlparse.urlunparse((up[0],up[1],np,up[3],up[4],up[5]))
|
||||
up = urlparse.urlparse(uri)
|
||||
np = urllib.quote(up[2])
|
||||
return urlparse.urlunparse((up[0], up[1], np, up[3], up[4], up[5]))
|
||||
|
||||
def get_uriparentpath(uri):
|
||||
""" extract the uri path and remove the last element """
|
||||
up=urlparse.urlparse(uri)
|
||||
return joinfields(split(up[2],"/")[:-1],"/")
|
||||
up = urlparse.urlparse(uri)
|
||||
return joinfields(split(up[2], "/")[:-1], "/")
|
||||
|
||||
def get_urifilename(uri):
|
||||
""" extract the uri path and return the last element """
|
||||
up=urlparse.urlparse(uri)
|
||||
return split(up[2],"/")[-1]
|
||||
up = urlparse.urlparse(uri)
|
||||
return split(up[2], "/")[-1]
|
||||
|
||||
def get_parenturi(uri):
|
||||
""" return the parent of the given resource"""
|
||||
up=urlparse.urlparse(uri)
|
||||
np=joinfields(split(up[2],"/")[:-1],"/")
|
||||
return urlparse.urlunparse((up[0],up[1],np,up[3],up[4],up[5]))
|
||||
up = urlparse.urlparse(uri)
|
||||
np = joinfields(split(up[2], "/")[:-1], "/")
|
||||
return urlparse.urlunparse((up[0], up[1], np, up[3], up[4], up[5]))
|
||||
|
||||
### XML utilities
|
||||
|
||||
def make_xmlresponse(result):
|
||||
""" construct a response from a dict of uri:error_code elements """
|
||||
doc = Document(None)
|
||||
ms=doc.createElement("D:multistatus")
|
||||
ms.setAttribute("xmlns:D","DAV:")
|
||||
ms = doc.createElement("D:multistatus")
|
||||
ms.setAttribute("xmlns:D", "DAV:")
|
||||
doc.appendChild(ms)
|
||||
|
||||
for el,ec in result.items():
|
||||
re=doc.createElement("D:response")
|
||||
hr=doc.createElement("D:href")
|
||||
st=doc.createElement("D:status")
|
||||
huri=doc.createTextNode(quote_uri(el))
|
||||
t=doc.createTextNode(gen_estring(ec))
|
||||
for el, ec in result.items():
|
||||
re = doc.createElement("D:response")
|
||||
hr = doc.createElement("D:href")
|
||||
st = doc.createElement("D:status")
|
||||
huri = doc.createTextNode(quote_uri(el))
|
||||
t = doc.createTextNode(gen_estring(ec))
|
||||
st.appendChild(t)
|
||||
hr.appendChild(huri)
|
||||
re.appendChild(hr)
|
||||
re.appendChild(st)
|
||||
ms.appendChild(re)
|
||||
|
||||
sfile=StringIO()
|
||||
ext.PrettyPrint(doc,stream=sfile)
|
||||
s=sfile.getvalue()
|
||||
sfile = StringIO()
|
||||
ext.PrettyPrint(doc, stream = sfile)
|
||||
s = sfile.getvalue()
|
||||
sfile.close()
|
||||
return s
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
|
@ -15,7 +15,7 @@
|
|||
# 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/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
|
|
@ -49,7 +49,9 @@
|
|||
"demo_xml" : [],
|
||||
"update_xml" : [
|
||||
'security/ir.model.access.csv',
|
||||
'caldav_wizard.xml',
|
||||
'wizard/calendar_event_export_view.xml',
|
||||
'wizard/calendar_event_import_view.xml',
|
||||
'wizard/calendar_event_subscribe_view.xml',
|
||||
'caldav_view.xml'
|
||||
],
|
||||
"installable" : True,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
|
@ -15,7 +15,7 @@
|
|||
# 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/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
@ -36,14 +36,21 @@ import time
|
|||
try:
|
||||
import vobject
|
||||
except ImportError:
|
||||
raise osv.except_osv('vobject Import Error!','Please install python-vobject from http://vobject.skyhouseconsulting.com/')
|
||||
|
||||
raise osv.except_osv('vobject Import Error!','Please install python-vobject \
|
||||
from http://vobject.skyhouseconsulting.com/')
|
||||
|
||||
# O-1 Optional and can come only once
|
||||
# O-n Optional and can come more than once
|
||||
# R-1 Required and can come only once
|
||||
# R-n Required and can come more than once
|
||||
|
||||
def uid2openobjectid(cr, uidval, oomodel, rdate):
|
||||
""" UID To Open Object Id
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uidval: Get USerId vale
|
||||
@oomodel: Open Object ModelName
|
||||
@param rdate: Get Recurrent Date
|
||||
"""
|
||||
__rege = re.compile(r'OpenObject-([\w|\.]+)_([0-9]+)@(\w+)$')
|
||||
wematch = __rege.match(uidval.encode('utf8'))
|
||||
if not wematch:
|
||||
|
@ -60,17 +67,28 @@ def uid2openobjectid(cr, uidval, oomodel, rdate):
|
|||
r_id = cr.fetchone()
|
||||
if r_id:
|
||||
return (id, r_id[0])
|
||||
cr.execute(qry)
|
||||
cr.execute(qry)
|
||||
ids = map(lambda x: str(x[0]), cr.fetchall())
|
||||
if id in ids:
|
||||
return (id, None)
|
||||
return (False, None)
|
||||
|
||||
def openobjectid2uid(cr, uidval, oomodel):
|
||||
""" Open Object Id To UId
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uidval: Get USerId vale
|
||||
@oomodel: Open Object ModelName """
|
||||
|
||||
value = 'OpenObject-%s_%s@%s' % (oomodel, uidval, cr.dbname)
|
||||
return value
|
||||
|
||||
def get_attribute_mapping(cr, uid, calname, context={}):
|
||||
""" Attribute Mapping with Basic calendar fields and lines
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param calname: Get Calendar name
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
if not context:
|
||||
context = {}
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
|
@ -100,6 +118,10 @@ def get_attribute_mapping(cr, uid, calname, context={}):
|
|||
return res
|
||||
|
||||
def map_data(cr, uid, obj):
|
||||
""" Map Data
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,"""
|
||||
|
||||
vals = {}
|
||||
for map_dict in obj.__attribute__:
|
||||
map_val = obj.ical_get(map_dict, 'value')
|
||||
|
@ -146,14 +168,26 @@ def map_data(cr, uid, obj):
|
|||
class CalDAV(object):
|
||||
__attribute__ = {}
|
||||
|
||||
|
||||
|
||||
|
||||
def ical_set(self, name, value, type):
|
||||
""" set calendar Attribute
|
||||
@param self: The object pointer,
|
||||
@param name: Get Attribute Name
|
||||
@param value: Get Attribute Value
|
||||
@param type: Get Attribute Type
|
||||
"""
|
||||
if name in self.__attribute__ and self.__attribute__[name]:
|
||||
self.__attribute__[name][type] = value
|
||||
return True
|
||||
|
||||
def ical_get(self, name, type):
|
||||
""" Get calendar Attribute
|
||||
@param self: The object pointer,
|
||||
@param name: Get Attribute Name
|
||||
@param type: Get Attribute Type
|
||||
"""
|
||||
|
||||
if self.__attribute__.get(name):
|
||||
val = self.__attribute__.get(name).get(type, None)
|
||||
valtype = self.__attribute__.get(name).get('type', None)
|
||||
|
@ -168,12 +202,23 @@ class CalDAV(object):
|
|||
return self.__attribute__.get(name, None)
|
||||
|
||||
def ical_reset(self, type):
|
||||
""" Reset Calendar Attribute
|
||||
@param self: The object pointer,
|
||||
@param type: Get Attribute Type
|
||||
"""
|
||||
|
||||
for name in self.__attribute__:
|
||||
if self.__attribute__[name]:
|
||||
self.__attribute__[name][type] = None
|
||||
return True
|
||||
|
||||
|
||||
def parse_ics(self, cr, uid, child, cal_children=None, context=None):
|
||||
""" parse calendaring and scheduling information
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
att_data = []
|
||||
for cal_data in child.getChildren():
|
||||
if cal_data.name.lower() == 'attendee':
|
||||
|
@ -197,7 +242,7 @@ class CalDAV(object):
|
|||
self.ical_set(cal_data.name.lower(), ','.join(exval), 'value')
|
||||
continue
|
||||
if cal_data.name.lower() in self.__attribute__:
|
||||
|
||||
|
||||
if cal_data.params.get('X-VOBJ-ORIGINAL-TZID'):
|
||||
self.ical_set('vtimezone', cal_data.params.get('X-VOBJ-ORIGINAL-TZID'), 'value')
|
||||
self.ical_set(cal_data.name.lower(), cal_data.value, 'value')
|
||||
|
@ -205,8 +250,15 @@ class CalDAV(object):
|
|||
return vals
|
||||
|
||||
def create_ics(self, cr, uid, datas, name, ical, context=None):
|
||||
""" create calendaring and scheduling information
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
if not datas:
|
||||
return
|
||||
timezones = []
|
||||
for data in datas:
|
||||
tzval = None
|
||||
vevent = ical.add(name)
|
||||
|
@ -222,10 +274,10 @@ class CalDAV(object):
|
|||
model_obj = self.pool.get(model)
|
||||
r_ids = []
|
||||
if model_obj._columns.get('recurrent_uid', None):
|
||||
cr.execute('select id from %s where recurrent_uid=%s'
|
||||
cr.execute('select id from %s where recurrent_uid=%s'
|
||||
% (model_obj._table, data[map_field]))
|
||||
r_ids = map(lambda x: x[0], cr.fetchall())
|
||||
if r_ids:
|
||||
if r_ids:
|
||||
rdata = self.pool.get(model).read(cr, uid, r_ids)
|
||||
event_obj = self.pool.get('basic.calendar.event')
|
||||
rcal = event_obj.export_cal(cr, uid, rdata, context=context)
|
||||
|
@ -246,17 +298,18 @@ class CalDAV(object):
|
|||
alarm_obj = self.pool.get('basic.calendar.alarm')
|
||||
vevent = alarm_obj.export_cal(cr, uid, model, \
|
||||
data[map_field][0], vevent, context=ctx)
|
||||
elif field == 'vtimezone' and data[map_field]:
|
||||
elif field == 'vtimezone' and data[map_field] and data[map_field] not in timezones:
|
||||
tzval = data[map_field]
|
||||
tz_obj = self.pool.get('basic.calendar.timezone')
|
||||
ical = tz_obj.export_cal(cr, uid, None, \
|
||||
data[map_field], ical, context=context)
|
||||
timezones.append(data[map_field])
|
||||
elif data[map_field]:
|
||||
if map_type in ("char", "text"):
|
||||
if field in ('exdate'):
|
||||
vevent.add(field).value = map(parser.parse, (data[map_field]).split(','))
|
||||
else:
|
||||
vevent.add(field).value = tools.ustr(data[map_field])
|
||||
vevent.add(field).value = tools.ustr(data[map_field])
|
||||
elif map_type in ('datetime', 'date') and data[map_field]:
|
||||
dtfield = vevent.add(field)
|
||||
dtfield.value = parser.parse(data[map_field])
|
||||
|
@ -276,8 +329,16 @@ class CalDAV(object):
|
|||
if val1 == data[map_field]:
|
||||
vevent.add(field).value = key1
|
||||
return vevent
|
||||
|
||||
|
||||
def check_import(self, cr, uid, vals, context={}):
|
||||
"""
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param vals: Get Values
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
ids = []
|
||||
model_obj = self.pool.get(context.get('model'))
|
||||
recur_pool = {}
|
||||
|
@ -309,6 +370,14 @@ class CalDAV(object):
|
|||
return ids
|
||||
|
||||
def export_cal(self, cr, uid, datas, vobj=None, context={}):
|
||||
""" Export Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param datas: Get Data's for caldav
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
try:
|
||||
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context)
|
||||
ical = vobject.iCalendar()
|
||||
|
@ -318,6 +387,14 @@ class CalDAV(object):
|
|||
raise osv.except_osv(('Error !'), (str(e)))
|
||||
|
||||
def import_cal(self, cr, uid, content, data_id=None, context=None):
|
||||
""" Import Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param data_id: Get Data’s ID or False
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
ical_data = base64.decodestring(content)
|
||||
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context)
|
||||
parsedCal = vobject.readOne(ical_data)
|
||||
|
@ -333,6 +410,7 @@ class CalDAV(object):
|
|||
self.ical_reset('value')
|
||||
return res
|
||||
|
||||
|
||||
class Calendar(CalDAV, osv.osv):
|
||||
_name = 'basic.calendar'
|
||||
_description = 'Calendar'
|
||||
|
@ -352,27 +430,35 @@ class Calendar(CalDAV, osv.osv):
|
|||
'vtimezone': None, # Use: O-n, Type: Collection of Timezone class
|
||||
}
|
||||
_columns = {
|
||||
'name': fields.char("Name", size=64),
|
||||
'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'),
|
||||
'active': fields.boolean('Active'),
|
||||
'create_date': fields.datetime('Created Date'),
|
||||
'write_date': fields.datetime('Modifided Date'),
|
||||
'name': fields.char("Name", size=64),
|
||||
'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'),
|
||||
'active': fields.boolean('Active'),
|
||||
'create_date': fields.datetime('Created Date'),
|
||||
'write_date': fields.datetime('Modifided Date'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'active': lambda *a: True,
|
||||
'active': lambda *a: True,
|
||||
}
|
||||
|
||||
def export_cal(self, cr, uid, ids, vobj='vevent', context={}):
|
||||
""" Export Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of calendar’s IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
cal = self.browse(cr, uid, ids[0])
|
||||
ical = vobject.iCalendar()
|
||||
ical = vobject.iCalendar()
|
||||
for line in cal.line_ids:
|
||||
if line.name in ('valarm', 'attendee'):
|
||||
continue
|
||||
mod_obj = self.pool.get(line.object_id.model)
|
||||
data_ids = mod_obj.search(cr, uid, eval(line.domain), context=context)
|
||||
datas = mod_obj.read(cr, uid, data_ids, context=context)
|
||||
context.update({'model': line.object_id.model,
|
||||
context.update({'model': line.object_id.model,
|
||||
'calendar_id': cal.id
|
||||
})
|
||||
self.__attribute__ = get_attribute_mapping(cr, uid, line.name, context)
|
||||
|
@ -380,6 +466,14 @@ class Calendar(CalDAV, osv.osv):
|
|||
return ical.serialize()
|
||||
|
||||
def import_cal(self, cr, uid, content, data_id=None, context=None):
|
||||
""" Import Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param data_id: Get Data’s ID or False
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
if not context:
|
||||
context = {}
|
||||
vals = []
|
||||
|
@ -394,7 +488,7 @@ class Calendar(CalDAV, osv.osv):
|
|||
cal_children[line.name] = line.object_id.model
|
||||
for child in parsedCal.getChildren():
|
||||
if child.name.lower() in cal_children:
|
||||
context.update({'model': cal_children[child.name.lower()],
|
||||
context.update({'model': cal_children[child.name.lower()],
|
||||
'calendar_id': cal.id
|
||||
})
|
||||
self.__attribute__ = get_attribute_mapping(cr, uid, child.name.lower(), context=context)
|
||||
|
@ -407,27 +501,39 @@ class Calendar(CalDAV, osv.osv):
|
|||
self.check_import(cr, uid, vals, context=context)
|
||||
return {}
|
||||
Calendar()
|
||||
|
||||
|
||||
|
||||
class basic_calendar_line(osv.osv):
|
||||
""" Calendar Lines """
|
||||
|
||||
_name = 'basic.calendar.lines'
|
||||
_description = 'Calendar Lines'
|
||||
|
||||
_columns = {
|
||||
'name': fields.selection([('vevent', 'Event'), ('vtodo', 'TODO'), \
|
||||
('valarm', 'Alarm'), \
|
||||
('attendee', 'Attendee')], \
|
||||
string="Type", size=64),
|
||||
'object_id': fields.many2one('ir.model', 'Object'),
|
||||
string="Type", size=64),
|
||||
'object_id': fields.many2one('ir.model', 'Object'),
|
||||
'calendar_id': fields.many2one('basic.calendar', 'Calendar', \
|
||||
required=True, ondelete='cascade'),
|
||||
'domain': fields.char('Domain', size=124),
|
||||
required=True, ondelete='cascade'),
|
||||
'domain': fields.char('Domain', size=124),
|
||||
'mapping_ids': fields.one2many('basic.calendar.fields', 'type_id', 'Fields Mapping')
|
||||
}
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'domain': lambda *a: '[]',
|
||||
'domain': lambda *a: '[]',
|
||||
}
|
||||
|
||||
|
||||
def create(self, cr, uid, vals, context={}):
|
||||
""" create calendar's line
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param vals: Get the Values
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
cr.execute("Select count(id) from basic_calendar_lines \
|
||||
where name='%s' and calendar_id=%s" % (vals.get('name'), vals.get('calendar_id')))
|
||||
res = cr.fetchone()
|
||||
|
@ -439,41 +545,52 @@ line "%s" more than once' % (vals.get('name'))))
|
|||
|
||||
basic_calendar_line()
|
||||
|
||||
|
||||
class basic_calendar_attribute(osv.osv):
|
||||
_name = 'basic.calendar.attributes'
|
||||
_description = 'Calendar attributes'
|
||||
_columns = {
|
||||
'name': fields.char("Name", size=64, required=True),
|
||||
_columns = {
|
||||
'name': fields.char("Name", size=64, required=True),
|
||||
'type': fields.selection([('vevent', 'Event'), ('vtodo', 'TODO'), \
|
||||
('alarm', 'Alarm'), \
|
||||
('attendee', 'Attendee')], \
|
||||
string="Type", size=64, required=True),
|
||||
string="Type", size=64, required=True),
|
||||
}
|
||||
|
||||
basic_calendar_attribute()
|
||||
|
||||
|
||||
class basic_calendar_fields(osv.osv):
|
||||
""" Calendar fields """
|
||||
|
||||
_name = 'basic.calendar.fields'
|
||||
_description = 'Calendar fields'
|
||||
|
||||
_columns = {
|
||||
'field_id': fields.many2one('ir.model.fields', 'OpenObject Field'),
|
||||
'name': fields.many2one('basic.calendar.attributes', 'Name', required=True),
|
||||
'field_id': fields.many2one('ir.model.fields', 'OpenObject Field'),
|
||||
'name': fields.many2one('basic.calendar.attributes', 'Name', required=True),
|
||||
'type_id': fields.many2one('basic.calendar.lines', 'Type', \
|
||||
required=True, ondelete='cascade'),
|
||||
'expr': fields.char("Expression", size=64),
|
||||
'fn': fields.selection([('field', 'Use the field'),
|
||||
('const', 'Expression as constant'),
|
||||
('hours', 'Interval in hours'),
|
||||
], 'Function'),
|
||||
'mapping': fields.text('Mapping'),
|
||||
required=True, ondelete='cascade'),
|
||||
'expr': fields.char("Expression", size=64),
|
||||
'fn': fields.selection([('field', 'Use the field'),
|
||||
('const', 'Expression as constant'),
|
||||
('hours', 'Interval in hours'),
|
||||
], 'Function'),
|
||||
'mapping': fields.text('Mapping'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'fn': lambda *a: 'field',
|
||||
'fn': lambda *a: 'field',
|
||||
}
|
||||
|
||||
|
||||
def check_line(self, cr, uid, vals, name, context=None):
|
||||
""" check calendar's line
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param vals: Get Values
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
f_obj = self.pool.get('ir.model.fields')
|
||||
field = f_obj.browse(cr, uid, vals['field_id'], context=context)
|
||||
relation = field.relation
|
||||
|
@ -485,8 +602,16 @@ class basic_calendar_fields(osv.osv):
|
|||
if (relation != 'NULL') and (not relation == line_rel):
|
||||
raise osv.except_osv(_('Warning !'), _('Please provide proper configuration of "%s" in Calendar Lines' % (name)))
|
||||
return True
|
||||
|
||||
|
||||
def create(self, cr, uid, vals, context={}):
|
||||
""" Create Calendar's fields
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param vals: Get Values
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
cr.execute('select name from basic_calendar_attributes \
|
||||
where id=%s' % (vals.get('name')))
|
||||
name = cr.fetchone()
|
||||
|
@ -500,8 +625,16 @@ class basic_calendar_fields(osv.osv):
|
|||
if res[0] > 0:
|
||||
raise osv.except_osv(_('Warning !'), _('Can not map the field more than once'))
|
||||
return super(basic_calendar_fields, self).create(cr, uid, vals, context=context)
|
||||
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
""" write Calendar's fields
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param vals: Get Values
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
if not vals:
|
||||
return
|
||||
for id in ids:
|
||||
|
@ -520,6 +653,7 @@ class basic_calendar_fields(osv.osv):
|
|||
|
||||
basic_calendar_fields()
|
||||
|
||||
|
||||
class Event(CalDAV, osv.osv_memory):
|
||||
_name = 'basic.calendar.event'
|
||||
_calname = 'vevent'
|
||||
|
@ -540,7 +674,7 @@ class Event(CalDAV, osv.osv_memory):
|
|||
'transp': None, # Use: O-1, Type: TEXT, Defines whether an event is transparent or not to busy time searches.
|
||||
'uid': None, # Use: O-1, Type: TEXT, Defines the persistent, globally unique identifier for the calendar component.
|
||||
'url': None, # Use: O-1, Type: URL, Defines a Uniform Resource Locator (URL) associated with the iCalendar object.
|
||||
'recurid': None,
|
||||
'recurid': None,
|
||||
'attach': None, # Use: O-n, Type: BINARY, Provides the capability to associate a document object with a calendar component.
|
||||
'attendee': None, # Use: O-n, Type: CAL-ADDRESS, Defines an "Attendee" within a calendar component.
|
||||
'categories': None, # Use: O-n, Type: TEXT, Defines the categories for a calendar component.
|
||||
|
@ -548,69 +682,89 @@ class Event(CalDAV, osv.osv_memory):
|
|||
'contact': None, # Use: O-n, Type: TEXT, Used to represent contact information or alternately a reference to contact information associated with the calendar component.
|
||||
'exdate': None, # Use: O-n, Type: DATE-TIME, Defines the list of date/time exceptions for a recurring calendar component.
|
||||
'exrule': None, # Use: O-n, Type: RECUR, Defines a rule or repeating pattern for an exception to a recurrence set.
|
||||
'rstatus': None,
|
||||
'rstatus': None,
|
||||
'related': None, # Use: O-n, Specify the relationship of the alarm trigger with respect to the start or end of the calendar component.
|
||||
# like A trigger set 5 minutes after the end of the event or to-do.---> TRIGGER;related=END:PT5M
|
||||
'resources': None, # Use: O-n, Type: TEXT, Defines the equipment or resources anticipated for an activity specified by a calendar entity like RESOURCES:EASEL,PROJECTOR,VCR, LANGUAGE=fr:1 raton-laveur
|
||||
'rdate': None, # Use: O-n, Type: DATE-TIME, Defines the list of date/times for a recurrence set.
|
||||
'rrule': None, # Use: O-n, Type: RECUR, Defines a rule or repeating pattern for recurring events, to-dos, or time zone definitions.
|
||||
'x-prop': None,
|
||||
'x-prop': None,
|
||||
'duration': None, # Use: O-1, Type: DURATION, Specifies a positive duration of time.
|
||||
'dtend': None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that a calendar component ends.
|
||||
}
|
||||
|
||||
def export_cal(self, cr, uid, datas, vobj='vevent', context={}):
|
||||
""" Export calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param datas: Get datas
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
return super(Event, self).export_cal(cr, uid, datas, 'vevent', context=context)
|
||||
|
||||
Event()
|
||||
|
||||
|
||||
class ToDo(CalDAV, osv.osv_memory):
|
||||
_name = 'basic.calendar.todo'
|
||||
_calname = 'vtodo'
|
||||
|
||||
__attribute__ = {
|
||||
'class': None,
|
||||
'completed': None,
|
||||
'created': None,
|
||||
'description': None,
|
||||
'dtstamp': None,
|
||||
'dtstart': None,
|
||||
'duration': None,
|
||||
'due': None,
|
||||
'geo': None,
|
||||
'last-mod ': None,
|
||||
'location': None,
|
||||
'organizer': None,
|
||||
'percent': None,
|
||||
'priority': None,
|
||||
'recurid': None,
|
||||
'seq': None,
|
||||
'status': None,
|
||||
'summary': None,
|
||||
'uid': None,
|
||||
'url': None,
|
||||
'attach': None,
|
||||
'attendee': None,
|
||||
'categories': None,
|
||||
'comment': None,
|
||||
'contact': None,
|
||||
'exdate': None,
|
||||
'exrule': None,
|
||||
'rstatus': None,
|
||||
'related': None,
|
||||
'resources': None,
|
||||
'rdate': None,
|
||||
'rrule': None,
|
||||
'class': None,
|
||||
'completed': None,
|
||||
'created': None,
|
||||
'description': None,
|
||||
'dtstamp': None,
|
||||
'dtstart': None,
|
||||
'duration': None,
|
||||
'due': None,
|
||||
'geo': None,
|
||||
'last-mod ': None,
|
||||
'location': None,
|
||||
'organizer': None,
|
||||
'percent': None,
|
||||
'priority': None,
|
||||
'recurid': None,
|
||||
'seq': None,
|
||||
'status': None,
|
||||
'summary': None,
|
||||
'uid': None,
|
||||
'url': None,
|
||||
'attach': None,
|
||||
'attendee': None,
|
||||
'categories': None,
|
||||
'comment': None,
|
||||
'contact': None,
|
||||
'exdate': None,
|
||||
'exrule': None,
|
||||
'rstatus': None,
|
||||
'related': None,
|
||||
'resources': None,
|
||||
'rdate': None,
|
||||
'rrule': None,
|
||||
}
|
||||
|
||||
def export_cal(self, cr, uid, datas, vobj='vevent', context={}):
|
||||
""" Export Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param datas: Get datas
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
return super(ToDo, self).export_cal(cr, uid, datas, 'vtodo', context=context)
|
||||
|
||||
ToDo()
|
||||
|
||||
|
||||
class Journal(CalDAV):
|
||||
__attribute__ = {
|
||||
}
|
||||
|
||||
|
||||
class FreeBusy(CalDAV):
|
||||
__attribute__ = {
|
||||
'contact': None, # Use: O-1, Type: Text, Represent contact information or alternately a reference to contact information associated with the calendar component.
|
||||
|
@ -624,15 +778,15 @@ class FreeBusy(CalDAV):
|
|||
'attendee': None, # Use: O-n, Type: CAL-ADDRESS, Defines an "Attendee" within a calendar component.
|
||||
'comment': None, # Use: O-n, Type: TEXT, Specifies non-processing information intended to provide a comment to the calendar user.
|
||||
'freebusy': None, # Use: O-n, Type: PERIOD, Defines one or more free or busy time intervals.
|
||||
'rstatus': None,
|
||||
'X-prop': None,
|
||||
'rstatus': None,
|
||||
'X-prop': None,
|
||||
}
|
||||
|
||||
|
||||
class Timezone(CalDAV, osv.osv_memory):
|
||||
_name = 'basic.calendar.timezone'
|
||||
_calname = 'vtimezone'
|
||||
|
||||
|
||||
__attribute__ = {
|
||||
'tzid': {'field': 'tzid'}, # Use: R-1, Type: Text, Specifies the text value that uniquely identifies the "VTIMEZONE" calendar component.
|
||||
'last-mod': None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that the information associated with the calendar component was last revised in the calendar store.
|
||||
|
@ -641,8 +795,15 @@ class Timezone(CalDAV, osv.osv_memory):
|
|||
'daylightc': {'tzprop': None}, # Use: R-1,
|
||||
'x-prop': None, # Use: O-n, Type: Text,
|
||||
}
|
||||
|
||||
|
||||
def get_name_offset(self, cr, uid, tzid, context={}):
|
||||
""" Get Name Offset value
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
mytz = pytz.timezone(tzid.title())
|
||||
mydt = datetime.now(tz=mytz)
|
||||
offset = mydt.utcoffset()
|
||||
|
@ -653,6 +814,14 @@ class Timezone(CalDAV, osv.osv_memory):
|
|||
return (mydt.tzname(), realoffset)
|
||||
|
||||
def export_cal(self, cr, uid, model, tzid, ical, context={}):
|
||||
""" Export Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param model: Get Model's name
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
ctx = context.copy()
|
||||
ctx.update({'model': model})
|
||||
cal_tz = ical.add('vtimezone')
|
||||
|
@ -664,8 +833,16 @@ class Timezone(CalDAV, osv.osv_memory):
|
|||
tz_std.add("DTSTART").value = datetime.now() # TODO
|
||||
tz_std.add("TZNAME").value = tzname
|
||||
return ical
|
||||
|
||||
|
||||
def import_cal(self, cr, uid, ical_data, context=None):
|
||||
""" Import Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ical_data: Get calendar's data
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
for child in ical_data.getChildren():
|
||||
if child.name.lower() == 'tzid':
|
||||
tzname = child.value
|
||||
|
@ -673,7 +850,7 @@ class Timezone(CalDAV, osv.osv_memory):
|
|||
vals = map_data(cr, uid, self)
|
||||
return vals
|
||||
|
||||
Timezone()
|
||||
Timezone()
|
||||
|
||||
|
||||
class Alarm(CalDAV, osv.osv_memory):
|
||||
|
@ -689,10 +866,19 @@ class Alarm(CalDAV, osv.osv_memory):
|
|||
'duration': None, # Type: DURATION, Duration' and 'repeat' are both optional, and MUST NOT occur more than once each, but if one occurs, so MUST the other. Use:- 0-1 for AUDIO, EMAIL and PROCEDURE, Use:- 0-n for DISPLAY
|
||||
'repeat': None, # Type: INTEGER, Duration' and 'repeat' are both optional, and MUST NOT occur more than once each, but if one occurs, so MUST the other. Use:- 0-1 for AUDIO, EMAIL and PROCEDURE, Use:- 0-n for DISPLAY
|
||||
'attach': None, # Use:- O-n: which MUST point to a sound resource, which is rendered when the alarm is triggered for AUDIO, Use:- O-n: which are intended to be sent as message attachments for EMAIL, Use:- R-1:which MUST point to a procedure resource, which is invoked when the alarm is triggered for PROCEDURE.
|
||||
'x-prop': None,
|
||||
'x-prop': None,
|
||||
}
|
||||
|
||||
def export_cal(self, cr, uid, model, alarm_id, vevent, context={}):
|
||||
""" Export Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param model: Get Model's name
|
||||
@param alarm_id: Get Alarm's Id
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
valarm = vevent.add('valarm')
|
||||
alarm_object = self.pool.get(model)
|
||||
alarm_data = alarm_object.read(cr, uid, alarm_id, [])
|
||||
|
@ -719,6 +905,14 @@ class Alarm(CalDAV, osv.osv_memory):
|
|||
return vevent
|
||||
|
||||
def import_cal(self, cr, uid, ical_data, context=None):
|
||||
""" Import Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ical_data: Get calendar's Data
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
ctx = context.copy()
|
||||
ctx.update({'model': context.get('model', None)})
|
||||
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, ctx)
|
||||
|
@ -753,6 +947,7 @@ class Alarm(CalDAV, osv.osv_memory):
|
|||
|
||||
Alarm()
|
||||
|
||||
|
||||
class Attendee(CalDAV, osv.osv_memory):
|
||||
_name = 'basic.calendar.attendee'
|
||||
_calname = 'attendee'
|
||||
|
@ -772,6 +967,14 @@ class Attendee(CalDAV, osv.osv_memory):
|
|||
}
|
||||
|
||||
def import_cal(self, cr, uid, ical_data, context=None):
|
||||
""" Import Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ical_data: Get calendar's Data
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
ctx = context.copy()
|
||||
ctx.update({'model': context.get('model', None)})
|
||||
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, ctx)
|
||||
|
@ -787,6 +990,15 @@ class Attendee(CalDAV, osv.osv_memory):
|
|||
return vals
|
||||
|
||||
def export_cal(self, cr, uid, model, attendee_ids, vevent, context={}):
|
||||
""" Export Calendar
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param model: Get model's name
|
||||
@param attendee_ids: Get Attendee's Id
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
attendee_object = self.pool.get(model)
|
||||
ctx = context.copy()
|
||||
ctx.update({'model': model})
|
||||
|
@ -812,5 +1024,4 @@ class Attendee(CalDAV, osv.osv_memory):
|
|||
|
||||
Attendee()
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 heapq
|
||||
|
||||
|
@ -10,8 +31,8 @@ def memoize(maxsize):
|
|||
def wrapper(*args):
|
||||
key = repr(args)
|
||||
# performance crap
|
||||
_cache=cache
|
||||
_heap=heap
|
||||
_cache = cache
|
||||
_heap = heap
|
||||
_heappop = heapq.heappop
|
||||
_heappush = heapq.heappush
|
||||
_time = time.time
|
||||
|
@ -20,13 +41,13 @@ def memoize(maxsize):
|
|||
if not _cache.has_key(key):
|
||||
if _cursize == _maxsize:
|
||||
# pop oldest element
|
||||
(_,oldkey) = _heappop(_heap)
|
||||
(_, oldkey) = _heappop(_heap)
|
||||
_cache.pop(oldkey)
|
||||
else:
|
||||
_cursize += 1
|
||||
# insert this element
|
||||
_cache[key] = f(*args)
|
||||
_heappush(_heap,(_time(),key))
|
||||
_heappush(_heap, (_time(), key))
|
||||
wrapper.misses += 1
|
||||
else:
|
||||
wrapper.hits += 1
|
||||
|
@ -34,6 +55,8 @@ def memoize(maxsize):
|
|||
wrapper.__doc__ = f.__doc__
|
||||
wrapper.__name__ = f.__name__
|
||||
wrapper.hits = wrapper.misses = 0
|
||||
return wrapper
|
||||
return wrapper
|
||||
return decorating_function
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
|
@ -15,7 +15,7 @@
|
|||
# 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/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
@ -49,10 +49,10 @@ class tinydav_handler(dav_interface):
|
|||
"""
|
||||
PROPS={'DAV:': dav_interface.PROPS['DAV:'], }
|
||||
|
||||
M_NS={ "DAV:" : dav_interface.M_NS['DAV:'], }
|
||||
M_NS={ "DAV:": dav_interface.M_NS['DAV:'], }
|
||||
|
||||
def __init__(self, parent, verbose=False):
|
||||
self.db_name = False
|
||||
self.db_name = False
|
||||
self.parent = parent
|
||||
self.baseuri = parent.baseuri
|
||||
|
||||
|
@ -64,7 +64,7 @@ class tinydav_handler(dav_interface):
|
|||
if not dbname:
|
||||
cr.close()
|
||||
return props
|
||||
node = self.uri2object(cr,uid,pool, uri2)
|
||||
node = self.uri2object(cr, uid, pool, uri2)
|
||||
if node:
|
||||
props.update(node.get_dav_props(cr))
|
||||
cr.close()
|
||||
|
@ -78,18 +78,18 @@ class tinydav_handler(dav_interface):
|
|||
pname -- name of the property
|
||||
"""
|
||||
if self.M_NS.has_key(ns):
|
||||
return dav_interface.get_prop(self,uri,ns,propname)
|
||||
return dav_interface.get_prop(self, uri, ns, propname)
|
||||
|
||||
if uri[-1]=='/':uri=uri[:-1]
|
||||
if uri[-1]=='/':uri = uri[:-1]
|
||||
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
|
||||
if not dbname:
|
||||
cr.close()
|
||||
raise DAV_NotFound
|
||||
node = self.uri2object(cr,uid,pool, uri2)
|
||||
node = self.uri2object(cr, uid, pool, uri2)
|
||||
if not node:
|
||||
cr.close()
|
||||
raise DAV_NotFound
|
||||
res = node.get_dav_eprop(cr,ns,propname)
|
||||
res = node.get_dav_eprop(cr, ns, propname)
|
||||
cr.close()
|
||||
return res
|
||||
|
||||
|
@ -97,21 +97,21 @@ class tinydav_handler(dav_interface):
|
|||
""" Return the base URI of this request, or even join it with the
|
||||
ajoin path elements
|
||||
"""
|
||||
return self.baseuri+ '/'.join(ajoin)
|
||||
return self.baseuri+ '/'.join(ajoin)
|
||||
|
||||
def uri2local(self, uri):
|
||||
uparts=urlparse.urlparse(uri)
|
||||
reluri=uparts[2]
|
||||
uparts = urlparse.urlparse(uri)
|
||||
reluri = uparts[2]
|
||||
if reluri and reluri[-1]=="/":
|
||||
reluri=reluri[:-1]
|
||||
reluri = reluri[:-1]
|
||||
return reluri
|
||||
|
||||
#
|
||||
# pos: -1 to get the parent of the uri
|
||||
#
|
||||
def get_cr(self, uri):
|
||||
def get_cr(self, uri):
|
||||
pdb = self.parent.auth_proxy.last_auth
|
||||
reluri = self.uri2local(uri)
|
||||
reluri = self.uri2local(uri)
|
||||
try:
|
||||
dbname = reluri.split('/')[2]
|
||||
except:
|
||||
|
@ -121,7 +121,7 @@ class tinydav_handler(dav_interface):
|
|||
if not pdb and dbname:
|
||||
# if dbname was in our uri, we should have authenticated
|
||||
# against that.
|
||||
raise Exception("Programming error")
|
||||
raise Exception("Programming error")
|
||||
assert pdb == dbname, " %s != %s" %(pdb, dbname)
|
||||
user, passwd, dbn2, uid = self.parent.auth_proxy.auth_creds[pdb]
|
||||
db,pool = pooler.get_db_and_pool(dbname)
|
||||
|
@ -134,29 +134,29 @@ class tinydav_handler(dav_interface):
|
|||
return None
|
||||
return pool.get('basic.calendar').get_calendar_object(cr, uid, uri)
|
||||
|
||||
def get_data(self,uri):
|
||||
def get_data(self, uri):
|
||||
self.parent.log_message('GET: %s' % uri)
|
||||
if uri[-1]=='/':uri=uri[:-1]
|
||||
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
|
||||
try:
|
||||
if not dbname:
|
||||
raise DAV_Error, 409
|
||||
node = self.uri2object(cr,uid,pool, uri2)
|
||||
node = self.uri2object(cr, uid, pool, uri2)
|
||||
if not node:
|
||||
raise DAV_NotFound(uri2)
|
||||
try:
|
||||
try:
|
||||
datas = node.get_data(cr, uid)
|
||||
except TypeError,e:
|
||||
except TypeError, e:
|
||||
import traceback
|
||||
self.parent.log_error("GET typeError: %s", str(e))
|
||||
self.parent.log_message("Exc: %s",traceback.format_exc())
|
||||
self.parent.log_message("Exc: %s", traceback.format_exc())
|
||||
raise DAV_Forbidden
|
||||
except IndexError,e :
|
||||
except IndexError, e :
|
||||
self.parent.log_error("GET IndexError: %s", str(e))
|
||||
raise DAV_NotFound(uri2)
|
||||
except Exception,e:
|
||||
except Exception, e:
|
||||
import traceback
|
||||
self.parent.log_error("GET exception: %s",str(e))
|
||||
self.parent.log_error("GET exception: %s", str(e))
|
||||
self.parent.log_message("Exc: %s", traceback.format_exc())
|
||||
raise DAV_Error, 409
|
||||
return datas
|
||||
|
@ -164,7 +164,7 @@ class tinydav_handler(dav_interface):
|
|||
cr.close()
|
||||
|
||||
@memoize(CACHE_SIZE)
|
||||
def _get_dav_resourcetype(self,uri):
|
||||
def _get_dav_resourcetype(self, uri):
|
||||
""" return type of object """
|
||||
self.parent.log_message('get RT: %s' % uri)
|
||||
if uri[-1]=='/':uri=uri[:-1]
|
||||
|
@ -172,21 +172,21 @@ class tinydav_handler(dav_interface):
|
|||
try:
|
||||
if not dbname:
|
||||
return COLLECTION
|
||||
node = self.uri2object(cr,uid,pool, uri2)
|
||||
node = self.uri2object(cr, uid, pool, uri2)
|
||||
if not node:
|
||||
raise DAV_NotFound(uri2)
|
||||
raise DAV_NotFound(uri2)
|
||||
return OBJECT
|
||||
finally:
|
||||
cr.close()
|
||||
|
||||
def _get_dav_displayname(self,uri):
|
||||
def _get_dav_displayname(self, uri):
|
||||
self.parent.log_message('get DN: %s' % uri)
|
||||
if uri[-1]=='/':uri=uri[:-1]
|
||||
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
|
||||
if not dbname:
|
||||
cr.close()
|
||||
return COLLECTION
|
||||
node = self.uri2object(cr,uid,pool, uri2)
|
||||
node = self.uri2object(cr, uid, pool, uri2)
|
||||
if not node:
|
||||
cr.close()
|
||||
raise DAV_NotFound(uri2)
|
||||
|
@ -194,7 +194,7 @@ class tinydav_handler(dav_interface):
|
|||
return node.displayname
|
||||
|
||||
@memoize(CACHE_SIZE)
|
||||
def _get_dav_getcontentlength(self,uri):
|
||||
def _get_dav_getcontentlength(self, uri):
|
||||
""" return the content length of an object """
|
||||
self.parent.log_message('get length: %s' % uri)
|
||||
if uri[-1]=='/':uri=uri[:-1]
|
||||
|
@ -212,7 +212,7 @@ class tinydav_handler(dav_interface):
|
|||
return str(result)
|
||||
|
||||
@memoize(CACHE_SIZE)
|
||||
def _get_dav_getetag(self,uri):
|
||||
def _get_dav_getetag(self, uri):
|
||||
""" return the ETag of an object """
|
||||
self.parent.log_message('get etag: %s' % uri)
|
||||
if uri[-1]=='/':uri=uri[:-1]
|
||||
|
@ -230,7 +230,7 @@ class tinydav_handler(dav_interface):
|
|||
return str(result)
|
||||
|
||||
@memoize(CACHE_SIZE)
|
||||
def get_lastmodified(self,uri):
|
||||
def get_lastmodified(self, uri):
|
||||
""" return the last modified date of the object """
|
||||
if uri[-1]=='/':uri=uri[:-1]
|
||||
today = time.time()
|
||||
|
@ -238,18 +238,18 @@ class tinydav_handler(dav_interface):
|
|||
try:
|
||||
if not dbname:
|
||||
return today
|
||||
node = self.uri2object(cr,uid,pool, uri2)
|
||||
node = self.uri2object(cr, uid, pool, uri2)
|
||||
if not node:
|
||||
raise DAV_NotFound(uri2)
|
||||
if node.write_date:
|
||||
return time.mktime(time.strptime(node.write_date,'%Y-%m-%d %H:%M:%S'))
|
||||
return time.mktime(time.strptime(node.write_date, '%Y-%m-%d %H:%M:%S'))
|
||||
else:
|
||||
return today
|
||||
finally:
|
||||
cr.close()
|
||||
|
||||
@memoize(CACHE_SIZE)
|
||||
def get_creationdate(self,uri):
|
||||
def get_creationdate(self, uri):
|
||||
""" return the last modified date of the object """
|
||||
|
||||
if uri[-1]=='/':uri=uri[:-1]
|
||||
|
@ -257,11 +257,11 @@ class tinydav_handler(dav_interface):
|
|||
try:
|
||||
if not dbname:
|
||||
raise DAV_Error, 409
|
||||
node = self.uri2object(cr,uid,pool, uri2)
|
||||
node = self.uri2object(cr, uid, pool, uri2)
|
||||
if not node:
|
||||
raise DAV_NotFound(uri2)
|
||||
if node.create_date:
|
||||
result = time.strptime(node.create_date,'%Y-%m-%d %H:%M:%S')
|
||||
result = time.strptime(node.create_date, '%Y-%m-%d %H:%M:%S')
|
||||
else:
|
||||
result = time.gmtime()
|
||||
return result
|
||||
|
@ -269,14 +269,14 @@ class tinydav_handler(dav_interface):
|
|||
cr.close()
|
||||
|
||||
@memoize(CACHE_SIZE)
|
||||
def _get_dav_getcontenttype(self,uri):
|
||||
def _get_dav_getcontenttype(self, uri):
|
||||
self.parent.log_message('get contenttype: %s' % uri)
|
||||
if uri[-1]=='/':uri=uri[:-1]
|
||||
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
|
||||
try:
|
||||
if not dbname:
|
||||
return 'httpd/unix-directory'
|
||||
node = self.uri2object(cr,uid,pool, uri2)
|
||||
node = self.uri2object(cr, uid, pool, uri2)
|
||||
if not node:
|
||||
raise DAV_NotFound(uri2)
|
||||
result = node.mimetype
|
||||
|
@ -285,50 +285,50 @@ class tinydav_handler(dav_interface):
|
|||
finally:
|
||||
cr.close()
|
||||
|
||||
|
||||
|
||||
|
||||
def put(self, uri, data, content_type=None):
|
||||
""" put the object into the filesystem """
|
||||
self.parent.log_message('Putting %s (%d), %s'%( misc.ustr(uri), len(data), content_type))
|
||||
self.parent.log_message('Putting %s (%d), %s'%(misc.ustr(uri), len(data), content_type))
|
||||
parent='/'.join(uri.split('/')[:-1])
|
||||
cr, uid, pool,dbname, uri2 = self.get_cr(uri)
|
||||
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
|
||||
if not dbname:
|
||||
raise DAV_Forbidden
|
||||
try:
|
||||
node = self.uri2object(cr,uid,pool, uri2[:])
|
||||
node = self.uri2object(cr, uid, pool, uri2[:])
|
||||
except:
|
||||
node = False
|
||||
node = False
|
||||
|
||||
if not node:
|
||||
raise DAV_Forbidden
|
||||
else:
|
||||
try:
|
||||
node.set_data(cr, uid, data)
|
||||
except Exception,e:
|
||||
import traceback
|
||||
node.set_data(cr, uid, data)
|
||||
except Exception, e:
|
||||
import traceback
|
||||
self.parent.log_error("Cannot save :%s", str(e))
|
||||
self.parent.log_message("Exc: %s",traceback.format_exc())
|
||||
self.parent.log_message("Exc: %s", traceback.format_exc())
|
||||
raise DAV_Forbidden
|
||||
|
||||
|
||||
cr.commit()
|
||||
cr.close()
|
||||
return 201
|
||||
|
||||
|
||||
|
||||
|
||||
def exists(self,uri):
|
||||
def exists(self, uri):
|
||||
""" test if a resource exists """
|
||||
result = False
|
||||
cr, uid, pool,dbname, uri2 = self.get_cr(uri)
|
||||
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
|
||||
if not dbname:
|
||||
cr.close()
|
||||
return True
|
||||
try:
|
||||
node = self.uri2object(cr,uid,pool, uri2)
|
||||
node = self.uri2object(cr, uid, pool, uri2)
|
||||
if node:
|
||||
result = True
|
||||
except:
|
||||
pass
|
||||
cr.close()
|
||||
return result
|
||||
return result
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
|
@ -15,7 +15,7 @@
|
|||
# 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/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
@ -26,47 +26,46 @@ import tools
|
|||
import time
|
||||
import base64
|
||||
|
||||
class node_calendar(object):
|
||||
|
||||
class node_calendar(object):
|
||||
def __init__(self, path, context, calendar):
|
||||
self.path = path
|
||||
self.context = context
|
||||
self.calendar_id = calendar.id
|
||||
self.mimetype = 'ics'
|
||||
self.calendar_id = calendar.id
|
||||
self.mimetype = 'ics'
|
||||
self.create_date = calendar.create_date
|
||||
self.write_date = calendar.write_date or calendar.create_date
|
||||
self.content_length = 0
|
||||
self.displayname = calendar.name
|
||||
|
||||
|
||||
def get_data(self, cr, uid):
|
||||
|
||||
|
||||
def get_data(self, cr, uid):
|
||||
calendar_obj = pooler.get_pool(cr.dbname).get('basic.calendar')
|
||||
return calendar_obj.export_cal(cr, uid, [self.calendar_id])
|
||||
|
||||
def get_data_len(self, cr):
|
||||
return calendar_obj.export_cal(cr, uid, [self.calendar_id])
|
||||
|
||||
def get_data_len(self, cr):
|
||||
return self.content_length
|
||||
|
||||
def set_data(self, cr, uid, data):
|
||||
calendar_obj = pooler.get_pool(cr.dbname).get('basic.calendar')
|
||||
def set_data(self, cr, uid, data):
|
||||
calendar_obj = pooler.get_pool(cr.dbname).get('basic.calendar')
|
||||
return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id)
|
||||
|
||||
def get_etag(self,cr):
|
||||
def get_etag(self, cr):
|
||||
""" Get a tag, unique per object + modification.
|
||||
|
||||
|
||||
see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """
|
||||
return self._get_ttag(cr) + ':' + self._get_wtag(cr)
|
||||
|
||||
def _get_wtag(self,cr):
|
||||
def _get_wtag(self, cr):
|
||||
""" Return the modification time as a unique, compact string """
|
||||
if self.write_date:
|
||||
wtime = time.mktime(time.strptime(self.write_date,'%Y-%m-%d %H:%M:%S'))
|
||||
wtime = time.mktime(time.strptime(self.write_date, '%Y-%m-%d %H:%M:%S'))
|
||||
else: wtime = time.time()
|
||||
return str(wtime)
|
||||
|
||||
def _get_ttag(self,cr):
|
||||
def _get_ttag(self, cr):
|
||||
return 'calendar-%d' % self.calendar_id
|
||||
|
||||
def get_dav_eprop(self,cr,ns,prop):
|
||||
return None
|
||||
|
||||
|
||||
class Calendar(osv.osv):
|
||||
_inherit = 'basic.calendar'
|
||||
|
@ -82,5 +81,7 @@ class Calendar(osv.osv):
|
|||
return None
|
||||
calendar_id, calendar_name = res[0]
|
||||
calendar = self.browse(cr, uid, calendar_id)
|
||||
return node_calendar(uri, context, calendar)
|
||||
return node_calendar(uri, context, calendar)
|
||||
Calendar()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4
|
|
@ -31,7 +31,7 @@
|
|||
<separator string="Value Mapping" colspan="4" />
|
||||
<field name="mapping" select="1" colspan="4" nolabel="1" />
|
||||
</form>
|
||||
</field>
|
||||
</field>
|
||||
</form>
|
||||
<tree string="Attributes Mapping" editable="bottom">
|
||||
<field name="name" select="1" />
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<wizard string="Import .ics File" model="basic.calendar"
|
||||
name="calendar.event.import" id="wizard_cal_event_import" />
|
||||
|
||||
<wizard string="Subscribe"
|
||||
model="basic.calendar" name="calendar.event.subscribe"
|
||||
id="wizard_cal_event_subscribe" multi="True" />
|
||||
|
||||
<wizard string="Export .ics File" model="basic.calendar"
|
||||
name="calendar.event.export" id="wizard_cal_event_export" />
|
||||
|
||||
<wizard string="Edit this event" model="basic.calendar.event"
|
||||
name="calendar.event.edit.this" id="wizard_edit_this_event"
|
||||
menu="False" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,6 +1,13 @@
|
|||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_basic_calendar_all","basic.calendar","model_basic_calendar",,1,1,1,1
|
||||
"access_basic_calendar_event_all","basic.calendar.event","model_basic_calendar_event",,1,1,1,1
|
||||
"access_basic_calendar_attendee_all","basic.calendar.attendee","model_basic_calendar_attendee",,1,1,1,1
|
||||
"access_calendar_todo_all","basic.calendar.todo","model_basic_calendar_todo",,1,1,1,1
|
||||
"access_basic_calendar_alarm_all","basic.calendar.alarm","model_basic_calendar_alarm",,1,1,1,1
|
||||
"access_basic_calendar_all","basic.calendar","model_basic_calendar","base.group_user",1,1,1,1
|
||||
"access_basic_calendar_event_all","basic.calendar.event","model_basic_calendar_event","base.group_user",1,1,1,0
|
||||
"access_basic_calendar_attendee_all","basic.calendar.attendee","model_basic_calendar_attendee","base.group_user",1,1,1,0
|
||||
"access_calendar_todo_all","basic.calendar.todo","model_basic_calendar_todo","base.group_user",1,1,1,0
|
||||
"access_basic_calendar_alarm_all","basic.calendar.alarm","model_basic_calendar_alarm","base.group_user",1,1,1,1
|
||||
"access_basic_calendar_lines","basic.calendar.lines","model_basic_calendar_lines","base.group_user",1,1,1,1
|
||||
"access_basic_calendar_attributes","basic.calendar.attributes","model_basic_calendar_attributes","base.group_user",1,1,1,1
|
||||
"access_basic_calendar_fields","basic.calendar.fields","model_basic_calendar_fields","base.group_user",1,1,1,1
|
||||
"access_basic_calendar_timezone","basic.calendar.timezone","model_basic_calendar_timezone","base.group_user",1,1,1,1
|
||||
"access_calendar_event_export","calendar.event.export","model_calendar_event_export","base.group_user",1,1,1,1
|
||||
"access_calendar_event_import","calendar.event.import","model_calendar_event_import","base.group_user",1,1,1,1
|
||||
"access_calendar_event_subscribe","calendar.event.subscribe","model_calendar_event_subscribe","base.group_user",1,1,1,1
|
||||
|
|
|
|
@ -1,9 +1,7 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright P. Christeas <p_christ@hol.gr> 2008,2009
|
||||
#
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
|
@ -33,15 +31,16 @@ from tools.config import config
|
|||
from DAV.WebDAVServer import DAVRequestHandler
|
||||
from service.websrv_lib import HTTPDir,FixSendError
|
||||
|
||||
class DAVHandler(FixSendError,DAVRequestHandler):
|
||||
|
||||
class DAVHandler(FixSendError, DAVRequestHandler):
|
||||
verbose = False
|
||||
|
||||
def get_userinfo(self,user,pw):
|
||||
|
||||
def get_userinfo(self, user, pw):
|
||||
return False
|
||||
|
||||
def _log(self, message):
|
||||
netsvc.Logger().notifyChannel("webdav",netsvc.LOG_DEBUG,message)
|
||||
|
||||
netsvc.Logger().notifyChannel("webdav", netsvc.LOG_DEBUG, message)
|
||||
|
||||
def handle(self):
|
||||
pass
|
||||
|
||||
|
@ -50,30 +49,30 @@ class DAVHandler(FixSendError,DAVRequestHandler):
|
|||
|
||||
def setup(self):
|
||||
davpath = '/calendar/'
|
||||
self.baseuri = "http://%s:%d%s"% (self.server.server_name,self.server.server_port,davpath)
|
||||
self.baseuri = "http://%s:%d%s"% (self.server.server_name, self.server.server_port, davpath)
|
||||
self.IFACE_CLASS = tinydav_handler(self)
|
||||
pass
|
||||
|
||||
def log_message(self, format, *args):
|
||||
netsvc.Logger().notifyChannel('webdav',netsvc.LOG_DEBUG_RPC,format % args)
|
||||
netsvc.Logger().notifyChannel('webdav', netsvc.LOG_DEBUG_RPC, format % args)
|
||||
|
||||
def log_error(self, format, *args):
|
||||
netsvc.Logger().notifyChannel('webdav',netsvc.LOG_WARNING,format % args)
|
||||
netsvc.Logger().notifyChannel('webdav', netsvc.LOG_WARNING, format % args)
|
||||
|
||||
|
||||
try:
|
||||
from service.http_server import reg_http_service,OpenERPAuthProvider
|
||||
from service.http_server import reg_http_service, OpenERPAuthProvider
|
||||
davpath = '/calendar/'
|
||||
handler = DAVHandler
|
||||
handler.verbose = config.get_misc('webdav','verbose',True)
|
||||
handler.debug = config.get_misc('webdav','debug',True)
|
||||
reg_http_service(HTTPDir(davpath,DAVHandler,OpenERPAuthProvider()))
|
||||
netsvc.Logger().notifyChannel('webdav',netsvc.LOG_INFO,"WebDAV service registered at path: %s/ "% davpath)
|
||||
handler.verbose = config.get_misc('webdav', 'verbose', True)
|
||||
handler.debug = config.get_misc('webdav', 'debug', True)
|
||||
reg_http_service(HTTPDir(davpath, DAVHandler, OpenERPAuthProvider()))
|
||||
netsvc.Logger().notifyChannel('webdav', netsvc.LOG_INFO, "WebDAV service registered at path: %s/ "% davpath)
|
||||
except Exception, e:
|
||||
logger = netsvc.Logger()
|
||||
logger.notifyChannel('webdav', netsvc.LOG_ERROR, 'Cannot launch webdav: %s' % e)
|
||||
|
||||
#eof
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4
|
||||
|
||||
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue