[MERGE] merged with main trunk (revision 9186)
bzr revid: qdp-launchpad@openerp.com-20140228131516-ihigousbe5p1nt68
This commit is contained in:
commit
e36b32a661
|
@ -123,7 +123,9 @@ for a particular financial year and for preparation of vouchers there is a modul
|
|||
'edi/invoice_action_data.xml',
|
||||
'account_bank_view.xml',
|
||||
'res_config_view.xml',
|
||||
'account_pre_install.yml'
|
||||
'account_pre_install.yml',
|
||||
|
||||
'views/report_vat.xml',
|
||||
],
|
||||
'js': [
|
||||
'static/src/js/account_move_reconciliation.js',
|
||||
|
|
|
@ -114,7 +114,7 @@ class account_invoice(osv.osv):
|
|||
#we check if the invoice is partially reconciled and if there are other invoices
|
||||
#involved in this partial reconciliation (and we sum these invoices)
|
||||
for line in aml.reconcile_partial_id.line_partial_ids:
|
||||
if line.invoice:
|
||||
if line.invoice and invoice.type == line.invoice.type:
|
||||
nb_inv_in_partial_rec += 1
|
||||
#store the max invoice id as for this invoice we will make a balance instead of a simple division
|
||||
max_invoice_id = max(max_invoice_id, line.invoice.id)
|
||||
|
|
|
@ -27,13 +27,13 @@
|
|||
<report auto="False" id="account_intracom" menu="False" model="account.move.line" name="account.intracom" string="IntraCom"/>
|
||||
|
||||
<report
|
||||
auto="False"
|
||||
id="account_vat_declaration"
|
||||
menu="False"
|
||||
id="action_report_vat"
|
||||
model="account.tax.code"
|
||||
name="account.vat.declaration"
|
||||
rml="account/report/account_tax_report.rml"
|
||||
string="Taxes Report"/>
|
||||
report_type="qweb-pdf"
|
||||
string="Account tax"
|
||||
name="account.report_vat"
|
||||
file="account.report_vat"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
id="menu_tax_report"
|
||||
|
|
|
@ -588,7 +588,7 @@
|
|||
<field name="partner_id" on_change="onchange_partner_id(partner_id)" domain="[
|
||||
'&',
|
||||
'|',('parent_id','=',False),('is_company','=',True),
|
||||
'|',('customer','=',True),('supplier','=',True)]"/>
|
||||
'|',('customer','=',True),('supplier','=',True)]" context="{'default_supplier': 1}"/>
|
||||
<field name="type" on_change="onchange_type(partner_id, type)"/>
|
||||
<field name="account_id" options='{"no_open":True}' domain="[('journal_id','=',parent.journal_id), ('company_id', '=', parent.company_id)]"/>
|
||||
<field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('company_id', '=', parent.company_id), ('type', '<>', 'view')]"/>
|
||||
|
@ -1451,7 +1451,7 @@
|
|||
<act_window
|
||||
id="act_account_move_to_account_move_line_open"
|
||||
name="Journal Items"
|
||||
context="{'search_default_journal_id': active_id, 'default_journal_id': active_id}"
|
||||
context="{'search_default_move_id': active_id, 'default_move_id': active_id}"
|
||||
res_model="account.move.line"
|
||||
src_model="account.move"/>
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -32,7 +32,7 @@ import account_print_invoice
|
|||
import account_print_overdue
|
||||
import account_aged_partner_balance
|
||||
#import tax_report
|
||||
import account_tax_report
|
||||
import report_vat
|
||||
import account_invoice_report
|
||||
import account_report
|
||||
import account_entries_report
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<document filename="Taxes.pdf">
|
||||
<template title="Taxes" author="OpenERP S.A.(sales@openerp.com)" allowSplitting="20">
|
||||
<pageTemplate id="first">
|
||||
<frame id="first" x1="42.0" y1="62.0" width="511" height="728"/>
|
||||
</pageTemplate>
|
||||
</template>
|
||||
<stylesheet>
|
||||
<blockTableStyle id="Standard_Outline">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<blockValign value="TOP"/>
|
||||
</blockTableStyle>
|
||||
<blockTableStyle id="Table1">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<blockValign value="TOP"/>
|
||||
<blockBackground colorName="#e6e6e6" start="0,0" stop="0,0"/>
|
||||
<blockBackground colorName="#e6e6e6" start="1,0" stop="1,0"/>
|
||||
<blockBackground colorName="#e6e6e6" start="2,0" stop="2,0"/>
|
||||
<blockBackground colorName="#e6e6e6" start="0,1" stop="0,1"/>
|
||||
<blockBackground colorName="#e6e6e6" start="1,1" stop="1,1"/>
|
||||
<blockBackground colorName="#e6e6e6" start="2,1" stop="2,1"/>
|
||||
</blockTableStyle>
|
||||
|
||||
<blockTableStyle id="Table2">
|
||||
<lineStyle kind="LINEBELOW" colorName="#000000" start="0,0" stop="0,0"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#000000" start="1,0" stop="1,0"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#000000" start="2,0" stop="2,0"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#000000" start="3,0" stop="3,0"/>
|
||||
|
||||
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,1" stop="0,-1"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,1" stop="1,-1"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,1" stop="2,-1"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,1" stop="3,-1"/>
|
||||
|
||||
|
||||
<blockValign value="TOP"/>
|
||||
</blockTableStyle>
|
||||
<blockTableStyle id="Table4">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<lineStyle kind="LINEBEFORE" colorName="#cccccc" start="1,0" stop="1,-1"/>
|
||||
</blockTableStyle>
|
||||
<blockTableStyle id="Table3">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<blockValign value="TOP"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="0,0" stop="-1,0"/>
|
||||
<lineStyle kind="LINEBEFORE" colorName="#cccccc" start="0,0" stop="0,-1"/>
|
||||
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="0,0" stop="0,0"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="0,-1" stop="0,-1"/>
|
||||
<lineStyle kind="LINEBEFORE" colorName="#cccccc" start="1,0" stop="1,-1"/>
|
||||
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="1,0" stop="1,0"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="1,-1" stop="1,-1"/>
|
||||
<lineStyle kind="LINEBEFORE" colorName="#cccccc" start="2,0" stop="2,-1"/>
|
||||
<lineStyle kind="LINEAFTER" colorName="#cccccc" start="2,0" stop="2,-1"/>
|
||||
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="2,0" stop="2,0"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="2,-1" stop="2,-1"/>
|
||||
<lineStyle kind="LINEBEFORE" colorName="#cccccc" start="3,0" stop="3,-1"/>
|
||||
<lineStyle kind="LINEAFTER" colorName="#cccccc" start="3,0" stop="3,-1"/>
|
||||
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="3,0" stop="3,0"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="3,-1" stop="3,-1"/>
|
||||
<lineStyle kind="LINEBEFORE" colorName="#cccccc" start="4,0" stop="4,-1"/>
|
||||
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="4,0" stop="4,0"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="4,-1" stop="4,-1"/>
|
||||
<lineStyle kind="LINEBEFORE" colorName="#cccccc" start="5,0" stop="5,-1"/>
|
||||
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="5,0" stop="5,0"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="5,-1" stop="5,-1"/>
|
||||
<lineStyle kind="LINEBEFORE" colorName="#cccccc" start="6,0" stop="6,-1"/>
|
||||
<lineStyle kind="LINEAFTER" colorName="#cccccc" start="6,0" stop="6,-1"/>
|
||||
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="6,0" stop="6,0"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="6,-1" stop="6,-1"/>
|
||||
<lineStyle kind="LINEBEFORE" colorName="#cccccc" start="7,0" stop="7,-1"/>
|
||||
<lineStyle kind="LINEAFTER" colorName="#cccccc" start="7,0" stop="7,-1"/>
|
||||
<lineStyle kind="LINEABOVE" colorName="#cccccc" start="7,0" stop="7,0"/>
|
||||
</blockTableStyle>
|
||||
<blockTableStyle id="Tableau1">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<blockValign value="TOP"/>
|
||||
</blockTableStyle>
|
||||
<blockTableStyle id="Tableau2">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<blockValign value="TOP"/>
|
||||
</blockTableStyle>
|
||||
<initialize>
|
||||
<paraStyle name="all" alignment="justify"/>
|
||||
</initialize>
|
||||
<paraStyle name="P1" fontName="Helvetica-Bold" alignment="CENTER" fontSize="14.5" leftIndent="-5.0"/>
|
||||
<paraStyle name="P2" fontName="Helvetica-bold" fontSize="15.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P3" fontName="Helvetica" fontSize="8.0" leading="10" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P4" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P5" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P6" fontName="Helvetica" fontSize="8.0" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P7" fontName="Helvetica" fontSize="8.0" leading="14" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P8" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P9" fontName="Helvetica" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P9a" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P9c" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P9b" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P10" fontName="Helvetica" alignment="CENTER"/>
|
||||
<paraStyle name="P11" fontName="Helvetica" fontSize="8.0" leading="14"/>
|
||||
<paraStyle name="P12" fontName="Helvetica-bold" fontSize="9.0" leading="10" alignment="LEFT" spaceBefore="0.6" spaceAfter="6.0"/>
|
||||
<paraStyle name="P12a" fontName="Helvetica-bold" fontSize="9.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
|
||||
<paraStyle name="P13" fontName="Helvetica" fontSize="8.0" leading="10" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P14" fontName="Helvetica-Bold" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P15" rightIndent="17.0" leftIndent="-0.0" fontName="Helvetica" fontSize="8.0" leading="10" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P16" fontName="Helvetica-Bold" fontSize="8.0" leading="14" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="Standard" fontName="Helvetica"/>
|
||||
<paraStyle name="Text body" fontName="Helvetica" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="List" fontName="Helvetica" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="Table Contents" fontName="Helvetica" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="Table Heading" fontName="Helvetica" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="Caption" fontName="Helvetica" fontSize="1.0" leading="1" spaceBefore="0" spaceAfter="0"/>
|
||||
<paraStyle name="Index" fontName="Helvetica"/>
|
||||
<paraStyle name="terp_tblheader_General_Centre" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="terp_default_Centre_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
|
||||
|
||||
</stylesheet>
|
||||
<story>
|
||||
<para style="P2">Tax Statement</para>
|
||||
<para style="P2"><font color="white"> </font></para>
|
||||
<blockTable colWidths="140.0,120.0,160.0,120.0" style="Table3">
|
||||
<tr>
|
||||
<td><para style="terp_tblheader_General_Centre">Chart of Tax</para></td>
|
||||
<td><para style="terp_tblheader_General_Centre">Fiscal Year</para></td>
|
||||
<td><para style="terp_tblheader_General_Centre">Periods</para></td>
|
||||
<td><para style="terp_tblheader_General_Centre">Based On</para></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><para style="terp_default_Centre_8">[[ get_account(data) or removeParentNode('para') ]]</para></td>
|
||||
<td><para style="terp_default_Centre_8">[[ get_fiscalyear(data) or '' ]]</para></td>
|
||||
<td>
|
||||
<blockTable colWidths="80.0,80.0" style="Table4">
|
||||
<tr>
|
||||
<td><para style="terp_tblheader_General_Centre">Start Period</para></td>
|
||||
<td><para style="terp_tblheader_General_Centre">End Period</para></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><para style="terp_default_Centre_8">[[ get_start_period(data) or '' ]]</para></td>
|
||||
<td><para style="terp_default_Centre_8">[[ get_end_period(data) or '' ]]</para></td>
|
||||
</tr>
|
||||
</blockTable>
|
||||
</td>
|
||||
<td><para style="terp_default_Centre_8">[[ get_basedon(data) or '' ]]</para></td>
|
||||
</tr>
|
||||
</blockTable>
|
||||
<para style="P2"><font color="white"> </font></para>
|
||||
<blockTable colWidths="340.0,55.0,55.0,90.0" style="Table2" repeatRows="1">
|
||||
<tr>
|
||||
<td><para style="P12">Tax Name</para></td>
|
||||
<td><para style="P12a">Debit</para></td>
|
||||
<td><para style="P12a">Credit</para></td>
|
||||
<td><para style="P12a">Tax Amount</para></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><para style="P5"><font>[[ repeatIn(get_lines(data['form']['based_on'], data['form']['company_id']), 'o') ]]</font><font color="white">[[ (o['level']) ]]</font> <font>[[ (len(o['level'])<5 and setTag('para','para',{'fontName':'Helvetica-Bold'})) or removeParentNode('font') ]]</font><font>[[ o['code'] ]] [[ o['name'] ]] </font></para></td>
|
||||
<td><para style="P6"><font>[[ len(o['level'])<5 and setTag('para','para',{'fontName':"Helvetica-Bold"}) or removeParentNode('font')]]</font><font>[[ o['type']=='view' and removeParentNode('font') ]][[ formatLang(o['debit']) ]]</font><font>[[ o['type']<>'view' and removeParentNode('font') ]][[ formatLang(o['debit']) ]]</font></para></td>
|
||||
<td><para style="P6"><font>[[ len(o['level'])<5 and setTag('para','para',{'fontName':"Helvetica-Bold"}) or removeParentNode('font')]]</font><font>[[ o['type']=='view' and removeParentNode('font') ]][[ formatLang(o['credit']) ]]</font><font>[[ o['type']<>'view' and removeParentNode('font') ]][[ formatLang(o['credit'])]]</font></para></td>
|
||||
<td><para style="P6"><font>[[ len(o['level'])<5 and setTag('para','para',{'fontName':"Helvetica-Bold"}) or removeParentNode('font')]]</font><font>[[ o['type']=='view' and removeParentNode('font') ]][[ formatLang(o['tax_amount'], currency_obj=company.currency_id) ]]</font><font>[[ o['type']<>'view' and removeParentNode('font') ]][[ formatLang(o['tax_amount'], currency_obj=company.currency_id) ]]</font> </para></td>
|
||||
</tr>
|
||||
</blockTable>
|
||||
</story>
|
||||
</document>
|
|
@ -19,16 +19,25 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from common_report_header import common_report_header
|
||||
from openerp.report import report_sxw
|
||||
try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO
|
||||
import xlwt
|
||||
|
||||
class tax_report(report_sxw.rml_parse, common_report_header):
|
||||
_name = 'report.account.vat.declaration'
|
||||
|
||||
def set_context(self, objects, data, ids, report_type=None):
|
||||
new_ids = ids
|
||||
class tax_report(http.Controller, common_report_header):
|
||||
|
||||
@http.route(['/report/account.report_vat'], type='http', auth='user', website=True, multilang=True)
|
||||
def report_account_tax(self, **data):
|
||||
report_obj = request.registry['report']
|
||||
self.cr, self.uid, self.pool = request.cr, request.uid, request.registry
|
||||
|
||||
data = report_obj.eval_params(data)
|
||||
|
||||
res = {}
|
||||
self.period_ids = []
|
||||
period_obj = self.pool.get('account.period')
|
||||
|
@ -38,28 +47,16 @@ class tax_report(report_sxw.rml_parse, common_report_header):
|
|||
|
||||
if data['form'].get('period_from', False) and data['form'].get('period_to', False):
|
||||
self.period_ids = period_obj.build_ctx_periods(self.cr, self.uid, data['form']['period_from'], data['form']['period_to'])
|
||||
periods_l = period_obj.read(self.cr, self.uid, self.period_ids, ['name'])
|
||||
for period in periods_l:
|
||||
if res['periods'] == '':
|
||||
res['periods'] = period['name']
|
||||
else:
|
||||
res['periods'] += ", "+ period['name']
|
||||
return super(tax_report, self).set_context(objects, data, new_ids, report_type=report_type)
|
||||
|
||||
def __init__(self, cr, uid, name, context=None):
|
||||
super(tax_report, self).__init__(cr, uid, name, context=context)
|
||||
self.localcontext.update({
|
||||
'time': time,
|
||||
'get_codes': self._get_codes,
|
||||
'get_general': self._get_general,
|
||||
'get_currency': self._get_currency,
|
||||
'get_lines': self._get_lines,
|
||||
'get_fiscalyear': self._get_fiscalyear,
|
||||
'get_account': self._get_account,
|
||||
'get_start_period': self.get_start_period,
|
||||
'get_end_period': self.get_end_period,
|
||||
'get_basedon': self._get_basedon,
|
||||
})
|
||||
docargs = {
|
||||
'fiscalyear': self._get_fiscalyear(data),
|
||||
'account': self._get_account(data),
|
||||
'based_on': self._get_basedon(data),
|
||||
'period_from': self.get_start_period(data),
|
||||
'period_to': self.get_end_period(data),
|
||||
'taxlines': self._get_lines(self._get_basedon(data), company_id=data['form']['company_id']),
|
||||
}
|
||||
return request.registry['report'].render(self.cr, self.uid, [], 'account.report_vat', docargs)
|
||||
|
||||
def _get_basedon(self, form):
|
||||
return form['form']['based_on']
|
||||
|
@ -194,7 +191,6 @@ class tax_report(report_sxw.rml_parse, common_report_header):
|
|||
return self.pool.get('res.company').browse(self.cr, self.uid, form['company_id'], context=context).currency_id.name
|
||||
|
||||
def sort_result(self, accounts, context=None):
|
||||
# On boucle sur notre rapport
|
||||
result_accounts = []
|
||||
ind=0
|
||||
old_level=0
|
||||
|
@ -233,7 +229,43 @@ class tax_report(report_sxw.rml_parse, common_report_header):
|
|||
|
||||
return result_accounts
|
||||
|
||||
report_sxw.report_sxw('report.account.vat.declaration', 'account.tax.code',
|
||||
'addons/account/report/account_tax_report.rml', parser=tax_report, header="internal")
|
||||
@http.route(['/report/account.report_vat_xls'], type='http', auth='user', website=True, multilang=True)
|
||||
def report_account_tax_xls(self, **data):
|
||||
report_obj = request.registry['report']
|
||||
self.cr, self.uid, self.pool = request.cr, request.uid, request.registry
|
||||
|
||||
data = report_obj.eval_params(data)
|
||||
|
||||
res = {}
|
||||
self.period_ids = []
|
||||
period_obj = self.pool.get('account.period')
|
||||
self.display_detail = data['form']['display_detail']
|
||||
res['periods'] = ''
|
||||
res['fiscalyear'] = data['form'].get('fiscalyear_id', False)
|
||||
|
||||
if data['form'].get('period_from', False) and data['form'].get('period_to', False):
|
||||
self.period_ids = period_obj.build_ctx_periods(self.cr, self.uid, data['form']['period_from'], data['form']['period_to'])
|
||||
|
||||
content = ''
|
||||
lines = self._get_lines(self._get_basedon(data), company_id=data['form']['company_id'])
|
||||
|
||||
if lines:
|
||||
xls = StringIO.StringIO()
|
||||
xls_workbook = xlwt.Workbook()
|
||||
vat_sheet = xls_workbook.add_sheet('report_vat')
|
||||
|
||||
for x in range(0, len(lines)):
|
||||
for y in range(0, len(lines[0])):
|
||||
vat_sheet.write(x, y, lines[x].values()[y])
|
||||
|
||||
xls_workbook.save(xls)
|
||||
xls.seek(0)
|
||||
content = xls.read()
|
||||
|
||||
response = request.make_response(content, headers=[
|
||||
('Content-Type', 'application/vnd.ms-excel'),
|
||||
('Content-Disposition', 'attachment; filename=report_vat.xls;')
|
||||
])
|
||||
return response
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -22,6 +22,7 @@ openerp.account.quickadd = function (instance) {
|
|||
start:function(){
|
||||
var tmp = this._super.apply(this, arguments);
|
||||
var self = this;
|
||||
var defs = [];
|
||||
this.$el.parent().prepend(QWeb.render("AccountMoveLineQuickAdd", {widget: this}));
|
||||
|
||||
this.$el.parent().find('.oe_account_select_journal').change(function() {
|
||||
|
@ -41,11 +42,17 @@ openerp.account.quickadd = function (instance) {
|
|||
self.$el.parent().find('.oe_account_select_period').removeAttr('disabled');
|
||||
});
|
||||
var mod = new instance.web.Model("account.move.line", self.dataset.context, self.dataset.domain);
|
||||
mod.call("default_get", [['journal_id','period_id'],self.dataset.context]).then(function(result) {
|
||||
defs.push(mod.call("default_get", [['journal_id','period_id'],self.dataset.context]).then(function(result) {
|
||||
self.current_period = result['period_id'];
|
||||
self.current_journal = result['journal_id'];
|
||||
});
|
||||
return tmp;
|
||||
}));
|
||||
defs.push(mod.call("list_journals", []).then(function(result) {
|
||||
self.journals = result;
|
||||
}));
|
||||
defs.push(mod.call("list_periods", []).then(function(result) {
|
||||
self.periods = result;
|
||||
}));
|
||||
return $.when(tmp, defs);
|
||||
},
|
||||
do_search: function(domain, context, group_by) {
|
||||
var self = this;
|
||||
|
@ -53,12 +60,6 @@ openerp.account.quickadd = function (instance) {
|
|||
this.last_context = context;
|
||||
this.last_group_by = group_by;
|
||||
this.old_search = _.bind(this._super, this);
|
||||
var mod = new instance.web.Model("account.move.line", context, domain);
|
||||
return $.when(mod.call("list_journals", []).then(function(result) {
|
||||
self.journals = result;
|
||||
}),mod.call("list_periods", []).then(function(result) {
|
||||
self.periods = result;
|
||||
})).then(function () {
|
||||
var o;
|
||||
self.$el.parent().find('.oe_account_select_journal').children().remove().end();
|
||||
self.$el.parent().find('.oe_account_select_journal').append(new Option('', ''));
|
||||
|
@ -80,7 +81,6 @@ openerp.account.quickadd = function (instance) {
|
|||
}
|
||||
self.$el.parent().find('.oe_account_select_period').val(self.current_period).attr('selected',true);
|
||||
return self.search_by_journal_period();
|
||||
});
|
||||
},
|
||||
search_by_journal_period: function() {
|
||||
var self = this;
|
||||
|
@ -93,7 +93,9 @@ openerp.account.quickadd = function (instance) {
|
|||
self.last_context["journal_type"] = self.current_journal_type;
|
||||
self.last_context["currency"] = self.current_journal_currency;
|
||||
self.last_context["analytic_journal_id"] = self.current_journal_analytic;
|
||||
return self.old_search(new instance.web.CompoundDomain(self.last_domain, domain), self.last_context, self.last_group_by);
|
||||
var compound_domain = new instance.web.CompoundDomain(self.last_domain, domain);
|
||||
self.dataset.domain = compound_domain.eval();
|
||||
return self.old_search(compound_domain, self.last_context, self.last_group_by);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<template id="report_vat">
|
||||
<t t-call="report.html_container">
|
||||
<t t-call="report.internal_layout">
|
||||
<div class="page">
|
||||
<h2>Tax Statement</h2>
|
||||
|
||||
<div class="row mt32 mb32">
|
||||
<div class="col-xs-3">
|
||||
<strong>Chart of Tax:</strong>
|
||||
<p t-esc="account"/>
|
||||
</div>
|
||||
<div class="col-xs-3" t-if="fiscalyear">
|
||||
<strong>Fiscal Year:</strong>
|
||||
<p t-esc="fiscalyear"/>
|
||||
</div>
|
||||
<div class="col-xs-3" t-if="period_from and period_to">
|
||||
<strong>Periods:</strong>
|
||||
<p>
|
||||
Start Period: <span t-esc="period_from"/><br/>
|
||||
End Period: <span t-esc="period_to"/>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<strong>Based On:</strong>
|
||||
<p t-esc="based_on"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tax Name</th>
|
||||
<th class="text-right">Debit</th>
|
||||
<th class="text-right">Credit</th>
|
||||
<th class="text-right">Tax Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr t-foreach="taxlines" t-as="taxline">
|
||||
<t t-if="len(taxline['level']) > 5">
|
||||
<t t-set="style" t-value="'font-weight:normal;'"/>
|
||||
</t>
|
||||
<t t-if="not len(taxline['level']) > 5">
|
||||
<t t-set="style" t-value="'font-weight:bold;'"/>
|
||||
</t>
|
||||
|
||||
<td>
|
||||
<span t-att-style="style" t-esc="taxline['level']" style="color:white;"/>
|
||||
<span t-att-style="style" t-if="taxline['code']" t-esc="taxline['code']"/>
|
||||
<span t-att-style="style" t-esc="taxline['name']"/>
|
||||
</td>
|
||||
<td class="text-right"><span t-att-style="style" t-esc="taxline['debit']"/></td>
|
||||
<td class="text-right"><span t-att-style="style" t-esc="taxline['credit']"/></td>
|
||||
<td class="text-right">
|
||||
<span t-att-style="style" t-esc="formatLang(taxline['tax_amount'], currency_obj=res_company.currency_id)"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</data>
|
||||
</openerp>
|
|
@ -46,18 +46,20 @@ class account_vat_declaration(osv.osv_memory):
|
|||
def create_vat(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
datas = {'ids': context.get('active_ids', [])}
|
||||
datas['model'] = 'account.tax.code'
|
||||
datas['form'] = self.read(cr, uid, ids, context=context)[0]
|
||||
|
||||
for field in datas['form'].keys():
|
||||
if isinstance(datas['form'][field], tuple):
|
||||
datas['form'][field] = datas['form'][field][0]
|
||||
datas['form']['company_id'] = self.pool.get('account.tax.code').browse(cr, uid, [datas['form']['chart_tax_id']], context=context)[0].company_id.id
|
||||
return {
|
||||
'type': 'ir.actions.report.xml',
|
||||
'report_name': 'account.vat.declaration',
|
||||
'datas': datas,
|
||||
}
|
||||
|
||||
taxcode_obj = self.pool.get('account.tax.code')
|
||||
taxcode_id = datas['form']['chart_tax_id']
|
||||
taxcode = taxcode_obj.browse(cr, uid, [taxcode_id], context=context)[0]
|
||||
datas['form']['company_id'] = taxcode.company_id.id
|
||||
|
||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_vat', datas=datas, context=context)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -664,13 +664,20 @@ class account_analytic_account(osv.osv):
|
|||
|
||||
partner_payment_term = contract.partner_id.property_payment_term and contract.partner_id.property_payment_term.id or False
|
||||
|
||||
currency_id = False
|
||||
if contract.pricelist_id:
|
||||
currency_id = contract.pricelist_id.currency_id.id
|
||||
elif contract.partner_id.property_product_pricelist:
|
||||
currency_id = contract.partner_id.property_product_pricelist.currency_id.id
|
||||
elif contract.company_id:
|
||||
currency_id = contract.company_id.currency_id.id
|
||||
|
||||
inv_data = {
|
||||
'reference': contract.code or False,
|
||||
'account_id': contract.partner_id.property_account_receivable.id,
|
||||
'type': 'out_invoice',
|
||||
'partner_id': contract.partner_id.id,
|
||||
'currency_id': contract.partner_id.property_product_pricelist.id or False,
|
||||
'currency_id': currency_id,
|
||||
'journal_id': len(journal_ids) and journal_ids[0] or False,
|
||||
'date_invoice': contract.recurring_next_date,
|
||||
'origin': contract.name,
|
||||
|
|
|
@ -8,19 +8,19 @@ msgstr ""
|
|||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2010-09-29 11:28+0000\n"
|
||||
"Last-Translator: OpenERP Administrators <Unknown>\n"
|
||||
"PO-Revision-Date: 2014-02-18 16:35+0000\n"
|
||||
"Last-Translator: Boško Stojaković <bluesoft83@gmail.com>\n"
|
||||
"Language-Team: Bosnian <bs@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:28+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
"X-Launchpad-Export-Date: 2014-02-19 05:23+0000\n"
|
||||
"X-Generator: Launchpad (build 16916)\n"
|
||||
|
||||
#. module: account_cancel
|
||||
#: view:account.invoice:0
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
msgstr "Otkaži"
|
||||
|
||||
#~ msgid "Account Cancel"
|
||||
#~ msgstr "Računovodstvo - povrat"
|
||||
|
|
|
@ -8,14 +8,14 @@ msgstr ""
|
|||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2011-11-11 15:21+0000\n"
|
||||
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
|
||||
"PO-Revision-Date: 2014-02-16 20:38+0000\n"
|
||||
"Last-Translator: Harri Luuppala <Unknown>\n"
|
||||
"Language-Team: Finnish <fi@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 05:51+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
"X-Launchpad-Export-Date: 2014-02-17 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 16916)\n"
|
||||
|
||||
#. module: account_followup
|
||||
#: model:email.template,subject:account_followup.email_template_account_followup_default
|
||||
|
@ -55,12 +55,12 @@ msgstr ""
|
|||
#: view:account_followup.followup.line:0
|
||||
#: field:account_followup.followup.line,manual_action:0
|
||||
msgid "Manual Action"
|
||||
msgstr ""
|
||||
msgstr "Manuaalinen toimenpide"
|
||||
|
||||
#. module: account_followup
|
||||
#: field:account_followup.sending.results,needprinting:0
|
||||
msgid "Needs Printing"
|
||||
msgstr ""
|
||||
msgstr "Odottaa tulostusta"
|
||||
|
||||
#. module: account_followup
|
||||
#: view:res.partner:0
|
||||
|
|
|
@ -911,6 +911,7 @@ class account_voucher(osv.osv):
|
|||
if context.get('payment_expected_currency') and currency_id != context.get('payment_expected_currency'):
|
||||
vals['value']['amount'] = 0
|
||||
amount = 0
|
||||
if partner_id:
|
||||
res = self.onchange_partner_id(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context)
|
||||
for key in res.keys():
|
||||
vals[key].update(res[key])
|
||||
|
@ -965,7 +966,7 @@ class account_voucher(osv.osv):
|
|||
res = {}
|
||||
if not partner_id:
|
||||
return res
|
||||
res = {'account_id':False}
|
||||
res = {}
|
||||
partner_pool = self.pool.get('res.partner')
|
||||
journal_pool = self.pool.get('account.journal')
|
||||
if pay_now == 'pay_later':
|
||||
|
@ -977,6 +978,7 @@ class account_voucher(osv.osv):
|
|||
account_id = partner.property_account_payable.id
|
||||
else:
|
||||
account_id = journal.default_credit_account_id.id or journal.default_debit_account_id.id
|
||||
if account_id:
|
||||
res['account_id'] = account_id
|
||||
return {'value':res}
|
||||
|
||||
|
@ -1366,6 +1368,7 @@ class account_voucher(osv.osv):
|
|||
move_pool = self.pool.get('account.move')
|
||||
move_line_pool = self.pool.get('account.move.line')
|
||||
for voucher in self.browse(cr, uid, ids, context=context):
|
||||
local_context = dict(context, force_company=voucher.journal_id.company_id.id)
|
||||
if voucher.move_id:
|
||||
continue
|
||||
company_currency = self._get_company_currency(cr, uid, voucher.id, context)
|
||||
|
@ -1380,7 +1383,7 @@ class account_voucher(osv.osv):
|
|||
# Get the name of the account_move just created
|
||||
name = move_pool.browse(cr, uid, move_id, context=context).name
|
||||
# Create the first line of the voucher
|
||||
move_line_id = move_line_pool.create(cr, uid, self.first_move_line_get(cr,uid,voucher.id, move_id, company_currency, current_currency, context), context)
|
||||
move_line_id = move_line_pool.create(cr, uid, self.first_move_line_get(cr,uid,voucher.id, move_id, company_currency, current_currency, local_context), local_context)
|
||||
move_line_brw = move_line_pool.browse(cr, uid, move_line_id, context=context)
|
||||
line_total = move_line_brw.debit - move_line_brw.credit
|
||||
rec_list_ids = []
|
||||
|
@ -1392,9 +1395,9 @@ class account_voucher(osv.osv):
|
|||
line_total, rec_list_ids = self.voucher_move_line_create(cr, uid, voucher.id, line_total, move_id, company_currency, current_currency, context)
|
||||
|
||||
# Create the writeoff line if needed
|
||||
ml_writeoff = self.writeoff_move_line_get(cr, uid, voucher.id, line_total, move_id, name, company_currency, current_currency, context)
|
||||
ml_writeoff = self.writeoff_move_line_get(cr, uid, voucher.id, line_total, move_id, name, company_currency, current_currency, local_context)
|
||||
if ml_writeoff:
|
||||
move_line_pool.create(cr, uid, ml_writeoff, context)
|
||||
move_line_pool.create(cr, uid, ml_writeoff, local_context)
|
||||
# We post the voucher.
|
||||
self.write(cr, uid, [voucher.id], {
|
||||
'move_id': move_id,
|
||||
|
@ -1605,7 +1608,11 @@ class account_bank_statement(osv.osv):
|
|||
bank_st_line_obj = self.pool.get('account.bank.statement.line')
|
||||
st_line = bank_st_line_obj.browse(cr, uid, st_line_id, context=context)
|
||||
if st_line.voucher_id:
|
||||
voucher_obj.write(cr, uid, [st_line.voucher_id.id], {'number': next_number}, context=context)
|
||||
voucher_obj.write(cr, uid, [st_line.voucher_id.id],
|
||||
{'number': next_number,
|
||||
'date': st_line.date,
|
||||
'period_id': st_line.statement_id.period_id.id},
|
||||
context=context)
|
||||
if st_line.voucher_id.state == 'cancel':
|
||||
voucher_obj.action_cancel_draft(cr, uid, [st_line.voucher_id.id], context=context)
|
||||
voucher_obj.signal_proforma_voucher(cr, uid, [st_line.voucher_id.id])
|
||||
|
|
|
@ -73,8 +73,14 @@
|
|||
<group>
|
||||
<group>
|
||||
<field name="type" invisible="True"/>
|
||||
<field name="partner_id" domain="[('customer','=',True)]" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" string="Customer" context="{'search_default_customer':1, 'show_address': 1}" options='{"always_reload": True}'/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
<field name="partner_id" domain="[('customer','=',True)]" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" string="Customer" context="{'search_default_customer':1, 'show_address': 1}" options='{"always_reload": True}'/>
|
||||
<field name="account_id"
|
||||
domain="[('type','in', ['liquidity', 'receivable'])]"/>
|
||||
<field name="pay_now" on_change="onchange_payment(pay_now, journal_id, partner_id)" required="1"/>
|
||||
<field name="date_due" attrs="{'invisible':[('pay_now','=','pay_now')]}"/>
|
||||
<field name="reference"
|
||||
attrs="{'invisible':[('pay_now','!=','pay_now')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="journal_id" domain="[('type','in',['sale','sale_refund'])]" widget="selection" on_change="onchange_journal(journal_id, line_cr_ids, tax_id, partner_id, date, amount, type, company_id, context)" groups="account.group_account_user"/>
|
||||
|
@ -111,15 +117,6 @@
|
|||
attrs="{'invisible': [('state','!=','draft')]}"/>
|
||||
</div>
|
||||
<field name="amount" class="oe_subtotal_footer_separator" nolabel="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="pay_now" on_change="onchange_payment(pay_now, journal_id, partner_id)" required="1"/>
|
||||
<field name="date_due" attrs="{'invisible':[('pay_now','=','pay_now')]}"/>
|
||||
<field name="account_id"
|
||||
attrs="{'invisible':[('pay_now','!=','pay_now')]}"
|
||||
domain="[('type','=','liquidity')]"/>
|
||||
<field name="reference"
|
||||
attrs="{'invisible':[('pay_now','!=','pay_now')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
@ -224,11 +221,11 @@
|
|||
<h1><label for="number" string="Purchase Receipt"/> <field name="number" class="oe_inline" readonly="1"/></h1>
|
||||
|
||||
<field name="pay_now" invisible="1"/>
|
||||
<field name="account_id" domain="[('type','=','other')]" invisible="True"/>
|
||||
<field name="type" invisible="True"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_id" domain="[('supplier','=',True)]" string="Supplier" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}" />
|
||||
<field name="account_id" domain="[('type', 'in', ['liquidity', 'payable'])]"/>
|
||||
<field name="name" colspan="2"/>
|
||||
<field name="reference"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
|
|
|
@ -94,7 +94,7 @@ class account_statement_from_invoice_lines(osv.osv_memory):
|
|||
'account_id': result['value'].get('account_id', statement.journal_id.default_credit_account_id.id),
|
||||
'company_id': statement.company_id.id,
|
||||
'currency_id': statement.currency.id,
|
||||
'date': line.date,
|
||||
'date': statement.date,
|
||||
'amount': sign*amount,
|
||||
'payment_rate': result['value']['payment_rate'],
|
||||
'payment_rate_currency_id': result['value']['payment_rate_currency_id'],
|
||||
|
@ -119,7 +119,7 @@ class account_statement_from_invoice_lines(osv.osv_memory):
|
|||
'statement_id': statement_id,
|
||||
'ref': line.ref,
|
||||
'voucher_id': voucher_id,
|
||||
'date': time.strftime('%Y-%m-%d'),
|
||||
'date': statement.date,
|
||||
}, context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
# Japanese translation for openobject-addons
|
||||
# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2014-02-21 02:29+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Japanese <ja@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-02-22 06:39+0000\n"
|
||||
"X-Generator: Launchpad (build 16926)\n"
|
||||
|
||||
#. module: analytic_contract_hr_expense
|
||||
#: view:account.analytic.account:0
|
||||
msgid "or view"
|
||||
msgstr "または参照"
|
||||
|
||||
#. module: analytic_contract_hr_expense
|
||||
#: view:account.analytic.account:0
|
||||
msgid "Nothing to invoice, create"
|
||||
msgstr ""
|
||||
|
||||
#. module: analytic_contract_hr_expense
|
||||
#: view:account.analytic.account:0
|
||||
msgid "expenses"
|
||||
msgstr "経費"
|
||||
|
||||
#. module: analytic_contract_hr_expense
|
||||
#: model:ir.model,name:analytic_contract_hr_expense.model_account_analytic_account
|
||||
msgid "Analytic Account"
|
||||
msgstr "分析勘定"
|
||||
|
||||
#. module: analytic_contract_hr_expense
|
||||
#: code:addons/analytic_contract_hr_expense/analytic_contract_hr_expense.py:144
|
||||
#, python-format
|
||||
msgid "Expenses to Invoice of %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: analytic_contract_hr_expense
|
||||
#: code:addons/analytic_contract_hr_expense/analytic_contract_hr_expense.py:136
|
||||
#, python-format
|
||||
msgid "Expenses of %s"
|
||||
msgstr "%sの経費"
|
||||
|
||||
#. module: analytic_contract_hr_expense
|
||||
#: field:account.analytic.account,expense_invoiced:0
|
||||
#: field:account.analytic.account,expense_to_invoice:0
|
||||
#: field:account.analytic.account,remaining_expense:0
|
||||
msgid "unknown"
|
||||
msgstr "不明"
|
||||
|
||||
#. module: analytic_contract_hr_expense
|
||||
#: field:account.analytic.account,est_expenses:0
|
||||
msgid "Estimation of Expenses to Invoice"
|
||||
msgstr "請求対象経費見込"
|
||||
|
||||
#. module: analytic_contract_hr_expense
|
||||
#: field:account.analytic.account,charge_expenses:0
|
||||
msgid "Charge Expenses"
|
||||
msgstr "経費請求"
|
||||
|
||||
#. module: analytic_contract_hr_expense
|
||||
#: view:account.analytic.account:0
|
||||
msgid "⇒ Invoice"
|
||||
msgstr "⇒ 請求"
|
|
@ -268,10 +268,14 @@ def log_fct(cr, uid_orig, model, method, fct_src, *args, **kw):
|
|||
new_values = get_data(cr, uid_orig, pool, res_ids, model, method)
|
||||
elif method == 'read':
|
||||
res = fct_src(cr, uid_orig, model.model, method, *args, **kw)
|
||||
if isinstance(res, dict):
|
||||
records = [res]
|
||||
else:
|
||||
records = res
|
||||
# build the res_ids and the old_values dict. Here we don't use get_data() to
|
||||
# avoid performing an additional read()
|
||||
res_ids = []
|
||||
for record in res:
|
||||
for record in records:
|
||||
res_ids.append(record['id'])
|
||||
old_values[(model.id, record['id'])] = {'value': record, 'text': record}
|
||||
# log only the fields read
|
||||
|
@ -279,7 +283,9 @@ def log_fct(cr, uid_orig, model, method, fct_src, *args, **kw):
|
|||
elif method == 'unlink':
|
||||
res_ids = args[0]
|
||||
old_values = get_data(cr, uid_orig, pool, res_ids, model, method)
|
||||
res = fct_src(cr, uid_orig, model.model, method, *args, **kw)
|
||||
# process_data first as fct_src will unlink the record
|
||||
self.process_data(cr, uid_orig, pool, res_ids, model, method, old_values, new_values, field_list)
|
||||
return fct_src(cr, uid_orig, model.model, method, *args, **kw)
|
||||
else: # method is write, action or workflow action
|
||||
res_ids = []
|
||||
if args:
|
||||
|
@ -322,7 +328,7 @@ def get_data(cr, uid, pool, res_ids, model, method):
|
|||
data = {}
|
||||
resource_pool = pool[model.model]
|
||||
# read all the fields of the given resources in super admin mode
|
||||
for resource in resource_pool.read(cr, SUPERUSER_ID, res_ids):
|
||||
for resource in resource_pool.read(cr, SUPERUSER_ID, res_ids, resource_pool._all_columns):
|
||||
values = {}
|
||||
values_text = {}
|
||||
resource_id = resource['id']
|
||||
|
@ -456,7 +462,9 @@ def process_data(cr, uid, pool, res_ids, model, method, old_values=None, new_val
|
|||
|
||||
# if at least one modification has been found
|
||||
for model_id, resource_id in lines:
|
||||
name = pool[model.model].name_get(cr, uid, [resource_id])[0][1]
|
||||
line_model = pool.get('ir.model').browse(cr, SUPERUSER_ID, model_id).model
|
||||
name = pool.get(line_model).name_get(cr, uid, [resource_id])[0][1]
|
||||
|
||||
vals = {
|
||||
'method': method,
|
||||
'object_id': model_id,
|
||||
|
|
|
@ -31,7 +31,7 @@ Allow users to login through OAuth2 Provider.
|
|||
'author': 'OpenERP s.a.',
|
||||
'maintainer': 'OpenERP s.a.',
|
||||
'website': 'http://www.openerp.com',
|
||||
'depends': ['base', 'web', 'base_setup'],
|
||||
'depends': ['base', 'web', 'base_setup', 'auth_signup'],
|
||||
'data': [
|
||||
'res_users.xml',
|
||||
'auth_oauth_data.xml',
|
||||
|
|
|
@ -8,8 +8,8 @@ from werkzeug.exceptions import BadRequest
|
|||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp import http
|
||||
from openerp.http import request, LazyResponse
|
||||
from openerp.addons.web.controllers.main import db_monodb, set_cookie_and_redirect, login_and_redirect
|
||||
from openerp.http import request
|
||||
from openerp.addons.web.controllers.main import db_monodb, ensure_db, set_cookie_and_redirect, login_and_redirect
|
||||
from openerp.modules.registry import RegistryManager
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
@ -25,7 +25,7 @@ def fragment_to_query_string(func):
|
|||
return """<html><head><script>
|
||||
var l = window.location;
|
||||
var q = l.hash.substring(1);
|
||||
var r = '/' + l.search;
|
||||
var r = l.pathname + l.search;
|
||||
if(q.length !== 0) {
|
||||
var s = l.search ? (l.search === '?' ? '' : '&') : '?';
|
||||
r = l.pathname + l.search + s + q;
|
||||
|
@ -61,17 +61,22 @@ class OAuthLogin(openerp.addons.web.controllers.main.Home):
|
|||
return providers
|
||||
|
||||
def get_state(self, provider):
|
||||
return dict(
|
||||
state = dict(
|
||||
d=request.session.db,
|
||||
p=provider['id']
|
||||
)
|
||||
token = request.params.get('token')
|
||||
if token:
|
||||
state['t'] = token
|
||||
return state
|
||||
|
||||
@http.route()
|
||||
def web_login(self, *args, **kw):
|
||||
ensure_db()
|
||||
providers = self.list_providers()
|
||||
|
||||
response = super(OAuthLogin, self).web_login(*args, **kw)
|
||||
if isinstance(response, LazyResponse):
|
||||
if response.is_qweb:
|
||||
error = request.params.get('oauth_error')
|
||||
if error == '1':
|
||||
error = _("Sign up is not allowed on this database.")
|
||||
|
@ -82,12 +87,30 @@ class OAuthLogin(openerp.addons.web.controllers.main.Home):
|
|||
else:
|
||||
error = None
|
||||
|
||||
response.params['values']['providers'] = providers
|
||||
response.qcontext['providers'] = providers
|
||||
if error:
|
||||
response.params['values']['error'] = error
|
||||
response.qcontext['error'] = error
|
||||
|
||||
return response
|
||||
|
||||
@http.route()
|
||||
def web_auth_signup(self, *args, **kw):
|
||||
providers = self.list_providers()
|
||||
if len(providers) == 1:
|
||||
werkzeug.exceptions.abort(werkzeug.utils.redirect(providers[0]['auth_link'], 303))
|
||||
response = super(OAuthLogin, self).web_auth_signup(*args, **kw)
|
||||
response.qcontext.update(providers=providers)
|
||||
return response
|
||||
|
||||
@http.route()
|
||||
def web_auth_reset_password(self, *args, **kw):
|
||||
providers = self.list_providers()
|
||||
if len(providers) == 1:
|
||||
werkzeug.exceptions.abort(werkzeug.utils.redirect(providers[0]['auth_link'], 303))
|
||||
response = super(OAuthLogin, self).web_auth_reset_password(*args, **kw)
|
||||
response.qcontext.update(providers=providers)
|
||||
return response
|
||||
|
||||
class OAuthController(http.Controller):
|
||||
|
||||
@http.route('/auth_oauth/signin', type='http', auth='none')
|
||||
|
|
|
@ -3,15 +3,35 @@
|
|||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
<template id="auth_oauth.login" inherit_id="web.login" name="OAuth Login buttons">
|
||||
<xpath expr="//button[@type='submit']" position="before">
|
||||
<div class="pull-right">
|
||||
<template id="auth_oauth.providers" name="OAuth Providers">
|
||||
<div t-foreach="providers" t-as="p">
|
||||
<a t-att-href="p['auth_link']" class="btn btn-link">
|
||||
<i t-att-class="p['css_class']"/>
|
||||
<t t-esc="p['body']"/>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="auth_oauth.login" inherit_id="web.login" name="OAuth Login buttons">
|
||||
<xpath expr="//button[@type='submit']" position="before">
|
||||
<div class="pull-right">
|
||||
<t t-call="auth_oauth.providers"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="auth_oauth.signup" inherit_id="auth_signup.signup" name="OAuth Signup buttons">
|
||||
<xpath expr="//button[@type='submit']" position="before">
|
||||
<div class="pull-right">
|
||||
<t t-call="auth_oauth.providers"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="auth_oauth.reset_password" inherit_id="auth_signup.reset_password" name="OAuth Reset Password buttons">
|
||||
<xpath expr="//button[@type='submit']" position="before">
|
||||
<div class="pull-right">
|
||||
<t t-call="auth_oauth.providers"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2012-today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import res_users
|
||||
import controllers
|
|
@ -1,41 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2010-2014 OpenERP SA (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Signup with OAuth2 Authentication',
|
||||
'version': '1.0',
|
||||
'category': 'Hidden',
|
||||
'description': """
|
||||
Allow users to sign up through OAuth2 Provider.
|
||||
===============================================
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'website': 'http://www.openerp.com',
|
||||
'depends': ['auth_oauth', 'auth_signup'],
|
||||
'data': [
|
||||
'views/auth_oauth_signup.xml',
|
||||
],
|
||||
'js': [],
|
||||
'css': [],
|
||||
'qweb': [],
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
import main
|
||||
|
||||
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,20 +0,0 @@
|
|||
import openerp
|
||||
import werkzeug
|
||||
|
||||
from openerp.http import request
|
||||
|
||||
class OAuthSignupLogin(openerp.addons.web.controllers.main.Home):
|
||||
def list_providers(self):
|
||||
providers = super(OAuthSignupLogin, self).list_providers()
|
||||
if len(providers) == 1 and request.params.get('mode') == 'signup':
|
||||
werkzeug.exceptions.abort(werkzeug.utils.redirect(providers[0]['auth_link'], 303))
|
||||
return providers
|
||||
|
||||
def get_state(self, provider):
|
||||
state = super(OAuthSignupLogin, self).get_state(provider)
|
||||
token = request.params.get('token')
|
||||
if token:
|
||||
state['t'] = token
|
||||
return state
|
||||
|
||||
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,23 +0,0 @@
|
|||
# Arabic translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-11-26 18:16+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Arabic <ar@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "المستخدمين"
|
|
@ -1,22 +0,0 @@
|
|||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * auth_oauth_signup
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0alpha\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2012-12-21 17:05+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
# Czech translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2014-02-03 16:54+0000\n"
|
||||
"Last-Translator: Jakub Drozd <Unknown>\n"
|
||||
"Language-Team: Czech <cs@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-02-04 05:51+0000\n"
|
||||
"X-Generator: Launchpad (build 16916)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Uživatelé"
|
|
@ -1,23 +0,0 @@
|
|||
# Danish translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-09-15 20:08+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Danish <da@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Bruger"
|
|
@ -1,23 +0,0 @@
|
|||
# German translation for openobject-addons
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2012-12-27 22:22+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: German <de@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Benutzer"
|
|
@ -1,23 +0,0 @@
|
|||
# English (United Kingdom) translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-02-06 14:33+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: English (United Kingdom) <en_GB@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Users"
|
|
@ -1,23 +0,0 @@
|
|||
# Spanish translation for openobject-addons
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2012-12-27 11:38+0000\n"
|
||||
"Last-Translator: Pedro Manuel Baeza <pedro.baeza@gmail.com>\n"
|
||||
"Language-Team: Spanish <es@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Usuarios"
|
|
@ -1,23 +0,0 @@
|
|||
# Estonian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-10-09 14:34+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Estonian <et@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Kasutajad"
|
|
@ -1,23 +0,0 @@
|
|||
# French translation for openobject-addons
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2012-12-29 16:08+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: French <fr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Utilisateurs"
|
|
@ -1,23 +0,0 @@
|
|||
# Galician translation for openobject-addons
|
||||
# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2014-02-05 16:37+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Galician <gl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-02-06 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 16916)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Usuarios"
|
|
@ -1,23 +0,0 @@
|
|||
# Croatian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-01-24 12:30+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Croatian <hr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Korisnici"
|
|
@ -1,23 +0,0 @@
|
|||
# Hungarian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-03-19 18:13+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Hungarian <hu@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Felhasználók"
|
|
@ -1,23 +0,0 @@
|
|||
# Italian translation for openobject-addons
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2012-12-27 09:12+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Italian <it@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Utenti"
|
|
@ -1,23 +0,0 @@
|
|||
# Lithuanian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-04-24 18:21+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Lithuanian <lt@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Naudotojai"
|
|
@ -1,23 +0,0 @@
|
|||
# Macedonian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-02-28 14:54+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Macedonian <mk@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Корисници"
|
|
@ -1,23 +0,0 @@
|
|||
# Mongolian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-02-06 07:44+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Mongolian <mn@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Хэрэглэгчид"
|
|
@ -1,23 +0,0 @@
|
|||
# Dutch translation for openobject-addons
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2012-12-27 09:12+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Dutch <nl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Gebruikers"
|
|
@ -1,23 +0,0 @@
|
|||
# Dutch (Belgium) translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-04-15 16:01+0000\n"
|
||||
"Last-Translator: Els Van Vossel (Foxy) <Unknown>\n"
|
||||
"Language-Team: Dutch (Belgium) <nl_BE@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Gebruikers"
|
|
@ -1,23 +0,0 @@
|
|||
# Polish translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-11-14 12:00+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Polish <pl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Użytkownicy"
|
|
@ -1,23 +0,0 @@
|
|||
# Portuguese translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-01-08 17:56+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Portuguese <pt@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Utilizadores"
|
|
@ -1,23 +0,0 @@
|
|||
# Brazilian Portuguese translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-01-02 11:56+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Usuários"
|
|
@ -1,23 +0,0 @@
|
|||
# Romanian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-01-14 19:07+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Romanian <ro@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Utilizatori"
|
|
@ -1,23 +0,0 @@
|
|||
# Russian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-02-13 09:46+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Russian <ru@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Пользователи"
|
|
@ -1,23 +0,0 @@
|
|||
# Slovenian translation for openobject-addons
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2012-12-30 09:36+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Slovenian <sl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Uporabniki"
|
|
@ -1,23 +0,0 @@
|
|||
# Swedish translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-01-17 23:47+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Swedish <sv@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Användare"
|
|
@ -1,23 +0,0 @@
|
|||
# Turkish translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-02-03 12:07+0000\n"
|
||||
"Last-Translator: Ahmet Altınışık <Unknown>\n"
|
||||
"Language-Team: Turkish <tr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Kullanıcılar"
|
|
@ -1,23 +0,0 @@
|
|||
# Vietnamese translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-06-27 06:49+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Vietnamese <vi@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Người dùng"
|
|
@ -1,23 +0,0 @@
|
|||
# Chinese (Simplified) translation for openobject-addons
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-01-02 10:59+0000\n"
|
||||
"Last-Translator: Oliver Yuan <Unknown>\n"
|
||||
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "用户"
|
|
@ -1,23 +0,0 @@
|
|||
# Chinese (Traditional) translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-01-30 13:18+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Chinese (Traditional) <zh_TW@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "使用者"
|
|
@ -1,60 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2010-2012 OpenERP SA (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import logging
|
||||
import simplejson
|
||||
|
||||
import openerp
|
||||
from openerp.addons.auth_signup.res_users import SignupError
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class res_users(osv.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
def _auth_oauth_signin(self, cr, uid, provider, validation, params, context=None):
|
||||
# overridden to use signup method if regular oauth signin fails
|
||||
try:
|
||||
login = super(res_users, self)._auth_oauth_signin(cr, uid, provider, validation, params, context=context)
|
||||
|
||||
except openerp.exceptions.AccessDenied, access_denied_exception:
|
||||
if context and context.get('no_user_creation'):
|
||||
return None
|
||||
state = simplejson.loads(params['state'])
|
||||
token = state.get('t')
|
||||
oauth_uid = validation['user_id']
|
||||
email = validation.get('email', 'provider_%s_user_%s' % (provider, oauth_uid))
|
||||
name = validation.get('name', email)
|
||||
values = {
|
||||
'name': name,
|
||||
'login': email,
|
||||
'email': email,
|
||||
'oauth_provider_id': provider,
|
||||
'oauth_uid': oauth_uid,
|
||||
'oauth_access_token': params['access_token'],
|
||||
'active': True,
|
||||
}
|
||||
try:
|
||||
_, login, _ = self.signup(cr, uid, values, token, context=context)
|
||||
except SignupError:
|
||||
raise access_denied_exception
|
||||
return login
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- vim:et:si:ts=2:sts=2:sw=2 -->
|
||||
<openerp>
|
||||
<data>
|
||||
<template id="auth_oauth_signup.signup" inherit_id="auth_signup.signup" name="OAuth Signup buttons">
|
||||
<xpath expr="//button[@type='submit']" position="before">
|
||||
<div class="pull-right">
|
||||
<div t-foreach="providers or []" t-as="p">
|
||||
<a t-att-href="p['auth_link']" class="btn btn-link">
|
||||
<i t-att-class="p['css_class']"/>
|
||||
<t t-esc="p['body']"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
</openerp>
|
|
@ -42,6 +42,6 @@ Allow users to sign up and reset their password
|
|||
'res_users_view.xml',
|
||||
'views/auth_signup_login.xml',
|
||||
],
|
||||
'js': ['static/src/js/auth_signup.js'],
|
||||
'js': [],
|
||||
'bootstrap': True,
|
||||
}
|
||||
|
|
|
@ -19,81 +19,106 @@
|
|||
#
|
||||
##############################################################################
|
||||
import logging
|
||||
import werkzeug
|
||||
|
||||
import openerp
|
||||
import openerp.addons.web.controllers.main as webmain
|
||||
from openerp.addons.auth_signup.res_users import SignupError
|
||||
from openerp.addons.web.controllers.main import ensure_db
|
||||
from openerp import http
|
||||
from openerp.http import request, LazyResponse
|
||||
from openerp.http import request
|
||||
from openerp.tools.translate import _
|
||||
from openerp.tools import exception_to_unicode
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class AuthSignup(openerp.addons.web.controllers.main.Home):
|
||||
class AuthSignupHome(openerp.addons.web.controllers.main.Home):
|
||||
|
||||
@http.route()
|
||||
def web_login(self, *args, **kw):
|
||||
mode = request.params.get('mode')
|
||||
ensure_db()
|
||||
response = super(AuthSignupHome, self).web_login(*args, **kw)
|
||||
response.qcontext.update(self.get_auth_signup_config())
|
||||
return response
|
||||
|
||||
@http.route('/web/signup', type='http', auth='public', website=True, multilang=True)
|
||||
def web_auth_signup(self, *args, **kw):
|
||||
qcontext = self.get_auth_signup_qcontext()
|
||||
|
||||
if not qcontext.get('token') and not qcontext.get('signup_enabled'):
|
||||
raise werkzeug.exceptions.NotFound()
|
||||
|
||||
if 'error' not in qcontext and request.httprequest.method == 'POST':
|
||||
try:
|
||||
self.do_signup(qcontext)
|
||||
return super(AuthSignupHome, self).web_login(*args, **kw)
|
||||
except (SignupError, AssertionError), e:
|
||||
qcontext['error'] = _(e.message)
|
||||
|
||||
return request.render('auth_signup.signup', qcontext)
|
||||
|
||||
@http.route('/web/reset_password', type='http', auth='public', website=True, multilang=True)
|
||||
def web_auth_reset_password(self, *args, **kw):
|
||||
qcontext = self.get_auth_signup_qcontext()
|
||||
|
||||
if not qcontext.get('token') and not qcontext.get('reset_password_enabled'):
|
||||
raise werkzeug.exceptions.NotFound()
|
||||
|
||||
if 'error' not in qcontext and request.httprequest.method == 'POST':
|
||||
try:
|
||||
if qcontext.get('token'):
|
||||
self.do_signup(qcontext)
|
||||
return super(AuthSignupHome, self).web_login(*args, **kw)
|
||||
else:
|
||||
login = qcontext.get('login')
|
||||
assert login, "No login provided."
|
||||
res_users = request.registry.get('res.users')
|
||||
res_users.reset_password(request.cr, openerp.SUPERUSER_ID, login)
|
||||
qcontext['message'] = _("An email has been sent with credentials to reset your password")
|
||||
except SignupError:
|
||||
qcontext['error'] = _("Could not reset your password")
|
||||
_logger.exception('error when resetting password')
|
||||
except Exception, e:
|
||||
qcontext['error'] = _(e.message)
|
||||
|
||||
|
||||
return request.render('auth_signup.reset_password', qcontext)
|
||||
|
||||
def get_auth_signup_config(self):
|
||||
"""retrieve the module config (which features are enabled) for the login page"""
|
||||
|
||||
icp = request.registry.get('ir.config_parameter')
|
||||
return {
|
||||
'signup_enabled': icp.get_param(request.cr, openerp.SUPERUSER_ID, 'auth_signup.allow_uninvited') == 'True',
|
||||
'reset_password_enabled': icp.get_param(request.cr, openerp.SUPERUSER_ID, 'auth_signup.reset_password') == 'True',
|
||||
}
|
||||
|
||||
def get_auth_signup_qcontext(self):
|
||||
""" Shared helper returning the rendering context for signup and reset password """
|
||||
qcontext = request.params.copy()
|
||||
super_response = super(AuthSignup, self).web_login(*args, **kw)
|
||||
response = webmain.render_bootstrap_template(request.session.db, 'auth_signup.signup', qcontext, lazy=True)
|
||||
if isinstance(super_response, LazyResponse):
|
||||
response.params['values'].update(super_response.params['values'])
|
||||
token = qcontext.get('token', None)
|
||||
token_infos = None
|
||||
if token:
|
||||
qcontext.update(self.get_auth_signup_config())
|
||||
if qcontext.get('token'):
|
||||
try:
|
||||
# retrieve the user info (name, login or email) corresponding to a signup token
|
||||
res_partner = request.registry.get('res.partner')
|
||||
token_infos = res_partner.signup_retrieve_info(request.cr, openerp.SUPERUSER_ID, token)
|
||||
token_infos = res_partner.signup_retrieve_info(request.cr, openerp.SUPERUSER_ID, qcontext.get('token'))
|
||||
for k, v in token_infos.items():
|
||||
qcontext.setdefault(k, v)
|
||||
except:
|
||||
qcontext['error'] = _("Invalid signup token")
|
||||
response.params['template'] = 'web.login'
|
||||
return response
|
||||
return qcontext
|
||||
|
||||
# retrieve the module config (which features are enabled) for the login page
|
||||
icp = request.registry.get('ir.config_parameter')
|
||||
config = {
|
||||
'signup': icp.get_param(request.cr, openerp.SUPERUSER_ID, 'auth_signup.allow_uninvited') == 'True',
|
||||
'reset': icp.get_param(request.cr, openerp.SUPERUSER_ID, 'auth_signup.reset_password') == 'True',
|
||||
}
|
||||
qcontext.update(config)
|
||||
|
||||
if 'error' in qcontext or mode not in ('reset', 'signup') or (not token and not config[mode]):
|
||||
if isinstance(super_response, LazyResponse):
|
||||
super_response.params['values'].update(config)
|
||||
return super_response
|
||||
|
||||
if request.httprequest.method == 'GET':
|
||||
if token_infos:
|
||||
qcontext.update(token_infos)
|
||||
else:
|
||||
res_users = request.registry.get('res.users')
|
||||
login = request.params.get('login')
|
||||
if mode == 'reset' and not token:
|
||||
try:
|
||||
res_users.reset_password(request.cr, openerp.SUPERUSER_ID, login)
|
||||
qcontext['message'] = _("An email has been sent with credentials to reset your password")
|
||||
response.params['template'] = 'web.login'
|
||||
except Exception:
|
||||
qcontext['error'] = _("Could not reset your password")
|
||||
_logger.exception('error when resetting password')
|
||||
else:
|
||||
def do_signup(self, qcontext):
|
||||
""" Shared helper that creates a res.partner out of a token """
|
||||
values = dict((key, qcontext.get(key)) for key in ('login', 'name', 'password'))
|
||||
try:
|
||||
self._signup_with_values(token, values)
|
||||
assert any([k for k in values.values()]), "The form was not properly filled in."
|
||||
assert values.get('password') == qcontext.get('confirm_password'), "Passwords do not match; please retype them."
|
||||
self._signup_with_values(qcontext.get('token'), values)
|
||||
request.cr.commit()
|
||||
except SignupError, e:
|
||||
qcontext['error'] = exception_to_unicode(e)
|
||||
return super(AuthSignup, self).web_login(*args, **kw)
|
||||
|
||||
return response
|
||||
|
||||
def _signup_with_values(self, token, values):
|
||||
request.registry['res.users'].signup(request.cr, openerp.SUPERUSER_ID, values, token)
|
||||
|
||||
db, login, password = request.registry['res.users'].signup(request.cr, openerp.SUPERUSER_ID, values, token)
|
||||
request.cr.commit() # as authenticate will use its own cursor we need to commit the current transaction
|
||||
uid = request.session.authenticate(db, login, password)
|
||||
if not uid:
|
||||
raise SignupError(_('Authentification Failed.'))
|
||||
|
||||
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -25,7 +25,7 @@ from urlparse import urljoin
|
|||
|
||||
from openerp.addons.base.ir.ir_mail_server import MailDeliveryException
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT, ustr
|
||||
from ast import literal_eval
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
@ -66,11 +66,12 @@ class res_partner(osv.Model):
|
|||
self.signup_prepare(cr, uid, [partner.id], context=context)
|
||||
partner.refresh()
|
||||
|
||||
route = 'login'
|
||||
# the parameters to encode for the query
|
||||
query = dict(db=cr.dbname)
|
||||
signup_type = context.get('signup_force_type_in_url', partner.signup_type or '')
|
||||
if signup_type:
|
||||
query['mode'] = signup_type
|
||||
route = 'reset_password' if signup_type == 'reset' else signup_type
|
||||
|
||||
if partner.signup_token and signup_type:
|
||||
query['token'] = partner.signup_token
|
||||
|
@ -89,7 +90,7 @@ class res_partner(osv.Model):
|
|||
if res_id:
|
||||
fragment['id'] = res_id
|
||||
|
||||
res[partner.id] = urljoin(base_url, "/web/login?%s#%s" % (urlencode(query), urlencode(fragment)))
|
||||
res[partner.id] = urljoin(base_url, "/web/%s?%s#%s" % (route, urlencode(query), urlencode(fragment)))
|
||||
|
||||
return res
|
||||
|
||||
|
@ -236,7 +237,12 @@ class res_users(osv.Model):
|
|||
# create a copy of the template user (attached to a specific partner_id if given)
|
||||
values['active'] = True
|
||||
context = dict(context or {}, no_reset_password=True)
|
||||
try:
|
||||
with cr.savepoint():
|
||||
return self.copy(cr, uid, template_user_id, values, context=context)
|
||||
except Exception, e:
|
||||
# copy may failed if asked login is not available.
|
||||
raise SignupError(ustr(e))
|
||||
|
||||
def reset_password(self, cr, uid, login, context=None):
|
||||
""" retrieve the user corresponding to login (login or email),
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
openerp.auth_signup = function(instance) {
|
||||
openerp.web.LoginForm.include({
|
||||
start: function () {
|
||||
var self = this;
|
||||
this.$el.on('submit', function () {
|
||||
var password = self.get_password_field('password');
|
||||
var confirm_password = self.get_password_field('confirm_password');
|
||||
if (password && confirm_password && (password.value != confirm_password.value)) {
|
||||
alert("Passwords do not match; please retype them.");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
get_password_field: function (field) {
|
||||
var selector = 'input[name="' + field + '"][type="password"]:visible';
|
||||
return this.$(selector)[0];
|
||||
},
|
||||
});
|
||||
};
|
|
@ -5,85 +5,95 @@
|
|||
<data>
|
||||
<template id="auth_signup.login" inherit_id="web.login" name="Sign up - Reset Password">
|
||||
<xpath expr="//button[@type='submit']" position="before">
|
||||
<a t-if="signup" t-attf-href="?{{ keep_query('*', mode='signup') }}" class="btn btn-link pull-right">Sign up</a>
|
||||
<a t-if="reset" t-attf-href="?{{ keep_query('*', mode='reset') }}" class="btn btn-link pull-right">Reset Password</a>
|
||||
<a t-if="signup_enabled" t-attf-href="/web/signup?redirect=/web%3f{{ quote_plus(keep_query()) }}" class="btn btn-link pull-right">Sign up</a>
|
||||
<a t-if="reset_password_enabled" t-attf-href="/web/reset_password?redirect=/web/login%3f{{ quote_plus(keep_query()) }}" class="btn btn-link pull-right">Reset Password</a>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="auth_signup.signup" name="Sign up">
|
||||
<t t-call="web.login_layout">
|
||||
<t t-set="head">
|
||||
<t t-foreach="css" t-as="css_file">
|
||||
<link rel="stylesheet" t-att-href="css_file"/>
|
||||
</t>
|
||||
<t t-foreach="js" t-as="js_file">
|
||||
<script type="text/javascript" t-att-src="js_file"></script>
|
||||
</t>
|
||||
</t>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
var s = new openerp.init(<t t-raw="modules"/>);
|
||||
var login_form = new openerp.web.LoginForm($('.oe_signup_form'));
|
||||
});
|
||||
</script>
|
||||
|
||||
<t t-set="reset_without_token" t-value="mode == 'reset' and not token"/>
|
||||
|
||||
<form class="oe_signup_form" role="form" method="post">
|
||||
<template id="auth_signup.fields" name="Auth Signup/ResetPassword form fields">
|
||||
<t t-call="web.database_select"/>
|
||||
|
||||
<div class="form-group field-name" t-if="not reset_without_token">
|
||||
<div class="form-group field-name">
|
||||
<label for="name" class="control-label">Your Name</label>
|
||||
<input type="text" name="name" t-att-value="name" id="name" class="form-control" placeholder="e.g. John Doe"
|
||||
required="required" autofocus="autofocus" t-att-disabled="'disabled' if mode == 'reset' and token else None"/>
|
||||
required="required" t-att-autofocus="'autofocus' if not only_passwords else None" t-att-readonly="'readonly' if only_passwords else None"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group field-login">
|
||||
<label for="login" class="control-label">Your Email</label>
|
||||
<input type="text" name="login" t-att-value="login" id="login" class="form-control"
|
||||
t-att-autofocus="'autofocus' if reset_without_token else None"
|
||||
required="required" t-att-disabled="'disabled' if mode == 'reset' and token else None"/>
|
||||
<input type="hidden" name="login" t-att-value="login" t-if="mode == 'reset' and token"/>
|
||||
required="required" t-att-readonly="'readonly' if only_passwords else None"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group field-password" t-if="not reset_without_token">
|
||||
<div class="form-group field-password">
|
||||
<label for="password" class="control-label">Password</label>
|
||||
<input type="password" name="password" id="password" class="form-control"
|
||||
required="required" t-att-autofocus="'autofocus' if mode == 'reset' and token else None"/>
|
||||
<input type="password" name="password" autofocus="autofocus" id="password" class="form-control"
|
||||
required="required" t-att-autofocus="'autofocus' if only_passwords else None"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group field-confirm_password" t-if="not reset_without_token">
|
||||
<div class="form-group field-confirm_password">
|
||||
<label for="confirm_password" class="control-label">Confirm Password</label>
|
||||
<input type="password" name="confirm_password" id="confirm_password" class="form-control" required="required"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="auth_signup.signup" name="Sign up login">
|
||||
<t t-call="web.login_layout">
|
||||
<form class="oe_signup_form" role="form" t-attf-action="/web/signup{{ '?debug' if debug else '' }}" method="post" t-if="not message">
|
||||
|
||||
<t t-call="auth_signup.fields"/>
|
||||
|
||||
<p class="alert alert-danger" t-if="error">
|
||||
<t t-esc="error"/>
|
||||
</p>
|
||||
<p class="alert alert-success" t-if="message">
|
||||
<t t-esc="message"/>
|
||||
</p>
|
||||
|
||||
<input type="hidden" name="redirect" t-att-value="redirect"/>
|
||||
<input type="hidden" name="mode" t-att-value="mode"/>
|
||||
<input type="hidden" name="token" t-att-value="token"/>
|
||||
<div class="clearfix oe_login_buttons">
|
||||
<a t-attf-href="?{{ keep_query('*', mode='login') }}" class="btn btn-link pull-right">Back to Login</a>
|
||||
<button type="submit" class="btn btn-primary pull-left">
|
||||
<t t-if="mode == 'signup'">Sign up</t>
|
||||
<t t-if="mode == 'reset'">Reset password</t>
|
||||
</button>
|
||||
<a href="/web/login" class="btn btn-link pull-right">Back to Login</a>
|
||||
<button type="submit" class="btn btn-primary pull-left">Sign up</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<div class="oe_single_form_footer" t-if="not disable_footer">
|
||||
<t t-if="not disable_database_manager">
|
||||
<a class="oe_login_manage_db" t-attf-href="/web/database/manager{{ '?debug' if debug else '' }}">Manage Databases</a>
|
||||
<span class="oe_footer_seperator"> | </span>
|
||||
</t>
|
||||
<a href="http://www.openerp.com" target="_blank">Powered by <span>OpenERP</span></a>
|
||||
</template>
|
||||
|
||||
<template id="auth_signup.reset_password" name="Reset password">
|
||||
<t t-call="web.login_layout">
|
||||
<div t-if="message">
|
||||
<p class="alert alert-success" t-if="message">
|
||||
<t t-esc="message"/>
|
||||
</p>
|
||||
<a href="/web/login" class="btn btn-link pull-right">Back to Login</a>
|
||||
</div>
|
||||
|
||||
<form class="oe_reset_password_form" role="form" t-attf-action="/web/reset_password{{ '?debug' if debug else '' }}" method="post" t-if="not message">
|
||||
|
||||
<t t-if="token">
|
||||
<t t-call="auth_signup.fields">
|
||||
<t t-set="only_passwords" t-value="1"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-if="not token">
|
||||
<div class="form-group field-login">
|
||||
<label for="login" class="control-label">Your Email</label>
|
||||
<input type="text" name="login" t-att-value="login" id="login" class="form-control"
|
||||
autofocus="autofocus" required="required"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<p class="alert alert-danger" t-if="error">
|
||||
<t t-esc="error"/>
|
||||
</p>
|
||||
<input type="hidden" name="redirect" t-att-value="redirect"/>
|
||||
<input type="hidden" name="token" t-att-value="token"/>
|
||||
<div class="clearfix oe_login_buttons">
|
||||
<a href="/web/login" class="btn btn-link pull-right">Back to Login</a>
|
||||
<button type="submit" class="btn btn-primary pull-left">Reset password</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</t>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -275,6 +275,13 @@ class base_action_rule(osv.osv):
|
|||
if action.filter_id:
|
||||
domain = eval(action.filter_id.domain)
|
||||
ctx.update(eval(action.filter_id.context))
|
||||
if 'lang' not in ctx:
|
||||
# Filters might be language-sensitive, attempt to reuse creator lang
|
||||
# as we are usually running this as super-user in background
|
||||
[filter_meta] = action.filter_id.perm_read()
|
||||
user_id = filter_meta['write_uid'] and filter_meta['write_uid'][0] or \
|
||||
filter_meta['create_uid'][0]
|
||||
ctx['lang'] = self.pool['res.users'].browse(cr, uid, user_id).lang
|
||||
record_ids = model.search(cr, uid, domain, context=ctx)
|
||||
|
||||
# determine when action should occur for the records
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<record id="bank_swift_field" model="res.partner.bank.type.field">
|
||||
<field name="name">bank_bic</field>
|
||||
<field name="bank_type_id" ref="bank_iban"/>
|
||||
<field eval="True" name="required"/>
|
||||
<field eval="False" name="required"/>
|
||||
<field eval="False" name="readonly"/>
|
||||
</record>
|
||||
<record id="bank_country_field" model="res.partner.bank.type.field">
|
||||
|
|
|
@ -41,7 +41,9 @@ class base_config_settings(osv.osv_memory):
|
|||
help="""This installs the module google_docs."""),
|
||||
'module_google_calendar': fields.boolean('Allow the users to synchronize their calendar with Google Calendar',
|
||||
help="""This installs the module google_calendar."""),
|
||||
'font': fields.many2one('res.font', string="Report Font", help="Set the font into the report header, it will be used as default font in the RML reports of the user company"),
|
||||
'font': fields.many2one('res.font', string="Report Font", domain=[('mode', 'in', ('Normal', 'Regular', 'all', 'Book'))],
|
||||
help="Set the font into the report header, it will be used as default font in the RML reports of the user company"),
|
||||
|
||||
}
|
||||
|
||||
_defaults= {
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
<label for="font" />
|
||||
<div>
|
||||
<div>
|
||||
<field name="font" class="oe_inline" domain="[('mode', 'in', ('normal', 'regular', 'all', 'book'))]" />
|
||||
<field name="font" class="oe_inline" />
|
||||
<button string="(reload fonts)" name="act_discover_fonts" type="object" class="oe_link"/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -54,7 +54,7 @@ _ref_vat = {
|
|||
'gr': 'GR12345670',
|
||||
'hu': 'HU12345676',
|
||||
'hr': 'HR01234567896', # Croatia, contributed by Milan Tribuson
|
||||
'ie': 'IE1234567T',
|
||||
'ie': 'IE1234567FA',
|
||||
'it': 'IT12345670017',
|
||||
'lt': 'LT123456715',
|
||||
'lu': 'LU12345613',
|
||||
|
@ -190,6 +190,34 @@ class res_partner(osv.osv):
|
|||
return check == int(num[8])
|
||||
return False
|
||||
|
||||
def _ie_check_char(self, vat):
|
||||
vat = vat.zfill(8)
|
||||
extra = 0
|
||||
if vat[7] not in ' W':
|
||||
if vat[7].isalpha():
|
||||
extra = 9 * (ord(vat[7]) - 64)
|
||||
else:
|
||||
# invalid
|
||||
return -1
|
||||
checksum = extra + sum((8-i) * int(x) for i, x in enumerate(vat[:7]))
|
||||
return 'WABCDEFGHIJKLMNOPQRSTUV'[checksum % 23]
|
||||
|
||||
def check_vat_ie(self, vat):
|
||||
""" Temporary Ireland VAT validation to support the new format
|
||||
introduced in January 2013 in Ireland, until upstream is fixed.
|
||||
TODO: remove when fixed upstream"""
|
||||
if len(vat) not in (8, 9) or not vat[2:7].isdigit():
|
||||
return False
|
||||
if len(vat) == 8:
|
||||
# Normalize pre-2013 numbers: final space or 'W' not significant
|
||||
vat += ' '
|
||||
if vat[:7].isdigit():
|
||||
return vat[7] == self._ie_check_char(vat[:7] + vat[8])
|
||||
elif vat[1] in (string.ascii_uppercase + '+*'):
|
||||
# Deprecated format
|
||||
# See http://www.revenue.ie/en/online/third-party-reporting/reporting-payment-details/faqs.html#section3
|
||||
return vat[7] == self._ie_check_char(vat[2:7] + vat[0] + vat[8])
|
||||
return False
|
||||
|
||||
# Mexican VAT verification, contributed by <moylop260@hotmail.com>
|
||||
# and Panos Christeas <p_christ@hol.gr>
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import hashlib
|
||||
import pytz
|
||||
import re
|
||||
import time
|
||||
import openerp
|
||||
import openerp.service.report
|
||||
import uuid
|
||||
from werkzeug.exceptions import BadRequest
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil import parser
|
||||
from dateutil import rrule
|
||||
|
@ -34,10 +34,11 @@ from openerp import tools, SUPERUSER_ID
|
|||
from openerp.osv import fields, osv
|
||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from openerp.tools.translate import _
|
||||
from openerp import http
|
||||
from openerp.http import request
|
||||
from operator import itemgetter
|
||||
|
||||
from werkzeug.exceptions import BadRequest
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -844,6 +845,7 @@ class calendar_event(osv.Model):
|
|||
'attendee_ids': fields.one2many('calendar.attendee', 'event_id', 'Attendees', ondelete='cascade'),
|
||||
'partner_ids': fields.many2many('res.partner', string='Attendees', states={'done': [('readonly', True)]}),
|
||||
'alarm_ids': fields.many2many('calendar.alarm', string='Reminders', ondelete="restrict"),
|
||||
|
||||
}
|
||||
_defaults = {
|
||||
'end_type': 'count',
|
||||
|
@ -870,11 +872,9 @@ class calendar_event(osv.Model):
|
|||
]
|
||||
|
||||
def onchange_dates(self, cr, uid, ids, start_date, duration=False, end_date=False, allday=False, context=None):
|
||||
|
||||
"""Returns duration and/or end date based on values passed
|
||||
@param ids: List of calendar event's IDs.
|
||||
@param start_date: Starting date
|
||||
@param duration: Duration between start date and end date
|
||||
@param end_date: Ending Datee
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
@ -888,14 +888,14 @@ class calendar_event(osv.Model):
|
|||
value['duration'] = duration
|
||||
|
||||
if allday: # For all day event
|
||||
start = datetime.strptime(start_date.split(' ')[0].split('T')[0], "%Y-%m-%d")
|
||||
duration = 24.0
|
||||
value['duration'] = duration
|
||||
start = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S")
|
||||
user = self.pool['res.users'].browse(cr, uid, uid)
|
||||
tz = pytz.timezone(user.tz) if user.tz else pytz.utc
|
||||
start = pytz.utc.localize(start).astimezone(tz) # convert start in user's timezone
|
||||
start = start.astimezone(pytz.utc) # convert start back to utc
|
||||
value['date'] = start.strftime("%Y-%m-%d") + ' 00:00:00'
|
||||
|
||||
value['duration'] = 24.0
|
||||
value['date'] = datetime.strftime(start, "%Y-%m-%d %H:%M:%S")
|
||||
else:
|
||||
start = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
@ -1353,16 +1353,56 @@ class calendar_event(osv.Model):
|
|||
res = super(calendar_event, self).copy(cr, uid, calendar_id2real_id(id), default, context)
|
||||
return res
|
||||
|
||||
def _detach_one_event(self, cr, uid, id, values=dict(), context=None):
|
||||
real_event_id = calendar_id2real_id(id)
|
||||
data = self.read(cr, uid, id, ['date', 'date_deadline', 'rrule', 'duration'])
|
||||
|
||||
if data.get('rrule'):
|
||||
data.update(
|
||||
values,
|
||||
recurrent_id=real_event_id,
|
||||
recurrent_id_date=data.get('date'),
|
||||
rrule_type=False,
|
||||
rrule='',
|
||||
recurrency=False,
|
||||
end_date = datetime.strptime(values.get('date', False) or data.get('date'),"%Y-%m-%d %H:%M:%S")
|
||||
+ timedelta(hours=values.get('duration', False) or data.get('duration'))
|
||||
)
|
||||
|
||||
#do not copy the id
|
||||
if data.get('id'):
|
||||
del(data['id'])
|
||||
new_id = self.copy(cr, uid, real_event_id, default=data, context=context)
|
||||
return new_id
|
||||
|
||||
def open_after_detach_event(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
new_id = self._detach_one_event(cr, uid, ids[0], context=context)
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'calendar.event',
|
||||
'view_mode': 'form',
|
||||
'res_id': new_id,
|
||||
'target': 'current',
|
||||
'flags': {'form': {'action_buttons': True, 'options' : { 'mode' : 'edit' } } }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
def write(self, cr, uid, ids, values, context=None):
|
||||
def _only_changes_to_apply_on_real_ids(field_names):
|
||||
''' return True if changes are only to be made on the real ids'''
|
||||
for field in field_names:
|
||||
if field not in ['name', 'message_follower_ids','oe_update_date']:
|
||||
return False
|
||||
if field in ['date','active']:
|
||||
return True
|
||||
return False
|
||||
|
||||
context = context or {}
|
||||
|
||||
|
||||
if isinstance(ids, (str,int, long)):
|
||||
if len(str(ids).split('-')) == 1:
|
||||
ids = [int(ids)]
|
||||
|
@ -1383,30 +1423,13 @@ class calendar_event(osv.Model):
|
|||
# if we are setting the recurrency flag to False or if we are only changing fields that
|
||||
# should be only updated on the real ID and not on the virtual (like message_follower_ids):
|
||||
# then set real ids to be updated.
|
||||
if not values.get('recurrency', True) or _only_changes_to_apply_on_real_ids(values.keys()):
|
||||
if not values.get('recurrency', True) or not _only_changes_to_apply_on_real_ids(values.keys()):
|
||||
ids.append(real_event_id)
|
||||
continue
|
||||
|
||||
#if edit one instance of a reccurrent id
|
||||
else:
|
||||
data = self.read(cr, uid, event_id, ['date', 'date_deadline', 'rrule', 'duration'])
|
||||
if data.get('rrule'):
|
||||
data.update(
|
||||
values,
|
||||
recurrent_id=real_event_id,
|
||||
recurrent_id_date=data.get('date'),
|
||||
rrule_type=False,
|
||||
rrule='',
|
||||
recurrency=False,
|
||||
end_date = datetime.strptime(values.get('date', False) or data.get('date'),"%Y-%m-%d %H:%M:%S")
|
||||
+ timedelta(hours=values.get('duration', False) or data.get('duration'))
|
||||
)
|
||||
|
||||
#do not copy the id
|
||||
if data.get('id'):
|
||||
del(data['id'])
|
||||
new_id = self.copy(cr, uid, real_event_id, default=data, context=context)
|
||||
context.update({'active_id': new_id, 'active_ids': [new_id]})
|
||||
continue
|
||||
new_id = self._detach_one_event(cr, uid, event_id, values, context=None)
|
||||
|
||||
res = super(calendar_event, self).write(cr, uid, ids, values, context=context)
|
||||
|
||||
|
@ -1473,7 +1496,6 @@ class calendar_event(osv.Model):
|
|||
if context is None:
|
||||
context = {}
|
||||
fields2 = fields and fields[:] or None
|
||||
|
||||
EXTRAFIELDS = ('class', 'user_id', 'duration', 'date', 'rrule', 'vtimezone')
|
||||
for f in EXTRAFIELDS:
|
||||
if fields and (f not in fields):
|
||||
|
@ -1518,6 +1540,7 @@ class calendar_event(osv.Model):
|
|||
for k in EXTRAFIELDS:
|
||||
if (k in r) and (fields and (k not in fields)):
|
||||
del r[k]
|
||||
|
||||
if isinstance(ids, (str, int, long)):
|
||||
return result and result[0] or False
|
||||
return result
|
||||
|
|
|
@ -6,19 +6,6 @@
|
|||
-->
|
||||
|
||||
<!--For Meetings -->
|
||||
<record id="res_partner_another" model="res.partner">
|
||||
<field name="name">Arshaw</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="customer" eval="False"/>
|
||||
<field name="email">fullcalendar@example.com</field>
|
||||
</record>
|
||||
<record id="res_user_another" model="res.users">
|
||||
<field name="name" >Second Demo User</field>
|
||||
<field name="login" >Second Demo User</field>
|
||||
<field name="partner_id" ref="res_partner_another"/>
|
||||
<field name="company_id" ref="base.main_company" />
|
||||
</record>
|
||||
|
||||
<record id="cal_contact_1" model="calendar.contacts">
|
||||
<field eval="1" name="active"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
|
@ -105,8 +92,8 @@
|
|||
|
||||
<record id="calendar_event_7" model="calendar.event">
|
||||
<field eval="1" name="active"/>
|
||||
<field name="user_id" ref="res_user_another"/>
|
||||
<field name="partner_ids" eval="[(6,0,[ref('res_partner_another'),ref('base.res_partner_8')])]"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="partner_ids" eval="[(6,0,[ref('base.res_partner_7')])]"/>
|
||||
<field name="name">Presentation of the new Calendar</field>
|
||||
<field name="categ_ids" eval="[(6,0,[ref('categ_meet1'), ref('categ_meet2')])]"/>
|
||||
<field eval="time.strftime('%Y-%m-16 6:00:00')" name="date"/>
|
||||
|
@ -115,17 +102,6 @@
|
|||
<field name="state">draft</field>
|
||||
</record>
|
||||
|
||||
<record id="calendar_event_8" model="calendar.event">
|
||||
<field eval="1" name="active"/>
|
||||
<field name="user_id" ref="res_user_another"/>
|
||||
<field name="partner_ids" eval="[(6,0,[ref('res_partner_another'),ref('base.partner_root')])]"/>
|
||||
<field name="name">Discuss about the module : Calendar </field>
|
||||
<field name="categ_ids" eval="[(6,0,[ref('categ_meet1'), ref('categ_meet2')])]"/>
|
||||
<field eval="time.strftime('%Y-%m-16 6:00:00')" name="date"/>
|
||||
<field eval="time.strftime('%Y-%m-16 18:30:00')" name="date_deadline"/>
|
||||
<field eval="8.5" name="duration"/>
|
||||
<field name="state">draft</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -51,6 +51,11 @@
|
|||
</div>
|
||||
<notebook>
|
||||
<page string="Meeting Details">
|
||||
<group attrs="{'invisible': [('recurrency','==',False)]}" class="oe_edit_only ">
|
||||
<p class='alert alert-warning'> This event is linked to a recurrence...<br/>
|
||||
<button type="object" name="open_after_detach_event" string="Update only this instance" help="Click here to update only this instance and not all recurrences. " class="oe_link"/>
|
||||
</p>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="date" string="Starting at" on_change="onchange_dates(date, duration, False, allday)"/>
|
||||
|
@ -60,12 +65,12 @@
|
|||
on_change="onchange_dates(date, duration, False, allday)"
|
||||
class="oe_inline" attrs="{'invisible': [('allday','=',True)]}"/>
|
||||
<label string="hours" attrs="{'invisible': [('allday','=',True)]}"/>
|
||||
(<field name="allday" on_change="onchange_dates(date,False,False,allday)" class="oe_inline"/>
|
||||
(<field name="allday" class="oe_inline"/>
|
||||
<label for="allday" string="All Day?"/>)
|
||||
</div>
|
||||
<field name="date_deadline" groups="base.group_no_one"
|
||||
attrs="{'invisible': ['|', ('allday','=',True), ('duration','<', 24)]}"
|
||||
on_change="onchange_dates(date,False,date_deadline)"/>
|
||||
/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="categ_ids" widget="many2many_tags"/>
|
||||
|
@ -268,7 +273,6 @@
|
|||
<field name="view_mode">calendar,tree,form,gantt</field>
|
||||
<field name="view_id" ref="view_calendar_event_calendar"/>
|
||||
<field name="search_view_id" ref="view_calendar_event_search"/>
|
||||
<field name="context">{"search_default_mymeetings": 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to schedule a new meeting.
|
||||
|
|
|
@ -26,7 +26,7 @@ class calendar_contacts(osv.osv):
|
|||
|
||||
_columns = {
|
||||
'user_id': fields.many2one('res.users','Me'),
|
||||
'partner_id': fields.many2one('res.partner','Employee',required=True, domain=[('customer','=',True)]),
|
||||
'partner_id': fields.many2one('res.partner','Employee',required=True, domain=[]),
|
||||
'active':fields.boolean('active'),
|
||||
}
|
||||
_defaults = {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<field name="res_model">calendar.contacts</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="domain">[('user_id','=',uid)]</field>
|
||||
<field name="view_id" ref="view_calendar_contacts" />
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
openerp.calendar = function(instance) {
|
||||
var _t = instance.web._t;
|
||||
var QWeb = instance.web.qweb;
|
||||
instance.calendar = {}
|
||||
instance.calendar = {};
|
||||
|
||||
|
||||
instance.web.WebClient = instance.web.WebClient.extend({
|
||||
|
@ -58,7 +58,7 @@ openerp.calendar = function(instance) {
|
|||
show_application: function() {
|
||||
this._super();
|
||||
this.check_notifications();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
@ -77,7 +77,6 @@ openerp.calendar = function(instance) {
|
|||
if(instance.session.session_is_valid(self.db) && instance.session.username != "anonymous") {
|
||||
self.redirect_meeting_view(self.db,self.action,self.id,self.view);
|
||||
} else {
|
||||
alert('in anonymous or null ');
|
||||
self.open_invitation_form(self.attendee_data);
|
||||
}
|
||||
},
|
||||
|
@ -92,9 +91,8 @@ openerp.calendar = function(instance) {
|
|||
|
||||
var reload_page = function(){
|
||||
return location.replace(action_url);
|
||||
}
|
||||
};
|
||||
reload_page();
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -108,7 +106,7 @@ openerp.calendar = function(instance) {
|
|||
});
|
||||
},
|
||||
map_tag: function(value){
|
||||
return _.map(value, function(el) {return {name: el[1], id:el[0], state: el[2]};})
|
||||
return _.map(value, function(el) {return {name: el[1], id:el[0], state: el[2]};});
|
||||
},
|
||||
get_render_data: function(ids){
|
||||
var self = this;
|
||||
|
@ -121,7 +119,7 @@ openerp.calendar = function(instance) {
|
|||
if (! self.get("effective_readonly")) {
|
||||
var tag_element = self.tags.tagElements();
|
||||
_.each(data,function(value, key){
|
||||
$(tag_element[key]).find(".custom-edit").addClass(data[key][2])
|
||||
$(tag_element[key]).find(".custom-edit").addClass(data[key][2]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +132,7 @@ openerp.calendar = function(instance) {
|
|||
instance.session.session_bind(instance.session.origin).done(function () {
|
||||
new instance.calendar.invitation(null,db,action,id,view,attendee_data).appendTo($("body").addClass('openerp'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -33,7 +33,9 @@
|
|||
!python {model: calendar.event}: |
|
||||
ids = self.search(cr, uid, [('date', '>=', '2011-04-30 16:00:00'), ('date', '<=', '2011-05-31 00:00:00')], context={'virtual_id': True} )
|
||||
before = self.search(cr, uid, [('date', '>=', '2011-04-30 16:00:00'), ('date', '<=', '2011-05-31 00:00:00')], context={'virtual_id': False})
|
||||
self.write(cr, uid,[ids[1]], {'name':'New Name','recurrency' : True}, context={'virtual_id': True})
|
||||
# We start by detach the event
|
||||
newid = self._detach_one_event(cr, uid,ids[1])
|
||||
self.write(cr, uid,[newid], {'name':'New Name','recurrency' : True}, context={'virtual_id': True})
|
||||
after = self.search(cr, uid, [('date', '>=', '2011-04-30 16:00:00'), ('date', '<=', '2011-05-31 00:00:00')], context={'virtual_id': False})
|
||||
assert len(after) == len(before)+1, 'Wrong number of events found, after to have moved a virtual event'
|
||||
new_id = list(set(after)-set(before))[0]
|
||||
|
@ -58,7 +60,6 @@
|
|||
duration: 1
|
||||
interval: days
|
||||
type: notification
|
||||
|
||||
-
|
||||
Now I will assign this reminder to all day event
|
||||
-
|
||||
|
|
|
@ -84,9 +84,12 @@
|
|||
idval = '%d-%s' % (ref('calendar_event_sprintreview0'), '20110425124700')
|
||||
self.write(cr, uid, [idval], {'description': 'Review code of the module: sync_google_calendar.'})
|
||||
-
|
||||
I check whether the record is edited perfectly or not.
|
||||
I check whether that all the records of this recurrence has been edited.
|
||||
-
|
||||
!python {model: calendar.event}: |
|
||||
meeting_ids = self.search(cr, uid, [('recurrent_id', '=', ref('calendar_event_sprintreview0')), ('recurrent_id_date','=','2011-04-25 12:47:00')], context)
|
||||
assert meeting_ids, 'Meeting is not edited !'
|
||||
meeting_ids = self.search(cr, uid, [('recurrent_id', '=', ref('calendar_event_sprintreview0'))], context)
|
||||
meetings = self.browse(cr, uid, meeting_ids, context)
|
||||
for meeting in meetings:
|
||||
assert meeting.description == 'Review code of the module: sync_google_calendar.', 'Description not changed for id: %s' %meeting.id
|
||||
|
||||
|
||||
|
|
|
@ -120,14 +120,14 @@ class crm_case_section(osv.osv):
|
|||
month_begin = date.today().replace(day=1)
|
||||
section_result = [{
|
||||
'value': 0,
|
||||
'tooltip': (month_begin + relativedelta.relativedelta(months=-i)).strftime('%B'),
|
||||
'tooltip': (month_begin + relativedelta.relativedelta(months=-i)).strftime('%B %Y'),
|
||||
} for i in range(self._period_number - 1, -1, -1)]
|
||||
group_obj = obj.read_group(cr, uid, domain, read_fields, groupby_field, context=context)
|
||||
pattern = tools.DEFAULT_SERVER_DATE_FORMAT if obj.fields_get(cr, uid, groupby_field)[groupby_field]['type'] == 'date' else tools.DEFAULT_SERVER_DATETIME_FORMAT
|
||||
for group in group_obj:
|
||||
group_begin_date = datetime.strptime(group['__domain'][0][2], pattern)
|
||||
month_delta = relativedelta.relativedelta(month_begin, group_begin_date)
|
||||
section_result[self._period_number - (month_delta.months + 1)] = {'value': group.get(value_field, 0), 'tooltip': group_begin_date.strftime('%B')}
|
||||
section_result[self._period_number - (month_delta.months + 1)] = {'value': group.get(value_field, 0), 'tooltip': group.get(groupby_field, 0)}
|
||||
return section_result
|
||||
|
||||
def _get_opportunities_data(self, cr, uid, ids, field_name, arg, context=None):
|
||||
|
@ -140,13 +140,18 @@ class crm_case_section(osv.osv):
|
|||
month_begin = date.today().replace(day=1)
|
||||
date_begin = month_begin - relativedelta.relativedelta(months=self._period_number - 1)
|
||||
date_end = month_begin.replace(day=calendar.monthrange(month_begin.year, month_begin.month)[1])
|
||||
date_domain = [('create_date', '>=', date_begin.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)), ('create_date', '<=', date_end.strftime(tools.DEFAULT_SERVER_DATE_FORMAT))]
|
||||
lead_pre_domain = [('create_date', '>=', date_begin.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)),
|
||||
('create_date', '<=', date_end.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)),
|
||||
('type', '=', 'lead')]
|
||||
opp_pre_domain = [('date_deadline', '>=', date_begin.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)),
|
||||
('date_deadline', '<=', date_end.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)),
|
||||
('type', '=', 'opportunity')]
|
||||
for id in ids:
|
||||
res[id] = dict()
|
||||
lead_domain = date_domain + [('type', '=', 'lead'), ('section_id', '=', id)]
|
||||
lead_domain = lead_pre_domain + [('section_id', '=', id)]
|
||||
opp_domain = opp_pre_domain + [('section_id', '=', id)]
|
||||
res[id]['monthly_open_leads'] = self.__get_bar_values(cr, uid, obj, lead_domain, ['create_date'], 'create_date_count', 'create_date', context=context)
|
||||
opp_domain = date_domain + [('type', '=', 'opportunity'), ('section_id', '=', id)]
|
||||
res[id]['monthly_planned_revenue'] = self.__get_bar_values(cr, uid, obj, opp_domain, ['planned_revenue', 'create_date'], 'planned_revenue', 'create_date', context=context)
|
||||
res[id]['monthly_planned_revenue'] = self.__get_bar_values(cr, uid, obj, opp_domain, ['planned_revenue', 'date_deadline'], 'planned_revenue', 'date_deadline', context=context)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
|
|
|
@ -63,9 +63,9 @@
|
|||
<record id="action_report_crm_lead_salesteam" model="ir.actions.act_window">
|
||||
<field name="name">Leads Analysis</field>
|
||||
<field name="res_model">crm.lead.report</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="context">{"search_default_month":1}</field>
|
||||
<field name="view_mode">tree,graph</field>
|
||||
<field name="view_mode">graph</field>
|
||||
<field name="view_id" ref="crm.view_report_crm_lead_graph_two"/>
|
||||
<field name="domain">[('type','=', 'lead'),('section_id', '=', active_id)]</field>
|
||||
<field name="help">Leads Analysis allows you to check different CRM related information like the treatment delays or number of leads per state. You can sort out your leads analysis by different groups to get accurate grained analysis.</field>
|
||||
</record>
|
||||
|
@ -73,9 +73,8 @@
|
|||
<record id="action_report_crm_opportunity_salesteam" model="ir.actions.act_window">
|
||||
<field name="name">Opportunities Analysis</field>
|
||||
<field name="res_model">crm.lead.report</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="context">{"search_default_month":1}</field>
|
||||
<field name="view_mode">tree,graph</field>
|
||||
<field name="view_mode">graph</field>
|
||||
<field name="view_id" ref="crm.view_report_crm_opportunity_graph"/>
|
||||
<field name="domain">[('type','=', 'opportunity'), ('section_id', '=', active_id)]</field>
|
||||
<field name="help">Opportunities Analysis gives you an instant access to your opportunities with information such as the expected revenue, planned cost, missed deadlines or the number of interactions per opportunity. This report is mainly used by the sales manager in order to do the periodic review with the teams of the sales pipeline.</field>
|
||||
</record>
|
||||
|
@ -124,7 +123,7 @@
|
|||
<a name="%(crm_case_form_view_salesteams_opportunity)d" type="action">Opportunities</a>
|
||||
<a name="%(action_report_crm_opportunity_salesteam)d" type="action">
|
||||
<field name="monthly_planned_revenue" widget="sparkline_bar"
|
||||
options="{'height': '20px', 'barWidth': '4', 'barSpacing': '1', 'delayIn': '3000', 'tooltip_suffix': 'Opportunities'}">Planned Revenue per Month<br/>Click to see a detailed analysis of opportunities.</field>
|
||||
options="{'height': '20px', 'barWidth': '4', 'barSpacing': '1', 'delayIn': '3000', 'tooltip_suffix': ' (Planned Revenue)'}">Planned Revenue per Month<br/>Click to see a detailed analysis of opportunities.</field>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -330,6 +330,7 @@ class crm_lead(format_address, osv.osv):
|
|||
'phone': partner.phone,
|
||||
'mobile': partner.mobile,
|
||||
'fax': partner.fax,
|
||||
'zip': partner.zip,
|
||||
}
|
||||
return {'value': values}
|
||||
|
||||
|
|
|
@ -146,6 +146,7 @@
|
|||
<!-- CRM-related subtypes for messaging / Chatter -->
|
||||
<record id="mt_lead_create" model="mail.message.subtype">
|
||||
<field name="name">Lead Created</field>
|
||||
<field name="hidden" eval="True"/>
|
||||
<field name="res_model">crm.lead</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Lead created</field>
|
||||
|
@ -171,6 +172,7 @@
|
|||
<!-- Salesteam-related subtypes for messaging / Chatter -->
|
||||
<record id="mt_salesteam_lead" model="mail.message.subtype">
|
||||
<field name="name">Lead Created</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">crm.case.section</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="parent_id" eval="ref('mt_lead_create')"/>
|
||||
|
@ -178,18 +180,21 @@
|
|||
</record>
|
||||
<record id="mt_salesteam_lead_stage" model="mail.message.subtype">
|
||||
<field name="name">Opportunity Stage Changed</field>
|
||||
<field name="sequence">11</field>
|
||||
<field name="res_model">crm.case.section</field>
|
||||
<field name="parent_id" eval="ref('mt_lead_stage')"/>
|
||||
<field name="relation_field">section_id</field>
|
||||
</record>
|
||||
<record id="mt_salesteam_lead_won" model="mail.message.subtype">
|
||||
<field name="name">Opportunity Won</field>
|
||||
<field name="sequence">12</field>
|
||||
<field name="res_model">crm.case.section</field>
|
||||
<field name="parent_id" eval="ref('mt_lead_won')"/>
|
||||
<field name="relation_field">section_id</field>
|
||||
</record>
|
||||
<record id="mt_salesteam_lead_lost" model="mail.message.subtype">
|
||||
<field name="name">Opportunity Lost</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="res_model">crm.case.section</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="parent_id" eval="ref('mt_lead_lost')"/>
|
||||
|
|
|
@ -343,6 +343,7 @@
|
|||
help="Leads that are assigned to any sales teams I am member of"/>
|
||||
<filter string="Dead" name="dead"
|
||||
domain="[('probability', '=', '0'), ('stage_id.fold', '=', True)]"/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator />
|
||||
<filter string="Available for mass mailing"
|
||||
name='not_opt_out' domain="[('opt_out', '=', False)]"
|
||||
|
@ -562,6 +563,7 @@
|
|||
<filter string="My Team(s)"
|
||||
domain="[('section_id.member_ids', 'in', [uid])]" context="{'invisible_section': False}"
|
||||
help="Opportunities that are assigned to any sales teams I am member of"/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<group expand="0" string="Group By..." colspan="16">
|
||||
<filter string="Salesperson" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
|
|
|
@ -171,6 +171,7 @@
|
|||
<filter icon="terp-gtk-go-back-rtl" string="To Do" name="current" domain="[('state','=','open')]"/>
|
||||
<separator/>
|
||||
<filter string="Unassigned Phonecalls" icon="terp-personal-" domain="[('user_id','=',False)]" help="Unassigned Phonecalls"/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="Phone Calls Assigned to Me or My Team(s)" icon="terp-personal+" domain="['|', ('section_id.user_id','=',uid), ('user_id', '=', uid)]"
|
||||
help="Phone Calls Assigned to the current user or with a team having the current user as team leader"/>
|
||||
|
|
|
@ -89,10 +89,6 @@ class crm_lead_report(osv.osv):
|
|||
id,
|
||||
c.date_deadline,
|
||||
|
||||
to_char(c.create_date, 'YYYY') as creation_year,
|
||||
to_char(c.create_date, 'MM') as creation_month,
|
||||
to_char(c.create_date, 'YYYY-MM-DD') as creation_day,
|
||||
|
||||
to_char(c.date_open, 'YYYY-MM-DD') as opening_date,
|
||||
to_char(c.date_closed, 'YYYY-mm-dd') as date_closed,
|
||||
|
||||
|
|
|
@ -15,6 +15,17 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_report_crm_lead_graph_two" model="ir.ui.view">
|
||||
<field name="name">crm.lead.report.graph.two</field>
|
||||
<field name="model">crm.lead.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Leads Analysis" type="pivot" stacked="True">
|
||||
<field name="create_date" type="row"/>
|
||||
<field name="user_id" type="col"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_report_crm_opportunity_graph" model="ir.ui.view">
|
||||
<field name="name">crm.opportunity.report.graph</field>
|
||||
<field name="model">crm.lead.report</field>
|
||||
|
@ -23,7 +34,7 @@
|
|||
<field name="date_deadline" type="row"/>
|
||||
<field name="user_id" type="col"/>
|
||||
<field name="stage_id" type="col"/>
|
||||
<field name="probable_revenue" type="measure"/>
|
||||
<field name="planned_revenue" type="measure"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -84,7 +95,7 @@
|
|||
<filter string="Creation date (week)" icon="terp-go-year"
|
||||
domain="[]" context="{'group_by':'create_date:week'}"/>
|
||||
<filter string="Creation date (month)" icon="terp-go-year"
|
||||
domain="[]" context="{'group_by':'create_date:month'}"/>
|
||||
domain="[]" context="{'group_by':'create_date:month'}" name="month"/>
|
||||
<filter string="Creation date (year)" icon="terp-go-year"
|
||||
domain="[]" context="{'group_by':'create_date:year'}"/>
|
||||
<separator orientation="vertical" />
|
||||
|
|
|
@ -140,8 +140,8 @@
|
|||
</group>
|
||||
<group col="2">
|
||||
<separator string="Categorization" colspan="2"/>
|
||||
<field name="type_id" widget="selection" readonly="1"/>
|
||||
<field name="channel_id" widget="selection" readonly="1"/>
|
||||
<field name="type_id" readonly="1"/>
|
||||
<field name="channel_id" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="Details" />
|
||||
|
|
|
@ -381,12 +381,18 @@ class email_template(osv.osv):
|
|||
for res_id in template_res_ids:
|
||||
attachments = []
|
||||
report_name = self.render_template(cr, uid, template.report_name, template.model, res_id, context=context)
|
||||
report_service = report_xml_pool.browse(cr, uid, template.report_template.id, context).report_name
|
||||
report = report_xml_pool.browse(cr, uid, template.report_template.id, context)
|
||||
report_service = report.report_name
|
||||
# Ensure report is rendered using template's language
|
||||
ctx = context.copy()
|
||||
if template.lang:
|
||||
ctx['lang'] = self.render_template_batch(cr, uid, template.lang, template.model, [res_id], context)[res_id] # take 0 ?
|
||||
|
||||
if report.report_type in ['qweb-html', 'qweb-pdf']:
|
||||
result, format = self.pool['report'].get_pdf(report, res_id, context=ctx), 'pdf'
|
||||
else:
|
||||
result, format = openerp.report.render_report(cr, uid, [res_id], report_service, {'model': template.model}, ctx)
|
||||
|
||||
result = base64.b64encode(result)
|
||||
if not report_name:
|
||||
report_name = 'report.' + report_service
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
<h3>Body</h3>
|
||||
<field name="body_html" width="250" height="450"
|
||||
placeholder="Rich-text/HTML content of the message (placeholders may be used here)"/>
|
||||
<field name="attachment_ids" nolabel="1" widget="many2many_binary"/>
|
||||
<field name="attachment_ids" widget="many2many_binary"/>
|
||||
</page>
|
||||
<page string="Advanced Settings">
|
||||
<group>
|
||||
|
|
|
@ -219,6 +219,7 @@ class event_event(osv.osv):
|
|||
]
|
||||
|
||||
def onchange_event_type(self, cr, uid, ids, type_event, context=None):
|
||||
values = {}
|
||||
if type_event:
|
||||
type_info = self.pool.get('event.type').browse(cr,uid,type_event,context)
|
||||
dic ={
|
||||
|
@ -228,7 +229,8 @@ class event_event(osv.osv):
|
|||
'seats_min': type_info.default_registration_min,
|
||||
'seats_max': type_info.default_registration_max,
|
||||
}
|
||||
return {'value': dic}
|
||||
values.update(dic)
|
||||
return values
|
||||
|
||||
def onchange_start_date(self, cr, uid, ids, date_begin=False, date_end=False, context=None):
|
||||
res = {'value':{}}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
# Finnish translation for openobject-addons
|
||||
# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2014-02-18 20:10+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Finnish <fi@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-02-19 05:23+0000\n"
|
||||
"X-Generator: Launchpad (build 16916)\n"
|
||||
|
||||
#. module: event_sale
|
||||
#: model:ir.model,name:event_sale.model_product_product
|
||||
msgid "Product"
|
||||
msgstr "Tuote"
|
||||
|
||||
#. module: event_sale
|
||||
#: help:product.product,event_ok:0
|
||||
msgid ""
|
||||
"Determine if a product needs to create automatically an event registration "
|
||||
"at the confirmation of a sales order line."
|
||||
msgstr ""
|
||||
|
||||
#. module: event_sale
|
||||
#: help:sale.order.line,event_id:0
|
||||
msgid ""
|
||||
"Choose an event and it will automatically create a registration for this "
|
||||
"event."
|
||||
msgstr ""
|
||||
"Valitse tapahtuma ja se luo automaattisesti rekisteröinnin kyseiseen "
|
||||
"tapahtumaan."
|
||||
|
||||
#. module: event_sale
|
||||
#: model:event.event,name:event_sale.event_technical_training
|
||||
msgid "Technical training in Grand-Rosiere"
|
||||
msgstr ""
|
||||
|
||||
#. module: event_sale
|
||||
#: help:product.product,event_type_id:0
|
||||
msgid ""
|
||||
"Select event types so when we use this product in sales order lines, it will "
|
||||
"filter events of this type only."
|
||||
msgstr ""
|
||||
"Valitse tapahtumatyypit, joiden avulla myyntitilausrivillä voidaan suodattaa "
|
||||
"vain tämän tyyppiset tapahtumat."
|
||||
|
||||
#. module: event_sale
|
||||
#: field:product.product,event_type_id:0
|
||||
msgid "Type of Event"
|
||||
msgstr "Tapahtumatyyppi"
|
||||
|
||||
#. module: event_sale
|
||||
#: field:sale.order.line,event_ok:0
|
||||
msgid "event_ok"
|
||||
msgstr ""
|
||||
|
||||
#. module: event_sale
|
||||
#: field:product.product,event_ok:0
|
||||
msgid "Event Subscription"
|
||||
msgstr "Tapahtumaan rekisteröityminen"
|
||||
|
||||
#. module: event_sale
|
||||
#: field:sale.order.line,event_type_id:0
|
||||
msgid "Event Type"
|
||||
msgstr "Tapahtumatyyppi"
|
||||
|
||||
#. module: event_sale
|
||||
#: model:product.template,name:event_sale.event_product_product_template
|
||||
msgid "Technical Training"
|
||||
msgstr "Tekninen koulutus"
|
||||
|
||||
#. module: event_sale
|
||||
#: code:addons/event_sale/event_sale.py:88
|
||||
#, python-format
|
||||
msgid "The registration %s has been created from the Sales Order %s."
|
||||
msgstr "Rekisteröinti %s on luotu myyntitilaukselta %s."
|
||||
|
||||
#. module: event_sale
|
||||
#: field:sale.order.line,event_id:0
|
||||
msgid "Event"
|
||||
msgstr "Tapahtuma"
|
||||
|
||||
#. module: event_sale
|
||||
#: model:ir.model,name:event_sale.model_sale_order_line
|
||||
msgid "Sales Order Line"
|
||||
msgstr "Myyntitilausrivi"
|
|
@ -187,7 +187,7 @@ openerp_mailgate: "|/path/to/openerp-mailgate.py --host=localhost -u %(uid)d -p
|
|||
for server in self.browse(cr, uid, ids, context=context):
|
||||
_logger.info('start checking for new emails on %s server %s', server.type, server.name)
|
||||
context.update({'fetchmail_server_id': server.id, 'server_type': server.type})
|
||||
count = 0
|
||||
count, failed = 0, 0
|
||||
imap_server = False
|
||||
pop_server = False
|
||||
if server.type == 'imap':
|
||||
|
@ -196,20 +196,26 @@ openerp_mailgate: "|/path/to/openerp-mailgate.py --host=localhost -u %(uid)d -p
|
|||
imap_server.select()
|
||||
result, data = imap_server.search(None, '(UNSEEN)')
|
||||
for num in data[0].split():
|
||||
res_id = None
|
||||
result, data = imap_server.fetch(num, '(RFC822)')
|
||||
imap_server.store(num, '-FLAGS', '\\Seen')
|
||||
try:
|
||||
res_id = mail_thread.message_process(cr, uid, server.object_id.model,
|
||||
data[0][1],
|
||||
save_original=server.original,
|
||||
strip_attachments=(not server.attach),
|
||||
context=context)
|
||||
except Exception:
|
||||
_logger.exception('Failed to process mail from %s server %s.', server.type, server.name)
|
||||
failed += 1
|
||||
if res_id and server.action_id:
|
||||
action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids': [res_id], 'active_model': context.get("thread_model", server.object_id.model)})
|
||||
imap_server.store(num, '+FLAGS', '\\Seen')
|
||||
cr.commit()
|
||||
count += 1
|
||||
_logger.info("fetched/processed %s email(s) on %s server %s", count, server.type, server.name)
|
||||
_logger.info("Fetched %d email(s) on %s server %s; %d succeeded, %d failed.", count, server.type, server.name, (count - failed), failed)
|
||||
except Exception:
|
||||
_logger.exception("Failed to fetch mail from %s server %s.", server.type, server.name)
|
||||
_logger.exception("General failure when trying to fetch mail from %s server %s.", server.type, server.name)
|
||||
finally:
|
||||
if imap_server:
|
||||
imap_server.close()
|
||||
|
@ -222,18 +228,23 @@ openerp_mailgate: "|/path/to/openerp-mailgate.py --host=localhost -u %(uid)d -p
|
|||
for num in range(1, numMsgs + 1):
|
||||
(header, msges, octets) = pop_server.retr(num)
|
||||
msg = '\n'.join(msges)
|
||||
res_id = None
|
||||
try:
|
||||
res_id = mail_thread.message_process(cr, uid, server.object_id.model,
|
||||
msg,
|
||||
save_original=server.original,
|
||||
strip_attachments=(not server.attach),
|
||||
context=context)
|
||||
except Exception:
|
||||
_logger.exception('Failed to process mail from %s server %s.', server.type, server.name)
|
||||
failed += 1
|
||||
if res_id and server.action_id:
|
||||
action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids': [res_id], 'active_model': context.get("thread_model", server.object_id.model)})
|
||||
pop_server.dele(num)
|
||||
cr.commit()
|
||||
_logger.info("fetched/processed %s email(s) on %s server %s", numMsgs, server.type, server.name)
|
||||
_logger.info("Fetched %d email(s) on %s server %s; %d succeeded, %d failed.", numMsgs, server.type, server.name, (numMsgs - failed), failed)
|
||||
except Exception:
|
||||
_logger.exception("Failed to fetch mail from %s server %s.", server.type, server.name)
|
||||
_logger.exception("General failure when trying to fetch mail from %s server %s.", server.type, server.name)
|
||||
finally:
|
||||
if pop_server:
|
||||
pop_server.quit()
|
||||
|
|
|
@ -62,19 +62,8 @@ class fleet_vehicle_cost(osv.Model):
|
|||
res[record.id] = _('Unknown')
|
||||
return res
|
||||
|
||||
def _cost_name_get_fnc(self, cr, uid, ids, name, unknow_none, context=None):
|
||||
res = {}
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
name = record.vehicle_id.name
|
||||
if record.cost_subtype_id.name:
|
||||
name += ' / '+ record.cost_subtype_id.name
|
||||
if record.date:
|
||||
name += ' / '+ record.date
|
||||
res[record.id] = name
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'name': fields.function(_cost_name_get_fnc, type="char", string='Name', store=True),
|
||||
'name': fields.related('vehicle_id', 'name', type="char", string='Name', store=True),
|
||||
'vehicle_id': fields.many2one('fleet.vehicle', 'Vehicle', required=True, help='Vehicle concerned by this log'),
|
||||
'cost_subtype_id': fields.many2one('fleet.service.type', 'Type', help='Cost type purchased with this cost'),
|
||||
'amount': fields.float('Total Price'),
|
||||
|
|
|
@ -832,6 +832,9 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
fleet.vehicle.cost
|
||||
-->
|
||||
<record model='ir.actions.act_window' id='fleet_vehicle_service_types_act'>
|
||||
<field name="name">Service Types</field>
|
||||
<field name="res_model">fleet.service.type</field>
|
||||
|
@ -848,6 +851,17 @@
|
|||
|
||||
<menuitem action="fleet_vehicle_service_types_act" parent="fleet_configuration" id="fleet_vehicle_service_types_menu" groups="base.group_no_one"/>
|
||||
|
||||
<record model='ir.ui.view' id='fleet_vehicle_cost_tree'>
|
||||
<field name="name">fleet.vehicle.cost.tree</field>
|
||||
<field name="model">fleet.vehicle.cost</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Vehicle Costs">
|
||||
<field name="vehicle_id"/>
|
||||
<field name="cost_subtype_id"/>
|
||||
<field name="date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model='ir.ui.view' id='fleet_vehicle_costs_report'>
|
||||
<field name="name">fleet.vehicle.cost.graph</field>
|
||||
|
@ -939,31 +953,5 @@
|
|||
</record>
|
||||
|
||||
<menuitem action="fleet_vehicle_costs_act" parent="fleet_vehicles" id="fleet_vehicle_costs_menu" groups="group_fleet_manager"/>
|
||||
<!--
|
||||
<record model='ir.ui.view' id='fleet_hr_employee_form'>
|
||||
<field name="name">fleet.hr.employee.form</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="hr.view_employee_form" />
|
||||
<field name="arch" type="xml">
|
||||
<notebook position="inside">
|
||||
<page string="Vehicle">
|
||||
<group>
|
||||
<field name="vehicle_id" widget="many2many_tags"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="fleet.vehicle.model" id="citroen">
|
||||
<field name="name">Citroen</field>
|
||||
</record>
|
||||
|
||||
<record model="fleet.vehicle" id="stw_vehicle">
|
||||
<field name="name">240BTN</field>
|
||||
<field name="model_id" ref="citroen" />
|
||||
</record>
|
||||
-->
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
<section class="oe_container">
|
||||
<div class="oe_row oe_spaced">
|
||||
<div class="oe_span12">
|
||||
<h2 class="oe_slogan">Drive Engagement with Gamification</h2>
|
||||
<h3 class="oe_slogan">Leverage natural desire for competition</h3>
|
||||
<p class="oe_mt32">
|
||||
Reinforce good habits and improve win rates with real-time recognition and rewards inspired by <a href="http://en.wikipedia.org/wiki/Gamification">game mechanics</a>. Align teams around clear business objectives with challenges, personal objectives and team leader boards.
|
||||
</p>
|
||||
<div class="oe_span4 oe_centered">
|
||||
<h3>Leaderboards</h3>
|
||||
<div class="oe_row_img oe_centered">
|
||||
<img class="oe_picture" src="crm_game_01.png">
|
||||
</div>
|
||||
<p>
|
||||
Promote leaders and competition amongst sales team with performance ratios.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oe_span4 oe_centered">
|
||||
<h3>Personnal Objectives</h3>
|
||||
<div class="oe_row_img">
|
||||
<img class="oe_picture" src="crm_game_02.png">
|
||||
</div>
|
||||
<p>
|
||||
Assign clear goals to users to align them with the company objectives.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oe_span4 oe_centered">
|
||||
<h3>Visual Information</h3>
|
||||
<div class="oe_row_img oe_centered">
|
||||
<img class="oe_picture" src="crm_game_03.png">
|
||||
</div>
|
||||
<p>
|
||||
See in an glance the progress of each user.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="oe_container oe_dark">
|
||||
<div class="oe_row oe_spaced">
|
||||
<h2 class="oe_slogan">Create custom Challenges</h2>
|
||||
<div class="oe_span6">
|
||||
<p class="oe_mt32">
|
||||
Use predefined goals to generate easily your own challenges. Assign it to a team or individual users. Receive feedback as often as needed: daily, weekly... Repeat it automatically to compare progresses through time.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<div class="oe_row_img oe_centered">
|
||||
<img class="oe_picture oe_screenshot" src="crm_sc_05.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="oe_container">
|
||||
<div class="oe_row oe_spaced">
|
||||
<h2 class="oe_slogan">Motivate with Badges</h2>
|
||||
<div class="oe_span6">
|
||||
<div class="oe_row_img oe_centered">
|
||||
<img class="oe_picture" src="crm_linkedin.png">
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<p class="oe_mt32">
|
||||
Inspire achievement with recognition of coworker's good work by rewarding badges. These can be deserved manually or upon completion of challenges. Add fun to the competition with rare badges.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="oe_container oe_dark">
|
||||
<div class="oe_row oe_spaced">
|
||||
<h2 class="oe_slogan">Adapt to any module</h2>
|
||||
<div class="oe_span6">
|
||||
<p class="oe_mt32">
|
||||
Create goals linked to any module. The evaluation system is very flexible and can be used for many different tasks : sales evaluation, creation of events, project completion or even helping new users to complete their profile.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<div class="oe_row_img oe_centered">
|
||||
<img class="oe_picture oe_screenshot" src="crm_sc_02.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
|
@ -4,10 +4,10 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 8.0alpha1\n"
|
||||
"Project-Id-Version: OpenERP Server 7.saas~3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-02-13 15:08+0000\n"
|
||||
"PO-Revision-Date: 2014-02-13 15:08+0000\n"
|
||||
"POT-Creation-Date: 2014-02-13 15:03+0000\n"
|
||||
"PO-Revision-Date: 2014-02-13 15:03+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
|
|
@ -433,7 +433,7 @@ class gamification_challenge(osv.Model):
|
|||
##### JS utilities #####
|
||||
|
||||
def _get_serialized_challenge_lines(self, cr, uid, challenge, user_id=False, restrict_goal_ids=False, restrict_top=False, context=None):
|
||||
"""Return a serialised version of the goals information
|
||||
"""Return a serialised version of the goals information if the user has not completed every goal
|
||||
|
||||
:challenge: browse record of challenge to compute
|
||||
:user_id: res.users id of the user retrieving progress (False if no distinction, only for ranking challenges)
|
||||
|
@ -487,6 +487,7 @@ class gamification_challenge(osv.Model):
|
|||
(start_date, end_date) = start_end_date_for_period(challenge.period)
|
||||
|
||||
res_lines = []
|
||||
all_reached = True
|
||||
for line in challenge.line_ids:
|
||||
line_data = {
|
||||
'name': line.definition_id.name,
|
||||
|
@ -537,6 +538,8 @@ class gamification_challenge(osv.Model):
|
|||
'completeness': goal.completeness,
|
||||
'state': goal.state,
|
||||
})
|
||||
if goal.state != 'reached':
|
||||
all_reached = False
|
||||
else:
|
||||
ranking += 1
|
||||
if user_id and goal.user_id.id == user_id:
|
||||
|
@ -554,8 +557,12 @@ class gamification_challenge(osv.Model):
|
|||
'completeness': goal.completeness,
|
||||
'state': goal.state,
|
||||
})
|
||||
if goal.state != 'reached':
|
||||
all_reached = False
|
||||
if goal_ids:
|
||||
res_lines.append(line_data)
|
||||
if all_reached:
|
||||
return []
|
||||
return res_lines
|
||||
|
||||
##### Reporting #####
|
||||
|
@ -620,22 +627,28 @@ class gamification_challenge(osv.Model):
|
|||
return self.write(cr, uid, challenge.id, {'last_report_date': fields.date.today()}, context=context)
|
||||
|
||||
##### Challenges #####
|
||||
# TODO in trunk, remove unused parameter user_id
|
||||
def accept_challenge(self, cr, uid, challenge_ids, context=None, user_id=None):
|
||||
"""The user accept the suggested challenge"""
|
||||
user_id = user_id or uid
|
||||
return self._accept_challenge(cr, uid, uid, challenge_ids, context=context)
|
||||
|
||||
def _accept_challenge(self, cr, uid, user_id, challenge_ids, context=None):
|
||||
user = self.pool.get('res.users').browse(cr, uid, user_id, context=context)
|
||||
message = "%s has joined the challenge" % user.name
|
||||
self.message_post(cr, uid, challenge_ids, body=message, context=context)
|
||||
self.message_post(cr, SUPERUSER_ID, challenge_ids, body=message, context=context)
|
||||
self.write(cr, SUPERUSER_ID, challenge_ids, {'invited_user_ids': [(3, user_id)], 'user_ids': [(4, user_id)]}, context=context)
|
||||
return self.generate_goals_from_challenge(cr, uid, challenge_ids, context=context)
|
||||
return self.generate_goals_from_challenge(cr, SUPERUSER_ID, challenge_ids, context=context)
|
||||
|
||||
# TODO in trunk, remove unused parameter user_id
|
||||
def discard_challenge(self, cr, uid, challenge_ids, context=None, user_id=None):
|
||||
"""The user discard the suggested challenge"""
|
||||
user_id = user_id or uid
|
||||
return self._discard_challenge(cr, uid, uid, challenge_ids, context=context)
|
||||
|
||||
def _discard_challenge(self, cr, uid, user_id, challenge_ids, context=None):
|
||||
user = self.pool.get('res.users').browse(cr, uid, user_id, context=context)
|
||||
message = "%s has refused the challenge" % user.name
|
||||
self.message_post(cr, SUPERUSER_ID, challenge_ids, body=message, context=context)
|
||||
return self.write(cr, uid, challenge_ids, {'invited_user_ids': (3, user_id)}, context=context)
|
||||
return self.write(cr, SUPERUSER_ID, challenge_ids, {'invited_user_ids': (3, user_id)}, context=context)
|
||||
|
||||
def reply_challenge_wizard(self, cr, uid, challenge_id, context=None):
|
||||
result = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'gamification', 'challenge_wizard')
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.osv import osv
|
||||
from challenge import MAX_VISIBILITY_RANKING
|
||||
|
||||
|
@ -39,10 +40,10 @@ class res_users_gamification_group(osv.Model):
|
|||
user_group_ids += [id for command in vals['groups_id'] if command[0] == 6 for id in command[2]]
|
||||
|
||||
challenge_obj = self.pool.get('gamification.challenge')
|
||||
challenge_ids = challenge_obj.search(cr, uid, [('autojoin_group_id', 'in', user_group_ids)], context=context)
|
||||
challenge_ids = challenge_obj.search(cr, SUPERUSER_ID, [('autojoin_group_id', 'in', user_group_ids)], context=context)
|
||||
if challenge_ids:
|
||||
challenge_obj.write(cr, uid, challenge_ids, {'user_ids': [(4, user_id) for user_id in ids]}, context=context)
|
||||
challenge_obj.generate_goals_from_challenge(cr, uid, challenge_ids, context=context)
|
||||
challenge_obj.write(cr, SUPERUSER_ID, challenge_ids, {'user_ids': [(4, user_id) for user_id in ids]}, context=context)
|
||||
challenge_obj.generate_goals_from_challenge(cr, SUPERUSER_ID, challenge_ids, context=context)
|
||||
return write_res
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
|
@ -54,10 +55,10 @@ class res_users_gamification_group(osv.Model):
|
|||
user_group_ids += [id for command in vals['groups_id'] if command[0] == 6 for id in command[2]]
|
||||
|
||||
challenge_obj = self.pool.get('gamification.challenge')
|
||||
challenge_ids = challenge_obj.search(cr, uid, [('autojoin_group_id', 'in', user_group_ids)], context=context)
|
||||
challenge_ids = challenge_obj.search(cr, SUPERUSER_ID, [('autojoin_group_id', 'in', user_group_ids)], context=context)
|
||||
if challenge_ids:
|
||||
challenge_obj.write(cr, uid, challenge_ids, {'user_ids': [(4, write_res)]}, context=context)
|
||||
challenge_obj.generate_goals_from_challenge(cr, uid, challenge_ids, context=context)
|
||||
challenge_obj.write(cr, SUPERUSER_ID, challenge_ids, {'user_ids': [(4, write_res)]}, context=context)
|
||||
challenge_obj.generate_goals_from_challenge(cr, SUPERUSER_ID, challenge_ids, context=context)
|
||||
return write_res
|
||||
|
||||
# def get_goals_todo_info(self, cr, uid, context=None):
|
||||
|
@ -130,8 +131,8 @@ class res_groups_gamification_group(osv.Model):
|
|||
user_ids += [id for command in vals['users'] if command[0] == 6 for id in command[2]]
|
||||
|
||||
challenge_obj = self.pool.get('gamification.challenge')
|
||||
challenge_ids = challenge_obj.search(cr, uid, [('autojoin_group_id', 'in', ids)], context=context)
|
||||
challenge_ids = challenge_obj.search(cr, SUPERUSER_ID, [('autojoin_group_id', 'in', ids)], context=context)
|
||||
if challenge_ids:
|
||||
challenge_obj.write(cr, uid, challenge_ids, {'user_ids': [(4, user_id) for user_id in user_ids]}, context=context)
|
||||
challenge_obj.generate_goals_from_challenge(cr, uid, challenge_ids, context=context)
|
||||
challenge_obj.write(cr, SUPERUSER_ID, challenge_ids, {'user_ids': [(4, user_id) for user_id in user_ids]}, context=context)
|
||||
challenge_obj.generate_goals_from_challenge(cr, SUPERUSER_ID, challenge_ids, context=context)
|
||||
return write_res
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
# 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
|
||||
|
@ -36,6 +37,168 @@ from dateutil import parser
|
|||
import pytz
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.osv import osv
|
||||
from collections import namedtuple
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Meta(type):
|
||||
""" This Meta class allow to define class as a structure, and so instancied variable
|
||||
in __init__ to avoid to have side effect alike 'static' variable """
|
||||
def __new__(typ, name, parents, attrs):
|
||||
methods = dict((k, v) for k, v in attrs.iteritems()
|
||||
if callable(v))
|
||||
attrs = dict((k, v) for k, v in attrs.iteritems()
|
||||
if not callable(v))
|
||||
|
||||
def init(self, **kw):
|
||||
for k, v in attrs.iteritems():
|
||||
setattr(self, k, v)
|
||||
for k, v in kw.iteritems():
|
||||
assert k in attrs
|
||||
setattr(self, k, v)
|
||||
|
||||
methods['__init__'] = init
|
||||
methods['__getitem__'] = getattr
|
||||
return type.__new__(typ, name, parents, methods)
|
||||
|
||||
class Struct(object):
|
||||
__metaclass__ = Meta
|
||||
|
||||
class OpenerpEvent(Struct):
|
||||
event = False
|
||||
found = False
|
||||
event_id = False
|
||||
isRecurrence = False
|
||||
isInstance = False
|
||||
update = False
|
||||
status = False
|
||||
attendee_id = False
|
||||
synchro = False
|
||||
|
||||
class GmailEvent(Struct):
|
||||
event = False
|
||||
found = False
|
||||
isRecurrence = False
|
||||
isInstance = False
|
||||
update = False
|
||||
status = False
|
||||
|
||||
class SyncEvent(object):
|
||||
def __init__(self):
|
||||
self.OE = OpenerpEvent()
|
||||
self.GG = GmailEvent()
|
||||
self.OP = None
|
||||
|
||||
def __getitem__(self, key):
|
||||
return getattr(self,key)
|
||||
|
||||
def compute_OP(self):
|
||||
#If event are already in Gmail and in OpenERP
|
||||
if self.OE.found and self.GG.found:
|
||||
#If the event has been deleted from one side, we delete on other side !
|
||||
if self.OE.status != self.GG.status:
|
||||
self.OP = Delete((self.OE.status and "OE") or (self.GG.status and "GG"),
|
||||
'The event has been deleted from one side, we delete on other side !' )
|
||||
#If event is not deleted !
|
||||
elif self.OE.status and self.GG.status:
|
||||
if self.OE.update.split('.')[0] != self.GG.update.split('.')[0]:
|
||||
if self.OE.update < self.GG.update:
|
||||
tmpSrc = 'GG'
|
||||
elif self.OE.update > self.GG.update:
|
||||
tmpSrc = 'OE'
|
||||
assert tmpSrc in ['GG','OE']
|
||||
|
||||
|
||||
#if self.OP.action == None:
|
||||
if self[tmpSrc].isRecurrence:
|
||||
if self[tmpSrc].status:
|
||||
self.OP = Update(tmpSrc, 'Only need to update, because i\'m active')
|
||||
else:
|
||||
self.OP = Exclude(tmpSrc, 'Need to Exclude (Me = First event from recurrence) from recurrence')
|
||||
|
||||
elif self[tmpSrc].isInstance:
|
||||
self.OP= Update(tmpSrc, 'Only need to update, because already an exclu');
|
||||
else:
|
||||
self.OP = Update(tmpSrc, 'Simply Update... I\'m a single event');
|
||||
#end-if self.OP.action == None:
|
||||
|
||||
else:
|
||||
if not self.OE.synchro or self.OE.synchro.split('.')[0] < self.OE.update.split('.')[0]:
|
||||
self.OP = Update('OE','Event already updated by another user, but not synchro with my google calendar')
|
||||
#import ipdb; ipdb.set_trace();
|
||||
else:
|
||||
self.OP = NothingToDo("",'Not update needed')
|
||||
else:
|
||||
self.OP = NothingToDo("", "Both are already deleted");
|
||||
|
||||
# New in openERP... Create on create_events of synchronize function
|
||||
elif self.OE.found and not self.GG.found:
|
||||
#Has been deleted from gmail
|
||||
if self.OE.status:
|
||||
self.OP = Delete('OE', 'Removed from GOOGLE')
|
||||
else:
|
||||
self.OP = NothingToDo("","Already Deleted in gmail and unlinked in OpenERP")
|
||||
elif self.GG.found and not self.OE.found:
|
||||
tmpSrc = 'GG'
|
||||
if not self.GG.status and not self.GG.isInstance:
|
||||
# don't need to make something... because event has been created and deleted before the synchronization
|
||||
self.OP = NothingToDo("", 'Nothing to do... Create and Delete directly')
|
||||
else:
|
||||
if self.GG.isInstance:
|
||||
if self[tmpSrc].status:
|
||||
self.OP = Exclude(tmpSrc, 'Need to create the new exclu')
|
||||
else:
|
||||
self.OP = Exclude(tmpSrc, 'Need to copy and Exclude')
|
||||
else:
|
||||
self.OP = Create(tmpSrc, 'New EVENT CREATE from GMAIL')
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def __repr__(self):
|
||||
myPrint = "---- A SYNC EVENT ---"
|
||||
myPrint += "\n ID OE: %s " % (self.OE.event and self.OE.event.id)
|
||||
myPrint += "\n ID GG: %s " % (self.GG.event and self.GG.event.get('id', False))
|
||||
myPrint += "\n Name OE: %s " % (self.OE.event and self.OE.event.name)
|
||||
myPrint += "\n Name GG: %s " % (self.GG.event and self.GG.event.get('summary', False))
|
||||
myPrint += "\n Found OE:%5s vs GG: %5s" % (self.OE.found, self.GG.found)
|
||||
myPrint += "\n Recurrence OE:%5s vs GG: %5s" % (self.OE.isRecurrence, self.GG.isRecurrence)
|
||||
myPrint += "\n Instance OE:%5s vs GG: %5s" % (self.OE.isInstance, self.GG.isInstance)
|
||||
myPrint += "\n Synchro OE: %10s " % (self.OE.synchro)
|
||||
myPrint += "\n Update OE: %10s " % (self.OE.update)
|
||||
myPrint += "\n Update GG: %10s " % (self.GG.update)
|
||||
myPrint += "\n Status OE:%5s vs GG: %5s" % (self.OE.status, self.GG.status)
|
||||
if (self.OP is None):
|
||||
myPrint += "\n Action %s" % "---!!!---NONE---!!!---"
|
||||
else:
|
||||
myPrint += "\n Action %s" % type(self.OP).__name__
|
||||
myPrint += "\n Source %s" % (self.OP.src)
|
||||
myPrint += "\n comment %s" % (self.OP.info)
|
||||
return myPrint
|
||||
|
||||
|
||||
class SyncOperation(object):
|
||||
def __init__(self, src,info, **kw):
|
||||
self.src = src
|
||||
self.info = info
|
||||
for k,v in kw.items():
|
||||
setattr(self,k,v)
|
||||
|
||||
def __str__(self):
|
||||
return 'in__STR__'
|
||||
|
||||
class Create(SyncOperation):
|
||||
pass
|
||||
class Update(SyncOperation):
|
||||
pass
|
||||
class Delete(SyncOperation):
|
||||
pass
|
||||
class NothingToDo(SyncOperation):
|
||||
pass
|
||||
class Exclude(SyncOperation):
|
||||
pass
|
||||
|
||||
|
||||
class google_calendar(osv.AbstractModel):
|
||||
|
@ -47,10 +210,12 @@ class google_calendar(osv.AbstractModel):
|
|||
start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT) , context=context).isoformat('T').split('T')[0]
|
||||
end_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(hours=event.duration), context=context).isoformat('T').split('T')[0]
|
||||
type = 'date'
|
||||
vstype = 'dateTime'
|
||||
else:
|
||||
start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context).isoformat('T')
|
||||
end_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.date_deadline, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context).isoformat('T')
|
||||
type = 'dateTime'
|
||||
vstype = 'date'
|
||||
attendee_list = []
|
||||
|
||||
for attendee in event.attendee_ids:
|
||||
|
@ -64,10 +229,12 @@ class google_calendar(osv.AbstractModel):
|
|||
"description": event.description or '',
|
||||
"start":{
|
||||
type:start_date,
|
||||
vstype:None,
|
||||
'timeZone':'UTC'
|
||||
},
|
||||
"end":{
|
||||
type:end_date,
|
||||
vstype:None,
|
||||
'timeZone':'UTC'
|
||||
},
|
||||
"attendees":attendee_list,
|
||||
|
@ -80,10 +247,13 @@ class google_calendar(osv.AbstractModel):
|
|||
if not event.active:
|
||||
data["state"] = "cancelled"
|
||||
|
||||
if not self.get_need_synchro_attendee(cr,uid,context=context):
|
||||
data.pop("attendees")
|
||||
|
||||
return data
|
||||
|
||||
def create_an_event(self, cr, uid,event, context=None):
|
||||
gs_pool = self.pool.get('google.service')
|
||||
gs_pool = self.pool['google.service']
|
||||
|
||||
data = self.generate_data(cr, uid,event, context=context)
|
||||
|
||||
|
@ -94,7 +264,7 @@ class google_calendar(osv.AbstractModel):
|
|||
return gs_pool._do_request(cr, uid, url, data_json, headers, type='POST', context=context)
|
||||
|
||||
def delete_an_event(self, cr, uid,event_id, context=None):
|
||||
gs_pool = self.pool.get('google.service')
|
||||
gs_pool = self.pool['google.service']
|
||||
|
||||
params = {
|
||||
'access_token' : self.get_token(cr,uid,context)
|
||||
|
@ -108,12 +278,14 @@ class google_calendar(osv.AbstractModel):
|
|||
if not token:
|
||||
token = self.get_token(cr,uid,context)
|
||||
|
||||
gs_pool = self.pool.get('google.service')
|
||||
gs_pool = self.pool['google.service']
|
||||
|
||||
params = {
|
||||
'fields': 'items,nextPageToken',
|
||||
'access_token' : token,
|
||||
'maxResults':1000
|
||||
'maxResults':1000,
|
||||
'timeMin': self.get_start_time_to_synchro(cr,uid,context=context).strftime("%Y-%m-%dT%H:%M:%S.%fz"),
|
||||
|
||||
}
|
||||
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
|
||||
|
||||
|
@ -134,7 +306,7 @@ class google_calendar(osv.AbstractModel):
|
|||
|
||||
def update_to_google(self, cr, uid, oe_event, google_event, context):
|
||||
calendar_event = self.pool['calendar.event']
|
||||
gs_pool = self.pool.get('google.service')
|
||||
gs_pool = self.pool['google.service']
|
||||
|
||||
url = "/calendar/v3/calendars/%s/events/%s?fields=%s&access_token=%s" % ('primary', google_event['id'],'id,updated', self.get_token(cr,uid,context))
|
||||
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
|
||||
|
@ -148,10 +320,10 @@ class google_calendar(osv.AbstractModel):
|
|||
calendar_event.write(cr, uid, [oe_event.id], {'oe_update_date':update_date})
|
||||
|
||||
if context['curr_attendee']:
|
||||
self.pool.get('calendar.attendee').write(cr,uid,[context['curr_attendee']], {'oe_synchro_date':update_date},context)
|
||||
self.pool['calendar.attendee'].write(cr,uid,[context['curr_attendee']], {'oe_synchro_date':update_date},context)
|
||||
|
||||
def update_an_event(self, cr, uid,event, context=None):
|
||||
gs_pool = self.pool.get('google.service')
|
||||
gs_pool = self.pool['google.service']
|
||||
|
||||
data = self.generate_data(cr, uid,event, context=context)
|
||||
|
||||
|
@ -164,7 +336,7 @@ class google_calendar(osv.AbstractModel):
|
|||
return response
|
||||
|
||||
def update_recurrent_event_exclu(self, cr, uid,instance_id,event_ori_google_id,event_new, context=None):
|
||||
gs_pool = self.pool.get('google.service')
|
||||
gs_pool = self.pool['google.service']
|
||||
|
||||
data = self.generate_data(cr, uid,event_new, context=context)
|
||||
|
||||
|
@ -186,7 +358,7 @@ class google_calendar(osv.AbstractModel):
|
|||
calendar_event = self.pool['calendar.event']
|
||||
res_partner_obj = self.pool['res.partner']
|
||||
calendar_attendee_obj = self.pool['calendar.attendee']
|
||||
user_obj = self.pool.get('res.users')
|
||||
user_obj = self.pool['res.users']
|
||||
myPartnerID = user_obj.browse(cr,uid,uid,context).partner_id.id
|
||||
attendee_record = []
|
||||
partner_record = [(4,myPartnerID)]
|
||||
|
@ -203,14 +375,16 @@ class google_calendar(osv.AbstractModel):
|
|||
|
||||
if google_attendee.get('found',False):
|
||||
continue
|
||||
if self.get_need_synchro_attendee(cr,uid,context=context):
|
||||
attendee_id = res_partner_obj.search(cr, uid,[('email', '=', google_attendee['email'])], context=context)
|
||||
if not attendee_id:
|
||||
attendee_id = [res_partner_obj.create(cr, uid,{'email': google_attendee['email'],'Customer': False, 'name': google_attendee.get("displayName",False) or google_attendee['email'] }, context=context)]
|
||||
attendee_id = [res_partner_obj.create(cr, uid,{'email': google_attendee['email'],'customer': False, 'name': google_attendee.get("displayName",False) or google_attendee['email'] }, context=context)]
|
||||
attendee = res_partner_obj.read(cr, uid, attendee_id[0], ['email'], context=context)
|
||||
partner_record.append((4, attendee.get('id')))
|
||||
attendee['partner_id'] = attendee.pop('id')
|
||||
attendee['state'] = google_attendee['responseStatus']
|
||||
attendee_record.append((0, 0, attendee))
|
||||
|
||||
UTC = pytz.timezone('UTC')
|
||||
if single_event_dict.get('start') and single_event_dict.get('end'): # If not cancelled
|
||||
if single_event_dict['start'].get('dateTime',False) and single_event_dict['end'].get('dateTime',False):
|
||||
|
@ -261,16 +435,17 @@ class google_calendar(osv.AbstractModel):
|
|||
res = calendar_event.create(cr, uid, result, context=context)
|
||||
|
||||
if context['curr_attendee']:
|
||||
self.pool.get('calendar.attendee').write(cr,uid,[context['curr_attendee']], {'oe_synchro_date':update_date,'google_internal_event_id': single_event_dict.get('id',False)},context)
|
||||
self.pool['calendar.attendee'].write(cr,uid,[context['curr_attendee']], {'oe_synchro_date':update_date,'google_internal_event_id': single_event_dict.get('id',False)},context)
|
||||
return res
|
||||
|
||||
def synchronize_events(self, cr, uid, ids, context=None):
|
||||
gc_obj = self.pool.get('google.calendar')
|
||||
gc_obj = self.pool['google.calendar']
|
||||
|
||||
# Create all new events from OpenERP into Gmail, if that is not recurrent event
|
||||
self.create_new_events(cr, uid, context=context)
|
||||
|
||||
self.bind_recurring_events_to_google(cr, uid, context)
|
||||
cr.commit()
|
||||
|
||||
|
||||
res = self.update_events(cr, uid, context)
|
||||
|
||||
|
@ -279,10 +454,9 @@ class google_calendar(osv.AbstractModel):
|
|||
"url" : ''
|
||||
}
|
||||
|
||||
def create_new_events(self, cr, uid, context):
|
||||
gc_pool = self.pool.get('google.calendar')
|
||||
|
||||
calendar_event = self.pool['calendar.event']
|
||||
def create_new_events(self, cr, uid, context=None):
|
||||
gc_pool = self.pool['google.calendar']
|
||||
ev_obj = self.pool['calendar.event']
|
||||
att_obj = self.pool['calendar.attendee']
|
||||
user_obj = self.pool['res.users']
|
||||
myPartnerID = user_obj.browse(cr,uid,uid,context=context).partner_id.id
|
||||
|
@ -290,58 +464,52 @@ class google_calendar(osv.AbstractModel):
|
|||
context_norecurrent = context.copy()
|
||||
context_norecurrent['virtual_id'] = False
|
||||
|
||||
my_att_ids = att_obj.search(cr, uid,[('partner_id', '=', myPartnerID),('google_internal_event_id', '=', False)], context=context_norecurrent)
|
||||
my_att_ids = att_obj.search(cr, uid,[ ('partner_id', '=', myPartnerID),
|
||||
('google_internal_event_id', '=', False),
|
||||
'|',
|
||||
('event_id.date_deadline','>',self.get_start_time_to_synchro(cr,uid,context).strftime("%Y-%m-%d %H:%M:%S")),
|
||||
('event_id.end_date','>',self.get_start_time_to_synchro(cr,uid,context).strftime("%Y-%m-%d %H:%M:%S")),
|
||||
], context=context_norecurrent)
|
||||
|
||||
for att in att_obj.browse(cr,uid,my_att_ids,context=context):
|
||||
if not att.event_id.recurrent_id or att.event_id.recurrent_id == 0:
|
||||
response = self.create_an_event(cr,uid,att.event_id,context=context)
|
||||
update_date = datetime.strptime(response['updated'],"%Y-%m-%dT%H:%M:%S.%fz")
|
||||
calendar_event.write(cr, uid, att.event_id.id, {'oe_update_date':update_date})
|
||||
ev_obj.write(cr, uid, att.event_id.id, {'oe_update_date':update_date})
|
||||
att_obj.write(cr, uid, [att.id], {'google_internal_event_id': response['id'], 'oe_synchro_date':update_date})
|
||||
cr.commit()
|
||||
return True
|
||||
|
||||
def get_empty_synchro_summarize(self) :
|
||||
return {
|
||||
#OPENERP
|
||||
'OE_event' : False,
|
||||
'OE_found' : False,
|
||||
'OE_event_id' : False,
|
||||
'OE_isRecurrence':False,
|
||||
'OE_isInstance':False,
|
||||
'OE_update':False,
|
||||
'OE_status':False,
|
||||
'OE_attendee_id': False,
|
||||
'OE_synchro':False,
|
||||
def bind_recurring_events_to_google(self, cr, uid, context):
|
||||
ev_obj = self.pool['calendar.event']
|
||||
att_obj = self.pool['calendar.attendee']
|
||||
user_obj = self.pool['res.users']
|
||||
myPartnerID = user_obj.browse(cr,uid,uid,context=context).partner_id.id
|
||||
|
||||
#GOOGLE
|
||||
'GG_event' : False,
|
||||
'GG_found' : False,
|
||||
'GG_isRecurrence':False,
|
||||
'GG_isInstance':False,
|
||||
'GG_update':False,
|
||||
'GG_status':False,
|
||||
context_norecurrent = context.copy()
|
||||
context_norecurrent['virtual_id'] = False
|
||||
context_norecurrent['active_test'] = False
|
||||
|
||||
#TO_DO_IN_GOOGLE
|
||||
'td_action':'', # create, update, delete, None
|
||||
#If 'td_action' in (create , update),
|
||||
# If td_source == OE
|
||||
# We create in google the event based on OpenERP
|
||||
# If td_source == GG
|
||||
# We create in OpenERP the event based on Gmail
|
||||
#
|
||||
#If 'td_action' in (delete),
|
||||
# If td_source == OE
|
||||
# We delete in OpenERP the event
|
||||
# If td_source == GG
|
||||
# We delete in Gmail the event
|
||||
# If td_source == ALL
|
||||
# We delete in openERP AND in Gmail the event
|
||||
'td_source': '', # OE, GG, ALL
|
||||
'td_comment':''
|
||||
my_att_ids = att_obj.search(cr, uid,[('partner_id', '=', myPartnerID),('google_internal_event_id', '=', False)], context=context_norecurrent)
|
||||
|
||||
}
|
||||
for att in att_obj.browse(cr,uid,my_att_ids,context=context):
|
||||
if att.event_id.recurrent_id and att.event_id.recurrent_id > 0:
|
||||
new_google_internal_event_id = False
|
||||
source_event_record = ev_obj.browse(cr, uid, att.event_id.recurrent_id, context)
|
||||
source_attendee_record_id = att_obj.search(cr, uid, [('partner_id','=', myPartnerID), ('event_id','=',source_event_record.id)], context=context)
|
||||
source_attendee_record = att_obj.browse(cr, uid, source_attendee_record_id, context)[0]
|
||||
|
||||
def update_events(self, cr, uid, context):
|
||||
if att.event_id.recurrent_id_date and source_event_record.allday and source_attendee_record.google_internal_event_id:
|
||||
new_google_internal_event_id = source_attendee_record.google_internal_event_id +'_'+ att.event_id.recurrent_id_date.split(' ')[0].replace('-','')
|
||||
elif att.event_id.recurrent_id_date and source_attendee_record.google_internal_event_id:
|
||||
new_google_internal_event_id = source_attendee_record.google_internal_event_id +'_'+ att.event_id.recurrent_id_date.replace('-','').replace(' ','T').replace(':','') + 'Z'
|
||||
|
||||
if new_google_internal_event_id:
|
||||
#TODO WARNING, NEED TO CHECK THAT EVENT and ALL instance NOT DELETE IN GMAIL BEFORE !
|
||||
res = self.update_recurrent_event_exclu(cr, uid,new_google_internal_event_id, source_attendee_record.google_internal_event_id,att.event_id, context=context)
|
||||
att_obj.write(cr, uid, [att.id], {'google_internal_event_id': new_google_internal_event_id}, context=context)
|
||||
cr.commit()
|
||||
|
||||
def update_events(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
|
@ -355,10 +523,14 @@ class google_calendar(osv.AbstractModel):
|
|||
context_novirtual['active_test'] = False
|
||||
|
||||
all_event_from_google = self.get_event_dict(cr, uid, context=context)
|
||||
all_new_event_from_google = all_event_from_google.copy()
|
||||
|
||||
# Select all events from OpenERP which have been already synchronized in gmail
|
||||
my_att_ids = att_obj.search(cr, uid,[('partner_id', '=', myPartnerID),('google_internal_event_id', '!=', False)], context=context_novirtual)
|
||||
my_att_ids = att_obj.search(cr, uid,[ ('partner_id', '=', myPartnerID),
|
||||
('google_internal_event_id', '!=', False),
|
||||
'|',
|
||||
('event_id.date_deadline','>',self.get_start_time_to_synchro(cr,uid,context).strftime("%Y-%m-%d %H:%M:%S")),
|
||||
('event_id.end_date','>',self.get_start_time_to_synchro(cr,uid,context).strftime("%Y-%m-%d %H:%M:%S")),
|
||||
], context=context_novirtual)
|
||||
event_to_synchronize = {}
|
||||
for att in att_obj.browse(cr,uid,my_att_ids,context=context):
|
||||
event = att.event_id
|
||||
|
@ -369,18 +541,19 @@ class google_calendar(osv.AbstractModel):
|
|||
event_to_synchronize[base_event_id] = {}
|
||||
|
||||
if att.google_internal_event_id not in event_to_synchronize[base_event_id]:
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id] = self.get_empty_synchro_summarize()
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id] = SyncEvent()
|
||||
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_attendee_id'] = att.id
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_event'] = event
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_found'] = True
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_event_id'] = event.id
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_isRecurrence'] = event.recurrency
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_isInstance'] = bool(event.recurrent_id and event.recurrent_id > 0)
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_update'] = event.oe_update_date
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_status'] = event.active
|
||||
event_to_synchronize[base_event_id][att.google_internal_event_id]['OE_synchro'] = att.oe_synchro_date
|
||||
ev_to_sync = event_to_synchronize[base_event_id][att.google_internal_event_id]
|
||||
|
||||
ev_to_sync.OE.attendee_id = att.id
|
||||
ev_to_sync.OE.event = event
|
||||
ev_to_sync.OE.found = True
|
||||
ev_to_sync.OE.event_id = event.id
|
||||
ev_to_sync.OE.isRecurrence = event.recurrency
|
||||
ev_to_sync.OE.isInstance = bool(event.recurrent_id and event.recurrent_id > 0)
|
||||
ev_to_sync.OE.update = event.oe_update_date
|
||||
ev_to_sync.OE.status = event.active
|
||||
ev_to_sync.OE.synchro = att.oe_synchro_date
|
||||
|
||||
for event in all_event_from_google.values():
|
||||
event_id = event.get('id')
|
||||
|
@ -390,97 +563,27 @@ class google_calendar(osv.AbstractModel):
|
|||
event_to_synchronize[base_event_id] = {}
|
||||
|
||||
if event_id not in event_to_synchronize[base_event_id]:
|
||||
event_to_synchronize[base_event_id][event_id] = self.get_empty_synchro_summarize()
|
||||
event_to_synchronize[base_event_id][event_id] = SyncEvent()
|
||||
|
||||
event_to_synchronize[base_event_id][event_id]['GG_event'] = event
|
||||
event_to_synchronize[base_event_id][event_id]['GG_found'] = True
|
||||
event_to_synchronize[base_event_id][event_id]['GG_isRecurrence'] = bool(event.get('recurrence',''))
|
||||
event_to_synchronize[base_event_id][event_id]['GG_isInstance'] = bool(event.get('recurringEventId',0))
|
||||
event_to_synchronize[base_event_id][event_id]['GG_update'] = event.get('updated',None) # if deleted, no date without browse event
|
||||
if event_to_synchronize[base_event_id][event_id]['GG_update']:
|
||||
event_to_synchronize[base_event_id][event_id]['GG_update'] =event_to_synchronize[base_event_id][event_id]['GG_update'].replace('T',' ').replace('Z','')
|
||||
event_to_synchronize[base_event_id][event_id]['GG_status'] = (event.get('status') != 'cancelled')
|
||||
ev_to_sync = event_to_synchronize[base_event_id][event_id]
|
||||
|
||||
ev_to_sync.GG.event = event
|
||||
ev_to_sync.GG.found = True
|
||||
ev_to_sync.GG.isRecurrence = bool(event.get('recurrence',''))
|
||||
ev_to_sync.GG.isInstance = bool(event.get('recurringEventId',0))
|
||||
ev_to_sync.GG.update = event.get('updated',None) # if deleted, no date without browse event
|
||||
if ev_to_sync.GG.update:
|
||||
ev_to_sync.GG.update = ev_to_sync.GG.update.replace('T',' ').replace('Z','')
|
||||
ev_to_sync.GG.status = (event.get('status') != 'cancelled')
|
||||
|
||||
######################
|
||||
# PRE-PROCESSING #
|
||||
######################
|
||||
|
||||
for base_event in event_to_synchronize:
|
||||
for current_event in event_to_synchronize[base_event]:
|
||||
event = event_to_synchronize[base_event][current_event]
|
||||
|
||||
#If event are already in Gmail and in OpenERP
|
||||
if event['OE_found'] and event['GG_found']:
|
||||
#If the event has been deleted from one side, we delete on other side !
|
||||
if event['OE_status'] != event['GG_status']:
|
||||
event['td_action'] = "DELETE"
|
||||
event['td_source'] = (event['OE_status'] and "OE") or (event['GG_status'] and "GG")
|
||||
#If event is not deleted !
|
||||
elif event['OE_status'] and event['GG_status']:
|
||||
if event['OE_update'].split('.')[0] != event['GG_update'].split('.')[0]:
|
||||
if event['OE_update'] < event['GG_update']:
|
||||
event['td_source'] = 'GG'
|
||||
elif event['OE_update'] > event['GG_update']:
|
||||
event['td_source'] = 'OE'
|
||||
|
||||
|
||||
if event['td_action'] != "None":
|
||||
if event['%s_isRecurrence' % event['td_source']]:
|
||||
if event['%s_status' % event['td_source']]:
|
||||
event['td_action'] = "UPDATE"
|
||||
event['td_comment'] = 'Only need to update, because i\'m active'
|
||||
else:
|
||||
event['td_action'] = "EXCLUDE"
|
||||
event['td_comment'] = 'Need to Exclude (Me = First event from recurrence) from recurrence'
|
||||
|
||||
elif event['%s_isInstance' % event['td_source']]:
|
||||
event['td_action'] = "UPDATE"
|
||||
event['td_comment'] = 'Only need to update, because already an exclu'
|
||||
else:
|
||||
event['td_action'] = "UPDATE"
|
||||
event['td_comment'] = 'Simply Update... I\'m a single event'
|
||||
|
||||
else:
|
||||
if not event['OE_synchro'] or event['OE_synchro'].split('.')[0] < event['OE_update'].split('.')[0]:
|
||||
event['td_source'] = 'OE'
|
||||
event['td_action'] = "UPDATE"
|
||||
event['td_comment'] = 'Event already updated by another user, but not synchro with my google calendar'
|
||||
|
||||
else:
|
||||
event['td_action'] = "None"
|
||||
event['td_comment'] = 'Not update needed'
|
||||
else:
|
||||
event['td_action'] = "None"
|
||||
event['td_comment'] = "Both are already deleted"
|
||||
# New in openERP... Create on create_events of synchronize function
|
||||
elif event['OE_found'] and not event['GG_found']:
|
||||
#Has been deleted from gmail
|
||||
if event['OE_status']:
|
||||
event['td_source'] = 'OE'
|
||||
event['td_action'] = 'DELETE'
|
||||
event['td_comment'] = 'Removed from GOOGLE ?'
|
||||
else:
|
||||
event['td_action'] = "None"
|
||||
event['td_comment'] = "Already Deleted in gmail and unlinked in OpenERP"
|
||||
elif event['GG_found'] and not event['OE_found']:
|
||||
event['td_source'] = 'GG'
|
||||
if not event['GG_status'] and not event['GG_isInstance']:
|
||||
# don't need to make something... because event has been created and deleted before the synchronization
|
||||
event['td_action'] = 'None'
|
||||
event['td_comment'] = 'Nothing to do... Create and Delete directly'
|
||||
|
||||
else:
|
||||
if event['GG_isInstance']:
|
||||
if event['%s_status' % event['td_source']]:
|
||||
event['td_action'] = "EXCLUDE"
|
||||
event['td_comment'] = 'Need to create the new exclu'
|
||||
else:
|
||||
event['td_action'] = "EXCLUDE"
|
||||
event['td_comment'] = 'Need to copy and Exclude'
|
||||
else:
|
||||
event['td_action'] = "CREATE"
|
||||
event['td_comment'] = 'New EVENT CREATE from GMAIL'
|
||||
event_to_synchronize[base_event][current_event].compute_OP()
|
||||
#print event_to_synchronize[base_event]
|
||||
#print "========================================================"
|
||||
|
||||
######################
|
||||
# DO ACTION #
|
||||
|
@ -489,104 +592,61 @@ class google_calendar(osv.AbstractModel):
|
|||
event_to_synchronize[base_event] = sorted(event_to_synchronize[base_event].iteritems(),key=operator.itemgetter(0))
|
||||
for current_event in event_to_synchronize[base_event]:
|
||||
cr.commit()
|
||||
event = current_event[1]
|
||||
#############
|
||||
### DEBUG ###
|
||||
#############
|
||||
# if event['td_action'] and event['td_action'] != 'None':
|
||||
# print " Real Event %s (%s)" % (current_event[0],event['OE_event_id'])
|
||||
# print " Found OE:%5s vs GG: %5s" % (event['OE_found'],event['GG_found'])
|
||||
# print " Recurrence OE:%5s vs GG: %5s" % (event['OE_isRecurrence'],event['GG_isRecurrence'])
|
||||
# print " Instance OE:%5s vs GG: %5s" % (event['OE_isInstance'],event['GG_isInstance'])
|
||||
# print " Synchro OE: %10s " % (event['OE_synchro'])
|
||||
# print " Update OE: %10s " % (event['OE_update'])
|
||||
# print " Update GG: %10s " % (event['GG_update'])
|
||||
# print " Status OE:%5s vs GG: %5s" % (event['OE_status'],event['GG_status'])
|
||||
# print " Action %s" % (event['td_action'])
|
||||
# print " Source %s" % (event['td_source'])
|
||||
# print " comment %s" % (event['td_comment'])
|
||||
event = current_event[1] # event is an Sync Event !
|
||||
|
||||
context['curr_attendee'] = event.get('OE_attendee_id',False)
|
||||
actToDo = event.OP
|
||||
actSrc = event.OP.src
|
||||
|
||||
actToDo = event['td_action']
|
||||
actSrc = event['td_source']
|
||||
if not actToDo:
|
||||
raise ("#!? WHAT I NEED TO DO ????")
|
||||
else:
|
||||
if actToDo == 'None':
|
||||
# if not isinstance(actToDo, NothingToDo):
|
||||
# print event
|
||||
|
||||
context['curr_attendee'] = event.OE.attendee_id
|
||||
|
||||
if isinstance(actToDo, NothingToDo):
|
||||
continue
|
||||
elif actToDo == 'CREATE':
|
||||
elif isinstance(actToDo, Create):
|
||||
context_tmp = context.copy()
|
||||
context_tmp['NewMeeting'] = True
|
||||
if actSrc == 'GG':
|
||||
res = self.update_from_google(cr, uid, False, event['GG_event'], "create", context=context_tmp)
|
||||
event['OE_event_id'] = res
|
||||
res = self.update_from_google(cr, uid, False, event.GG.event, "create", context=context_tmp)
|
||||
event.OE.event_id = res
|
||||
meeting = calendar_event.browse(cr,uid,res,context=context)
|
||||
attendee_record_id = att_obj.search(cr, uid, [('partner_id','=', myPartnerID), ('event_id','=',res)], context=context)
|
||||
self.pool.get('calendar.attendee').write(cr,uid,attendee_record_id, {'oe_synchro_date':meeting.oe_update_date,'google_internal_event_id': event['GG_event']['id']},context=context_tmp)
|
||||
self.pool['calendar.attendee'].write(cr, uid, attendee_record_id, {'oe_synchro_date':meeting.oe_update_date, 'google_internal_event_id':event.GG.event['id']}, context=context_tmp)
|
||||
elif actSrc == 'OE':
|
||||
raise "Should be never here, creation for OE is done before update !"
|
||||
#TODO Add to batch
|
||||
elif actToDo == 'UPDATE':
|
||||
elif isinstance(actToDo, Update):
|
||||
if actSrc == 'GG':
|
||||
self.update_from_google(cr, uid, event['OE_event'], event['GG_event'], 'write', context)
|
||||
self.update_from_google(cr, uid, event.OE.event, event.GG.event, 'write', context)
|
||||
elif actSrc == 'OE':
|
||||
self.update_to_google(cr, uid, event['OE_event'], event['GG_event'], context)
|
||||
elif actToDo == 'EXCLUDE' :
|
||||
self.update_to_google(cr, uid, event.OE.event, event.GG.event, context)
|
||||
elif isinstance(actToDo, Exclude):
|
||||
if actSrc == 'OE':
|
||||
self.delete_an_event(cr,uid,current_event[0],context=context)
|
||||
elif actSrc == 'GG':
|
||||
new_google_event_id = event['GG_event']['id'].split('_')[1]
|
||||
new_google_event_id = event.GG.event['id'].split('_')[1]
|
||||
if 'T' in new_google_event_id:
|
||||
new_google_event_id = new_google_event_id.replace('T','')[:-1]
|
||||
else:
|
||||
new_google_event_id = new_google_event_id + "000000"
|
||||
|
||||
if event['GG_status']:
|
||||
if event.GG.status:
|
||||
parent_event = {}
|
||||
parent_event['id'] = "%s-%s" % (event_to_synchronize[base_event][0][1].get('OE_event_id') , new_google_event_id)
|
||||
res = self.update_from_google(cr, uid, parent_event, event['GG_event'], "copy", context)
|
||||
parent_event['id'] = "%s-%s" % (event_to_synchronize[base_event][0][1].OE.event_id , new_google_event_id)
|
||||
res = self.update_from_google(cr, uid, parent_event, event.GG.event, "copy", context)
|
||||
else:
|
||||
if event_to_synchronize[base_event][0][1].get('OE_event_id'):
|
||||
parent_oe_id = event_to_synchronize[base_event][0][1].get('OE_event_id')
|
||||
if event_to_synchronize[base_event][0][1].OE.event_id:
|
||||
parent_oe_id = event_to_synchronize[base_event][0][1].OE.event_id
|
||||
calendar_event.unlink(cr,uid,"%s-%s" % (parent_oe_id,new_google_event_id),unlink_level=1,context=context)
|
||||
|
||||
elif actToDo == 'DELETE':
|
||||
elif isinstance(actToDo, Delete):
|
||||
if actSrc == 'GG':
|
||||
self.delete_an_event(cr,uid,current_event[0],context=context)
|
||||
elif actSrc == 'OE':
|
||||
calendar_event.unlink(cr,uid,event['OE_event_id'],unlink_level=0,context=context)
|
||||
calendar_event.unlink(cr,uid,event.OE.event_id,unlink_level=0,context=context)
|
||||
return True
|
||||
|
||||
def bind_recurring_events_to_google(self, cr, uid, context):
|
||||
calendar_event = self.pool['calendar.event']
|
||||
att_obj = self.pool.get('calendar.attendee')
|
||||
user_obj = self.pool['res.users']
|
||||
myPartnerID = user_obj.browse(cr,uid,uid,context=context).partner_id.id
|
||||
|
||||
context_norecurrent = context.copy()
|
||||
context_norecurrent['virtual_id'] = False
|
||||
context_norecurrent['active_test'] = False
|
||||
|
||||
my_att_ids = att_obj.search(cr, uid,[('partner_id', '=', myPartnerID),('google_internal_event_id', '=', False)], context=context_norecurrent)
|
||||
for att in att_obj.browse(cr,uid,my_att_ids,context=context):
|
||||
if att.event_id.recurrent_id and att.event_id.recurrent_id > 0:
|
||||
new_google_internal_event_id = False
|
||||
source_event_record = calendar_event.browse(cr, uid, att.event_id.recurrent_id, context)
|
||||
source_attendee_record_id = att_obj.search(cr, uid, [('partner_id','=', myPartnerID), ('event_id','=',source_event_record.id)], context=context)
|
||||
source_attendee_record = att_obj.browse(cr, uid, source_attendee_record_id, context)
|
||||
if source_attendee_record:
|
||||
source_attendee_record = source_attendee_record[0]
|
||||
|
||||
if att.event_id.recurrent_id_date and source_event_record.allday and source_attendee_record.google_internal_event_id:
|
||||
new_google_internal_event_id = source_attendee_record.google_internal_event_id +'_'+ att.event_id.recurrent_id_date.split(' ')[0].replace('-','')
|
||||
elif event.recurrent_id_date and source_attendee_record.google_internal_event_id:
|
||||
new_google_internal_event_id = source_attendee_record.google_internal_event_id +'_'+ att.event_id.recurrent_id_date.replace('-','').replace(' ','T').replace(':','') + 'Z'
|
||||
|
||||
if new_google_internal_event_id:
|
||||
#TODO WARNING, NEED TO CHECK THAT EVENT and ALL instance NOT DELETE IN GMAIL BEFORE !
|
||||
res = self.update_recurrent_event_exclu(cr,uid,new_google_internal_event_id,source_attendee_record.google_internal_event_id,att.event_id,context=context)
|
||||
att_obj.write(cr, uid, [att.event_id.id], {'google_internal_event_id': new_google_internal_event_id})
|
||||
|
||||
def check_and_sync(self, cr, uid, oe_event, google_event, context):
|
||||
if datetime.strptime(oe_event.oe_update_date,"%Y-%m-%d %H:%M:%S.%f") > datetime.strptime(google_event['updated'],"%Y-%m-%dT%H:%M:%S.%fz"):
|
||||
|
@ -595,7 +655,7 @@ class google_calendar(osv.AbstractModel):
|
|||
self.update_from_google(cr, uid, oe_event, google_event, 'write', context)
|
||||
|
||||
def get_sequence(self,cr,uid,instance_id,context=None):
|
||||
gs_pool = self.pool.get('google.service')
|
||||
gs_pool = self.pool['google.service']
|
||||
|
||||
params = {
|
||||
'fields': 'sequence',
|
||||
|
@ -613,7 +673,7 @@ class google_calendar(osv.AbstractModel):
|
|||
#################################
|
||||
|
||||
def get_token(self,cr,uid,context=None):
|
||||
current_user = self.pool.get('res.users').browse(cr,uid,uid,context=context)
|
||||
current_user = self.pool['res.users'].browse(cr,uid,uid,context=context)
|
||||
|
||||
if datetime.strptime(current_user.google_calendar_token_validity.split('.')[0], "%Y-%m-%d %H:%M:%S") < (datetime.now() + timedelta(minutes=1)):
|
||||
self.do_refresh_token(cr,uid,context=context)
|
||||
|
@ -622,8 +682,8 @@ class google_calendar(osv.AbstractModel):
|
|||
return current_user.google_calendar_token
|
||||
|
||||
def do_refresh_token(self,cr,uid,context=None):
|
||||
current_user = self.pool.get('res.users').browse(cr,uid,uid,context=context)
|
||||
gs_pool = self.pool.get('google.service')
|
||||
current_user = self.pool['res.users'].browse(cr,uid,uid,context=context)
|
||||
gs_pool = self.pool['google.service']
|
||||
|
||||
refresh = current_user.google_calendar_rtoken
|
||||
all_token = gs_pool._refresh_google_token_json(cr, uid, current_user.google_calendar_rtoken, self.STR_SERVICE, context=context)
|
||||
|
@ -632,10 +692,10 @@ class google_calendar(osv.AbstractModel):
|
|||
vals['google_%s_token_validity' % self.STR_SERVICE] = datetime.now() + timedelta(seconds=all_token.get('expires_in'))
|
||||
vals['google_%s_token' % self.STR_SERVICE] = all_token.get('access_token')
|
||||
|
||||
self.pool.get('res.users').write(cr,SUPERUSER_ID,uid,vals,context=context)
|
||||
self.pool['res.users'].write(cr,SUPERUSER_ID,uid,vals,context=context)
|
||||
|
||||
def need_authorize(self,cr,uid,context=None):
|
||||
current_user = self.pool.get('res.users').browse(cr,uid,uid,context=context)
|
||||
current_user = self.pool['res.users'].browse(cr,uid,uid,context=context)
|
||||
return current_user.google_calendar_rtoken == False
|
||||
|
||||
def get_calendar_scope(self,RO=False):
|
||||
|
@ -643,22 +703,30 @@ class google_calendar(osv.AbstractModel):
|
|||
return 'https://www.googleapis.com/auth/calendar%s' % (readonly)
|
||||
|
||||
def authorize_google_uri(self,cr,uid,from_url='http://www.openerp.com',context=None):
|
||||
url = self.pool.get('google.service')._get_authorize_uri(cr,uid,from_url,self.STR_SERVICE,scope=self.get_calendar_scope(),context=context)
|
||||
url = self.pool['google.service']._get_authorize_uri(cr,uid,from_url,self.STR_SERVICE,scope=self.get_calendar_scope(),context=context)
|
||||
return url
|
||||
|
||||
def can_authorize_google(self,cr,uid,context=None):
|
||||
return self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager')
|
||||
|
||||
def set_all_tokens(self,cr,uid,authorization_code,context=None):
|
||||
gs_pool = self.pool.get('google.service')
|
||||
gs_pool = self.pool['google.service']
|
||||
all_token = gs_pool._get_google_token_json(cr, uid, authorization_code,self.STR_SERVICE,context=context)
|
||||
|
||||
vals = {}
|
||||
vals['google_%s_rtoken' % self.STR_SERVICE] = all_token.get('refresh_token')
|
||||
vals['google_%s_token_validity' % self.STR_SERVICE] = datetime.now() + timedelta(seconds=all_token.get('expires_in'))
|
||||
vals['google_%s_token' % self.STR_SERVICE] = all_token.get('access_token')
|
||||
self.pool.get('res.users').write(cr,SUPERUSER_ID,uid,vals,context=context)
|
||||
self.pool['res.users'].write(cr,SUPERUSER_ID,uid,vals,context=context)
|
||||
|
||||
def get_start_time_to_synchro(self, cr, uid, context=None) :
|
||||
# WILL BE AN IR CONFIG PARAMETER - beginning from SAAS4
|
||||
number_of_week = 13
|
||||
return datetime.now()-timedelta(weeks=number_of_week)
|
||||
|
||||
def get_need_synchro_attendee(self, cr, uid, context=None):
|
||||
# WILL BE AN IR CONFIG PARAMETER - beginning from SAAS4
|
||||
return True
|
||||
|
||||
class res_users(osv.Model):
|
||||
_inherit = 'res.users'
|
||||
|
@ -718,7 +786,6 @@ class calendar_attendee(osv.Model):
|
|||
# If attendees are updated, we need to specify that next synchro need an action
|
||||
# Except if it come from an update_from_google
|
||||
if not context.get('curr_attendee', False) and not context.get('NewMeeting', False):
|
||||
self.pool.get('calendar.event').write(cr, uid, ref, {'oe_update_date':datetime.now()},context)
|
||||
self.pool['calendar.event'].write(cr, uid, ref, {'oe_update_date':datetime.now()},context)
|
||||
|
||||
return super(calendar_attendee, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
import logging
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp import tools
|
||||
from openerp.modules.module import get_module_resource
|
||||
from openerp.osv import fields, osv
|
||||
|
@ -248,27 +249,46 @@ class hr_employee(osv.osv):
|
|||
'color': 0,
|
||||
}
|
||||
|
||||
def create(self, cr, uid, data, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
create_ctx = dict(context, mail_create_nolog=True)
|
||||
employee_id = super(hr_employee, self).create(cr, uid, data, context=create_ctx)
|
||||
def _broadcast_welcome(self, cr, uid, employee_id, context=None):
|
||||
""" Broadcast the welcome message to all users in the employee company. """
|
||||
employee = self.browse(cr, uid, employee_id, context=context)
|
||||
if employee.user_id:
|
||||
res_users = self.pool['res.users']
|
||||
# send a copy to every user of the company
|
||||
# TODO: post to the `Whole Company` mail.group when we'll be able to link to the employee record
|
||||
_model, group_id = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base', 'group_user')
|
||||
user_ids = res_users.search(cr, uid, [('company_id', '=', employee.user_id.company_id.id),
|
||||
('groups_id', 'in', group_id)])
|
||||
partner_ids = list(set(u.partner_id.id for u in res_users.browse(cr, uid, user_ids, context=context)))
|
||||
else:
|
||||
partner_ids = []
|
||||
self.message_post(cr, uid, [employee_id],
|
||||
_model, group_id = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base', 'group_user')
|
||||
if employee.user_id:
|
||||
company_id = employee.user_id.company_id.id
|
||||
elif employee.company_id:
|
||||
company_id = employee.company_id.id
|
||||
elif employee.job_id:
|
||||
company_id = employee.job_id.company_id.id
|
||||
elif employee.department_id:
|
||||
company_id = employee.department_id.company_id.id
|
||||
else:
|
||||
company_id = self.pool['res.company']._company_default_get(cr, uid, 'hr.employee', context=context)
|
||||
res_users = self.pool['res.users']
|
||||
user_ids = res_users.search(
|
||||
cr, SUPERUSER_ID, [
|
||||
('company_id', '=', company_id),
|
||||
('groups_id', 'in', group_id)
|
||||
], context=context)
|
||||
partner_ids = list(set(u.partner_id.id for u in res_users.browse(cr, SUPERUSER_ID, user_ids, context=context)))
|
||||
self.message_post(
|
||||
cr, uid, [employee_id],
|
||||
body=_('Welcome to %s! Please help him/her take the first steps with OpenERP!') % (employee.name),
|
||||
partner_ids=partner_ids,
|
||||
subtype='mail.mt_comment', context=context
|
||||
)
|
||||
return True
|
||||
|
||||
def create(self, cr, uid, data, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if context.get("mail_broadcast"):
|
||||
context['mail_create_nolog'] = True
|
||||
|
||||
employee_id = super(hr_employee, self).create(cr, uid, data, context=context)
|
||||
|
||||
if context.get("mail_broadcast"):
|
||||
self._broadcast_welcome(cr, uid, employee_id, context=context)
|
||||
return employee_id
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
|
|
|
@ -74,8 +74,8 @@
|
|||
<label for="number_of_days_temp" string="Duration"/>
|
||||
<div>
|
||||
<group col="3" attrs="{'invisible': [('type', '=', 'add')]}">
|
||||
<field name="date_from" nolabel="1" on_change="onchange_date_from(date_to, date_from)" required="1" class="oe_inline"/><label string="-" class="oe_inline"/>
|
||||
<field name="date_to" nolabel="1" on_change="onchange_date_to(date_to, date_from)" required="1" class="oe_inline"/>
|
||||
<field name="date_from" nolabel="1" on_change="onchange_date_from(date_to, date_from)" attrs="{'required':[('type', '=', 'remove')]}" class="oe_inline"/><label string="-" class="oe_inline"/>
|
||||
<field name="date_to" nolabel="1" on_change="onchange_date_to(date_to, date_from)" attrs="{'required':[('type', '=', 'remove')]}" class="oe_inline"/>
|
||||
</group>
|
||||
<div>
|
||||
<field name="number_of_days_temp" class="oe_inline"/> days
|
||||
|
|
|
@ -453,6 +453,7 @@ class hr_applicant(osv.Model):
|
|||
contact_name = self.pool.get('res.partner').name_get(cr, uid, [applicant.partner_id.id])[0][1]
|
||||
if applicant.job_id and (applicant.partner_name or contact_name):
|
||||
applicant.job_id.write({'no_of_hired_employee': applicant.job_id.no_of_hired_employee + 1}, context=context)
|
||||
create_ctx = dict(context, mail_broadcast=True)
|
||||
emp_id = hr_employee.create(cr, uid, {'name': applicant.partner_name or contact_name,
|
||||
'job_id': applicant.job_id.id,
|
||||
'address_home_id': address_id,
|
||||
|
@ -460,7 +461,7 @@ class hr_applicant(osv.Model):
|
|||
'address_id': applicant.company_id and applicant.company_id.partner_id and applicant.company_id.partner_id.id or False,
|
||||
'work_email': applicant.department_id and applicant.department_id.company_id and applicant.department_id.company_id.email or False,
|
||||
'work_phone': applicant.department_id and applicant.department_id.company_id and applicant.department_id.company_id.phone or False,
|
||||
})
|
||||
}, context=create_ctx)
|
||||
self.write(cr, uid, [applicant.id], {'emp_id': emp_id}, context=context)
|
||||
self.pool['hr.job'].message_post(
|
||||
cr, uid, [applicant.job_id.id],
|
||||
|
|
|
@ -8,14 +8,14 @@ msgstr ""
|
|||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
|
||||
"PO-Revision-Date: 2012-02-11 15:26+0000\n"
|
||||
"Last-Translator: 开阖软件 Jeff Wang <jeff@osbzr.com>\n"
|
||||
"PO-Revision-Date: 2014-02-20 15:53+0000\n"
|
||||
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\n"
|
||||
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2014-01-28 06:29+0000\n"
|
||||
"X-Generator: Launchpad (build 16914)\n"
|
||||
"X-Launchpad-Export-Date: 2014-02-21 05:48+0000\n"
|
||||
"X-Generator: Launchpad (build 16916)\n"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: help:hr.applicant,active:0
|
||||
|
@ -33,24 +33,24 @@ msgstr "必备条件"
|
|||
#. module: hr_recruitment
|
||||
#: view:hr.applicant:0
|
||||
msgid "Application Summary"
|
||||
msgstr ""
|
||||
msgstr "申请摘要"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: view:hr.applicant:0
|
||||
msgid "Start Interview"
|
||||
msgstr ""
|
||||
msgstr "开始面试"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: view:hr.applicant:0
|
||||
msgid "Mobile:"
|
||||
msgstr ""
|
||||
msgstr "手机:"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: help:hr.recruitment.stage,fold:0
|
||||
msgid ""
|
||||
"This stage is not visible, for example in status bar or kanban view, when "
|
||||
"there are no records in that stage to display."
|
||||
msgstr ""
|
||||
msgstr "此阶段是不可见的。例如:状态栏或看板视图中,在该阶段中 不存在可显示的记录。"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: model:hr.recruitment.degree,name:hr_recruitment.degree_graduate
|
||||
|
@ -99,7 +99,7 @@ msgstr "暂停的职位"
|
|||
#: view:hr.applicant:0
|
||||
#: field:hr.applicant,message_unread:0
|
||||
msgid "Unread Messages"
|
||||
msgstr ""
|
||||
msgstr "未读消息"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: field:hr.applicant,company_id:0
|
||||
|
@ -157,7 +157,7 @@ msgstr ""
|
|||
#: model:ir.actions.act_window,name:hr_recruitment.crm_case_categ0_act_job
|
||||
#: model:ir.ui.menu,name:hr_recruitment.menu_crm_case_categ0_act_job
|
||||
msgid "Applications"
|
||||
msgstr ""
|
||||
msgstr "求职申请"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: field:hr.applicant,day_open:0
|
||||
|
@ -167,12 +167,12 @@ msgstr "开启天数"
|
|||
#. module: hr_recruitment
|
||||
#: field:hr.applicant,emp_id:0
|
||||
msgid "employee"
|
||||
msgstr ""
|
||||
msgstr "雇员"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: field:hr.config.settings,fetchmail_applicants:0
|
||||
msgid "Create applicants from an incoming email account"
|
||||
msgstr ""
|
||||
msgstr "从电子邮件帐号接收的邮件创建求职申请"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: view:hr.recruitment.report:0
|
||||
|
@ -184,7 +184,7 @@ msgstr "天数"
|
|||
#: view:hr.recruitment.partner.create:0
|
||||
#: model:ir.actions.act_window,name:hr_recruitment.action_hr_recruitment_partner_create
|
||||
msgid "Create Contact"
|
||||
msgstr ""
|
||||
msgstr "新建联系人"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: view:hr.applicant:0
|
||||
|
@ -808,7 +808,7 @@ msgstr "生效"
|
|||
#: view:hr.recruitment.report:0
|
||||
#: field:hr.recruitment.report,nbr:0
|
||||
msgid "# of Applications"
|
||||
msgstr ""
|
||||
msgstr "个申请"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: model:ir.actions.act_window,help:hr_recruitment.hr_recruitment_stage_act
|
||||
|
@ -1251,7 +1251,7 @@ msgstr "开始"
|
|||
#. module: hr_recruitment
|
||||
#: view:board.board:0
|
||||
msgid "Applications to be Processed"
|
||||
msgstr ""
|
||||
msgstr "待处理的申请"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: view:hr.applicant:0
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue