[MERGE]merge with latest trunk

bzr revid: csn@openerp.com-20121108153355-6t80srntxmce4qyt
This commit is contained in:
Cedric Snauwaert 2012-11-08 16:33:55 +01:00
commit 3b4b0c0f9f
364 changed files with 23806 additions and 61940 deletions

View File

@ -541,10 +541,18 @@ class account_account(osv.osv):
return False
return True
def _check_company_account(self, cr, uid, ids, context=None):
for account in self.browse(cr, uid, ids, context=context):
if account.parent_id:
if account.company_id != account.parent_id.company_id:
return False
return True
_constraints = [
(_check_recursion, 'Error!\nYou cannot create recursive accounts.', ['parent_id']),
(_check_type, 'Configuration Error!\nYou cannot define children to an account with internal type different of "View".', ['type']),
(_check_account_type, 'Configuration Error!\nYou cannot select an account type with a deferral method different of "Unreconciled" for accounts with internal type "Payable/Receivable".', ['user_type','type']),
(_check_company_account, 'Error!\nYou cannot create an account which has parent account of different company.', ['parent_id']),
]
_sql_constraints = [
('code_company_uniq', 'unique (code,company_id)', 'The code of the account must be unique per company !')

View File

@ -61,7 +61,7 @@ class account_bank_statement(osv.osv):
return res
def _get_period(self, cr, uid, context=None):
periods = self.pool.get('account.period').find(cr, uid)
periods = self.pool.get('account.period').find(cr, uid,context=context)
if periods:
return periods[0]
return False

View File

@ -78,7 +78,7 @@ class account_cash_statement(osv.osv):
"""
res = {}
for statement in self.browse(cr, uid, ids, context=context):
if statement.journal_id.type not in ('cash',):
if (statement.journal_id.type not in ('cash',)) or (not statement.journal_id.cash_control):
continue
start = end = 0
for line in statement.details_ids:
@ -289,13 +289,13 @@ class account_cash_statement(osv.osv):
super(account_cash_statement, self).button_confirm_bank(cr, uid, ids, context=context)
absl_proxy = self.pool.get('account.bank.statement.line')
TABLES = (('Profit', 'profit_account_id'), ('Loss', 'loss_account_id'),)
TABLES = ((_('Profit'), 'profit_account_id'), (_('Loss'), 'loss_account_id'),)
for obj in self.browse(cr, uid, ids, context=context):
if obj.difference == 0.0:
continue
for item_label, item_account in TALBES:
for item_label, item_account in TABLES:
if getattr(obj.journal_id, item_account):
raise osv.except_osv(_('Error!'),
_('There is no %s Account on the journal %s.') % (item_label, obj.journal_id.name,))

View File

@ -168,10 +168,8 @@
context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}"
domain="[('supplier', '=', True)]"/>
<field name="fiscal_position" widget="selection"/>
<group>
<field name="origin"/>
<field name="supplier_invoice_number"/>
</group>
<field name="origin"/>
<field name="supplier_invoice_number"/>
<label for="reference_type"/>
<div>
<field name="reference_type" class="oe_inline oe_edit_only"/>

View File

@ -975,7 +975,7 @@ class account_move_line(osv.osv):
if context is None:
context = {}
result = super(account_move_line, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu)
if view_type != 'tree':
if (view_type != 'tree') or view_id:
#Remove the toolbar from the form view
if view_type == 'form':
if result.get('toolbar', False):

View File

@ -1791,7 +1791,7 @@
<field name="name"/>
<field name="active"/>
</group>
<field name="note" placeholder="Note fo the invoice..."/>
<field name="note" placeholder="Note for the invoice..."/>
<separator string="Computation"/>
<field name="line_ids"/>
</form>

View File

@ -127,7 +127,6 @@
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Status</field>
<field name="field">state</field>
<field eval="True" name="invisible"/>
<field eval="19" name="sequence"/>
</record>
<record id="bank_col20" model="account.journal.column">
@ -215,7 +214,6 @@
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Status</field>
<field name="field">state</field>
<field eval="True" name="invisible"/>
<field eval="19" name="sequence"/>
</record>
<record id="bank_col20_multi" model="account.journal.column">
@ -291,7 +289,6 @@
<field name="view_id" ref="account_journal_view"/>
<field name="name">Status</field>
<field name="field">state</field>
<field eval="True" name="invisible"/>
<field eval="19" name="sequence"/>
</record>
@ -373,7 +370,6 @@
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Status</field>
<field name="field">state</field>
<field eval="True" name="invisible"/>
<field eval="19" name="sequence"/>
</record>
<record id="sp_journal_col20" model="account.journal.column">
@ -460,7 +456,6 @@
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Status</field>
<field name="field">state</field>
<field eval="True" name="invisible"/>
<field eval="19" name="sequence"/>
</record>
<record id="sp_refund_journal_col20" model="account.journal.column">

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-31 04:40+0000\n"
"X-Launchpad-Export-Date: 2012-11-03 05:03+0000\n"
"X-Generator: Launchpad (build 16218)\n"
#. module: account

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-11-01 04:36+0000\n"
"X-Launchpad-Export-Date: 2012-11-03 05:03+0000\n"
"X-Generator: Launchpad (build 16218)\n"
#. module: account

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:35+0000\n"
"PO-Revision-Date: 2012-06-20 16:03+0000\n"
"Last-Translator: Raphael Collet (OpenERP) <Unknown>\n"
"PO-Revision-Date: 2012-11-01 18:30+0000\n"
"Last-Translator: Dusan Laznik <laznik@mentis.si>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-30 05:04+0000\n"
"X-Generator: Launchpad (build 16206)\n"
"X-Launchpad-Export-Date: 2012-11-03 05:04+0000\n"
"X-Generator: Launchpad (build 16218)\n"
#. module: account
#: view:account.invoice.report:0
@ -1587,7 +1587,7 @@ msgstr "Neobdavčeno"
#. module: account
#: view:account.partner.reconcile.process:0
msgid "Go to Next Partner"
msgstr ""
msgstr "Naslednji parner"
#. module: account
#: view:account.bank.statement:0
@ -3150,7 +3150,7 @@ msgstr "Predloge kontnih načrtov"
#. module: account
#: model:ir.actions.act_window,name:account.action_wizard_multi_chart
msgid "Set Your Accounting Options"
msgstr ""
msgstr "Nastavitve"
#. module: account
#: view:report.account.sales:0
@ -4358,7 +4358,7 @@ msgstr "res_config_contents"
#. module: account
#: view:account.unreconcile:0
msgid "Unreconciliate Transactions"
msgstr ""
msgstr "Neusklajene postavke"
#. module: account
#: help:account.chart.template,visible:0
@ -4558,7 +4558,7 @@ msgstr "Datum dogodka"
#. module: account
#: view:account.unreconcile.reconcile:0
msgid "Unreconciliation Transactions"
msgstr ""
msgstr "Naknadno odprte postavke"
#. module: account
#: field:account.tax,ref_tax_code_id:0
@ -6046,7 +6046,7 @@ msgstr "Davek(%)"
#. module: account
#: view:account.addtmpl.wizard:0
msgid "Create an Account Based on this Template"
msgstr ""
msgstr "Ustvarite konto na osnovi te predloge"
#. module: account
#: view:account.account.type:0
@ -8827,7 +8827,7 @@ msgstr "Prodaja po vrstah"
#. module: account
#: view:account.analytic.cost.ledger.journal.report:0
msgid "Cost Ledger for Period"
msgstr ""
msgstr "Stroški za obdobje"
#. module: account
#: help:account.tax,child_depend:0
@ -10307,7 +10307,7 @@ msgstr "Urejanje vrst dnevnikov."
#. module: account
#: view:account.payment.term:0
msgid "Description on Invoices"
msgstr ""
msgstr "Opis na računih"
#. module: account
#: model:ir.model,name:account.model_account_analytic_chart

View File

@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:35+0000\n"
"PO-Revision-Date: 2012-10-30 16:03+0000\n"
"PO-Revision-Date: 2012-11-01 08:44+0000\n"
"Last-Translator: ccdos <ccdos@163.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-31 04:40+0000\n"
"X-Launchpad-Export-Date: 2012-11-03 05:04+0000\n"
"X-Generator: Launchpad (build 16218)\n"
#. module: account
@ -9642,7 +9642,7 @@ msgstr "本报表让您打印或产生一个由所有账簿生成的总账"
#: selection:account.account.template,type:0
#: selection:account.entries.report,type:0
msgid "Regular"
msgstr "定期"
msgstr "常规科目"
#. module: account
#: view:account.account:0

View File

@ -209,7 +209,7 @@ class res_partner(osv.osv):
relation='account.fiscal.position',
string="Fiscal Position",
view_load=True,
help="The fiscal position will determine taxes and the accounts used for the partner.",
help="The fiscal position will determine taxes and accounts used for the partner.",
),
'property_payment_term': fields.property(
'account.payment.term',

View File

@ -30,14 +30,14 @@ class product_category(osv.osv):
relation='account.account',
string="Income Account",
view_load=True,
help="This account will be used for invoices to value sales for the current product category"),
help="This account will be used for invoices to value sales."),
'property_account_expense_categ': fields.property(
'account.account',
'account.account',
type='many2one',
relation='account.account',
string="Expense Account",
view_load=True,
help="This account will be used for invoices to value expenses for the current product category"),
help="This account will be used for invoices to value expenses."),
}
product_category()
@ -60,14 +60,14 @@ class product_template(osv.osv):
relation='account.account',
string="Income Account",
view_load=True,
help="This account will be used for invoices instead of the default one to value sales for the current product"),
help="This account will be used for invoices instead of the default one to value sales for the current product."),
'property_account_expense': fields.property(
'account.account',
type='many2one',
relation='account.account',
string="Expense Account",
view_load=True,
help="This account will be used for invoices instead of the default one to value expenses for the current product"),
help="This account will be used for invoices instead of the default one to value expenses for the current product."),
}
product_template()

View File

@ -49,9 +49,11 @@
<field name="inherit_id" ref="product.product_category_form_view"/>
<field name="arch" type="xml">
<data>
<xpath expr="/form/sheet//group[@name='account_property']" position="inside">
<field name="property_account_income_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_account_expense_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<xpath expr="//group[@name='parent']" position="inside">
<group name="account_property" string="Account Properties" colspan="2">
<field name="property_account_income_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
<field name="property_account_expense_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
</group>
</xpath>
</data>
</field>

View File

@ -94,8 +94,8 @@
<field name="state">open</field>
<field name="partner_id" ref="base.res_partner_19"/>
</record>
<record id="analytic_magasin_bml_1" model="account.analytic.account">
<field name="name">Magasin BML 1</field>
<record id="analytic_millennium_industries" model="account.analytic.account">
<field name="name">Millennium Industries</field>
<field name="parent_id" ref="analytic_integration"/>
<field name="type">normal</field>
<field name="partner_id" ref="base.res_partner_15"/>
@ -121,8 +121,8 @@
<field name="parent_id" ref="analytic_customers"/>
<field name="partner_id" ref="base.res_partner_1"/>
</record>
<record id="analytic_distripc" model="account.analytic.account">
<field name="name">DistriPC</field>
<record id="analytic_deltapc" model="account.analytic.account">
<field name="name">Delta PC</field>
<field name="parent_id" ref="analytic_customers"/>
<field name="type">normal</field>
<field name="partner_id" ref="base.res_partner_4"/>
@ -145,8 +145,8 @@
<field name="partner_id" ref="base.res_partner_17"/>
<field name="state">open</field>
</record>
<record id="analytic_leclerc" model="account.analytic.account">
<field name="name">Leclerc</field>
<record id="analytic_luminous_technologies" model="account.analytic.account">
<field name="name">Luminous Technologies</field>
<field eval="time.strftime('%Y-04-24')" name="date_start"/>
<field eval="str(time.localtime()[0] + 1) + '-04-24'" name="date"/>
<field name="type">normal</field>
@ -161,8 +161,8 @@
<field name="parent_id" ref="analytic_partners"/>
<field name="partner_id" ref="base.res_partner_12"/>
</record>
<record id="analytic_tiny_at_work" model="account.analytic.account">
<field name="name">OpenERP SA AT Work</field>
<record id="analytic_think_big_systems" model="account.analytic.account">
<field name="name">Think Big Systems</field>
<field name="type">normal</field>
<field name="parent_id" ref="analytic_partners"/>
<field name="partner_id" ref="base.res_partner_18"/>

View File

@ -35,7 +35,6 @@
<field name="partner_id"/>
<field name="user_id"/>
<group expand="0" string="Group By...">
<filter string="Manager" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Associated Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Parent Account" icon="terp-folder-green" domain="[]" context="{'group_by':'parent_id'}"/>
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}" groups="base.group_no_one"/>
@ -144,8 +143,8 @@
<field name="product_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id, journal_id)"/>
<label for="unit_amount"/>
<div>
<field name="unit_amount" class="oe_inline"/>
<field name="product_uom_id" class="oe_inline"/>
<field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)" class="oe_inline"/>
<field name="product_uom_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)" class="oe_inline"/>
</div>
</group>
<group string="General Accounting">

View File

@ -42,7 +42,7 @@
<field name="arch" type="xml">
<graph string="Invoices Analysis" type="bar">
<field name="product_id"/>
<field name="user_currency_price_total"/>
<field name="price_total"/>
</graph>
</field>
</record>

View File

@ -277,7 +277,7 @@
<font color="white"> </font>
</para>
<section>
<para style="terp_default_Bold_9">[[ getLines(o) and removeParentNode('section')]]There is nothing due with this customer</para>
<para style="terp_default_Bold_9">[[ getLines(o) and removeParentNode('section')]]There is nothing due with this customer.</para>
</section>
<para style="terp_default_9">
<font color="white"> </font>

View File

@ -268,7 +268,7 @@
<field name="target">inline</field>
</record>
<menuitem id="menu_account_config" name="Accounting" parent="base.menu_config"
<menuitem id="menu_account_config" name="Invoicing" parent="base.menu_config"
sequence="14" action="action_account_config"/>
</data>

View File

@ -48,7 +48,7 @@ openerp.account = function (instance) {
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 mod.call("list_partners_to_reconcile", []).pipe(function(result) {
return mod.call("list_partners_to_reconcile", []).then(function(result) {
var current = self.current_partner !== null ? self.partners[self.current_partner][0] : null;
self.partners = result;
var index = _.find(_.range(self.partners.length), function(el) {
@ -74,7 +74,7 @@ openerp.account = function (instance) {
return fct();
} else {
return new instance.web.Model("res.partner").call("read",
[self.partners[self.current_partner][0], ["last_reconciliation_date"]]).pipe(function(res) {
[self.partners[self.current_partner][0], ["last_reconciliation_date"]]).then(function(res) {
self.last_reconciliation_date =
instance.web.format_value(res.last_reconciliation_date, {"type": "datetime"}, _t("Never"));
return fct();
@ -92,7 +92,7 @@ openerp.account = function (instance) {
return false;
}
new instance.web.Model("ir.model.data").call("get_object_reference", ["account", "action_view_account_move_line_reconcile"]).pipe(function(result) {
new instance.web.Model("ir.model.data").call("get_object_reference", ["account", "action_view_account_move_line_reconcile"]).then(function(result) {
var additional_context = _.extend({
active_id: ids[0],
active_ids: ids,
@ -101,7 +101,7 @@ openerp.account = function (instance) {
return self.rpc("/web/action/load", {
action_id: result[1],
context: additional_context
}).then(function (result) {
}).done(function (result) {
result.context = _.extend(result.context || {}, additional_context);
result.flags = result.flags || {};
result.flags.new_window = true;
@ -116,7 +116,7 @@ openerp.account = function (instance) {
mark_as_reconciled: function() {
var self = this;
var id = self.partners[self.current_partner][0];
new instance.web.Model("res.partner").call("mark_as_reconciled", [[id]]).pipe(function() {
new instance.web.Model("res.partner").call("mark_as_reconciled", [[id]]).then(function() {
self.do_search(self.last_domain, self.last_context, self.last_group_by);
});
},

View File

@ -5,6 +5,7 @@
<!-- Top menu item -->
<menuitem name="Accounting"
id="account.menu_finance"/>
<menuitem id="account.menu_account_config" name="Accounting" parent="base.menu_config"/>
</data>

View File

@ -3,13 +3,21 @@
<menuitem id="base.menu_invoiced" name="Invoicing" parent="base.menu_base_partner" sequence="5"/>
<record id="action_hr_tree_invoiced_all" model="ir.actions.act_window">
<field name="name">Time &amp; Costs to Invoice</field>
<field name="name">Time &amp; Materials to Invoice</field>
<field name="res_model">account.analytic.line</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_id','=',False)]</field>
<field name="context">{'search_default_to_invoice': 1}</field>
<field name="search_view_id" ref="account.view_account_analytic_line_filter"/>
<field name="help" type="html">
<p>
You will find here timesheets and purchases you did for
contracts that can be reinvoiced to the customer. If you want
to record new activities to invoice, you should use the timesheet
menu instead.
</p>
</field>
</record>
<menuitem action="action_hr_tree_invoiced_all" id="menu_action_hr_tree_invoiced_all" parent="base.menu_invoiced" sequence="5"/>

View File

@ -38,7 +38,7 @@ Allows to automatically select analytic accounts based on criterions:
'author': 'OpenERP SA',
'website': 'http://www.openerp.com',
'images': ['images/analytic_defaults.jpeg'],
'depends': ['sale'],
'depends': ['sale_stock'],
'data': [
'security/ir.model.access.csv',
'security/account_analytic_default_security.xml',

View File

@ -38,14 +38,14 @@ class product_category(osv.osv):
relation='account.account',
string="Income Account",
view_load=True,
help="This account will be used to value outgoing stock for the current product category using sale price"),
help="This account will be used to value outgoing stock using sale price."),
'property_account_expense_categ': fields.property(
'account.account',
type='many2one',
relation='account.account',
string="Expense Account",
view_load=True,
help="This account will be used to value outgoing stock for the current product category using cost price"),
help="This account will be used to value outgoing stock using cost price."),
}
product_category()
@ -68,14 +68,14 @@ class product_template(osv.osv):
relation='account.account',
string="Income Account",
view_load=True,
help="This account will be used to value outgoing stock for the current product category using sale price"),
help="This account will be used to value outgoing stock using sale price."),
'property_account_expense': fields.property(
'account.account',
type='many2one',
relation='account.account',
string="Expense Account",
view_load=True,
help="This account will be used to value outgoing stock for the current product category using cost price"),
help="This account will be used to value outgoing stock using cost price."),
}
product_template()

View File

@ -29,10 +29,10 @@
<record id="view_category_property_form" model="ir.ui.view">
<field name="name">product.category.property.form.inherit.stock</field>
<field name="model">product.category</field>
<field name="inherit_id" ref="product.product_category_form_view"/>
<field name="inherit_id" ref="account.view_category_property_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="/form/sheet//group[@name='account_property']" position="inside">
<xpath expr="//field[@name='property_account_income_categ']" position="before">
<field name="property_account_creditor_price_difference_categ" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
</xpath>
</data>

View File

@ -134,10 +134,11 @@ class account_asset_asset(osv.osv):
def compute_depreciation_board(self, cr, uid, ids, context=None):
depreciation_lin_obj = self.pool.get('account.asset.depreciation.line')
currency_obj = self.pool.get('res.currency')
for asset in self.browse(cr, uid, ids, context=context):
if asset.value_residual == 0.0:
continue
posted_depreciation_line_ids = depreciation_lin_obj.search(cr, uid, [('asset_id', '=', asset.id), ('move_check', '=', True)])
posted_depreciation_line_ids = depreciation_lin_obj.search(cr, uid, [('asset_id', '=', asset.id), ('move_check', '=', True)],order='depreciation_date desc')
old_depreciation_line_ids = depreciation_lin_obj.search(cr, uid, [('asset_id', '=', asset.id), ('move_id', '=', False)])
if old_depreciation_line_ids:
depreciation_lin_obj.unlink(cr, uid, old_depreciation_line_ids, context=context)
@ -148,7 +149,12 @@ class account_asset_asset(osv.osv):
else:
# depreciation_date = 1st January of purchase year
purchase_date = datetime.strptime(asset.purchase_date, '%Y-%m-%d')
depreciation_date = datetime(purchase_date.year, 1, 1)
#if we already have some previous validated entries, starting date isn't 1st January but last entry + method period
if (len(posted_depreciation_line_ids)>0):
last_depreciation_date = datetime.strptime(depreciation_lin_obj.browse(cr,uid,posted_depreciation_line_ids[0],context=context).depreciation_date, '%Y-%m-%d')
depreciation_date = (last_depreciation_date+relativedelta(months=+asset.method_period))
else:
depreciation_date = datetime(purchase_date.year, 1, 1)
day = depreciation_date.day
month = depreciation_date.month
year = depreciation_date.year
@ -158,6 +164,10 @@ class account_asset_asset(osv.osv):
for x in range(len(posted_depreciation_line_ids), undone_dotation_number):
i = x + 1
amount = self._compute_board_amount(cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=context)
company_currency = asset.company_id.currency_id.id
current_currency = asset.currency_id.id
# compute amount into company currency
amount = currency_obj.compute(cr, uid, current_currency, company_currency, amount, context=context)
residual_amount -= amount
vals = {
'amount': amount,
@ -191,7 +201,7 @@ class account_asset_asset(osv.osv):
def _amount_residual(self, cr, uid, ids, name, args, context=None):
cr.execute("""SELECT
l.asset_id as id, round(SUM(abs(l.debit-l.credit))) AS amount
l.asset_id as id, SUM(abs(l.debit-l.credit)) AS amount
FROM
account_move_line l
WHERE
@ -349,8 +359,8 @@ class account_asset_depreciation_line(osv.osv):
'sequence': fields.integer('Sequence', required=True),
'asset_id': fields.many2one('account.asset.asset', 'Asset', required=True),
'parent_state': fields.related('asset_id', 'state', type='char', string='State of Asset'),
'amount': fields.float('Depreciation Amount', required=True),
'remaining_value': fields.float('Amount to Depreciate', required=True),
'amount': fields.float('Depreciation Amount', digits_compute=dp.get_precision('Account'), required=True),
'remaining_value': fields.float('Amount to Depreciate', digits_compute=dp.get_precision('Account'),required=True),
'depreciated_value': fields.float('Amount Already Depreciated', required=True),
'depreciation_date': fields.date('Depreciation Date', select=1),
'move_id': fields.many2one('account.move', 'Depreciation Entry'),

View File

@ -105,7 +105,7 @@ account_bank_statement_line_global()
class account_bank_statement_line(osv.osv):
_inherit = 'account.bank.statement.line'
_columns = {
'val_date': fields.date('Valuta Date', states={'confirm': [('readonly', True)]}),
'val_date': fields.date('Value Date', states={'confirm': [('readonly', True)]}),
'globalisation_id': fields.many2one('account.bank.statement.line.global', 'Globalisation ID',
states={'confirm': [('readonly', True)]},
help="Code to identify transactions belonging to the same globalisation level within a batch payment"),

View File

@ -56,9 +56,6 @@
<field name="globalisation_id"/>
<field name="state" invisible="1"/>
</xpath>
<xpath expr="//page[@name='statement_line_ids']/field[@name='line_ids']/tree/field[@name='date']" position="replace">
<field name="date" string="'Entry Date'" attrs="{'readonly':[('state','=','draft')]}" />
</xpath>
</data>
</field>
</record>
@ -151,7 +148,7 @@
<field name="name">Bank Statement Lines</field>
<field name="res_model">account.bank.statement.line</field>
<field name="view_type">form</field>
<field name="view_mode">tree,graph,form</field>
<field name="view_mode">tree,form</field>
<field name="context">{'block_statement_line_delete' : 1}</field>
<field name="search_view_id" ref="view_bank_statement_line_filter"/>
<field name="view_id" ref="view_bank_statement_line_list"/>

View File

@ -284,13 +284,13 @@
<record model="ir.ui.view" id="view_account_analytic_account_form_inherit_budget">
<field name="name">account.analytic.account.form.inherot.budget</field>
<field name="name">account.analytic.account.form.inherit.budget</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Budget Lines" groups="account.group_account_user">
<field name="crossovered_budget_line" widget="one2many_list" colspan="4" nolabel="1" mode="tree,graph">
<field name="crossovered_budget_line" widget="one2many_list" colspan="4" nolabel="1" mode="tree">
<tree string="Budget Lines" editable="top">
<field name="crossovered_budget_id"/>
<field name="general_budget_id"/>
@ -310,11 +310,6 @@
<field name="paid_date"/>
<field name="planned_amount"/>
</form>
<graph type="bar" string="Lines">
<field name="general_budget_id" />
<field name="planned_amount" operator="+"/>
<field group="True" name="analytic_account_id"/>
</graph>
</field>
</page>
</notebook>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-31 04:40+0000\n"
"X-Launchpad-Export-Date: 2012-11-03 05:04+0000\n"
"X-Generator: Launchpad (build 16218)\n"
#. module: account_payment

View File

@ -712,14 +712,14 @@ class account_voucher(osv.osv):
'move_line_id':line.id,
'account_id':line.account_id.id,
'amount_original': amount_original,
'amount': (move_line_found == line.id) and min(price, amount_unreconciled) or 0.0,
'amount': (move_line_found == line.id) and min(abs(price), amount_unreconciled) or 0.0,
'date_original':line.date,
'date_due':line.date_maturity,
'amount_unreconciled': amount_unreconciled,
'currency_id': line_currency_id,
}
#split voucher amount by most old first, but only for lines in the same currency
#in case a corresponding move_line hasn't been found, we now try to assign the voucher amount
#on existing invoices: we split voucher amount by most old first, but only for lines in the same currency
if not move_line_found:
if currency_id == line_currency_id:
if line.credit:

View File

@ -7,14 +7,15 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n"
"PO-Revision-Date: 2012-05-10 17:31+0000\n"
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
"PO-Revision-Date: 2012-11-07 13:27+0000\n"
"Last-Translator: Frederic Clementi - Camptocamp.com "
"<frederic.clementi@camptocamp.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-30 05:19+0000\n"
"X-Generator: Launchpad (build 16206)\n"
"X-Launchpad-Export-Date: 2012-11-08 04:47+0000\n"
"X-Generator: Launchpad (build 16232)\n"
#. module: account_voucher
#: view:sale.receipt.report:0
@ -469,7 +470,7 @@ msgstr "Délai moyen de règlement"
#. module: account_voucher
#: field:res.company,income_currency_exchange_account_id:0
msgid "Income Currency Rate"
msgstr "Taux de change d'achat"
msgstr "Compte de gain de change"
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:1063
@ -625,9 +626,9 @@ msgid ""
"Unable to create accounting entry for currency rate difference. You have to "
"configure the field 'Income Currency Rate' on the company! "
msgstr ""
"Impossible de créer une entrée de la comptabilité à cause de la différence "
"de taux de change. Vous devez configurer le champ 'Taux de change de vente' "
"sur la société! "
"Impossible de créer une écriture comptable à cause de la différence de taux "
"de change. Vous devez configurer le champ 'Compte de gain de change' au "
"niveau du formulaire de la société! "
#. module: account_voucher
#: view:account.voucher:0 view:sale.receipt.report:0
@ -802,7 +803,7 @@ msgstr "Factures et transactions exceptionnelles"
#. module: account_voucher
#: field:res.company,expense_currency_exchange_account_id:0
msgid "Expense Currency Rate"
msgstr "Taux de change de la dépense"
msgstr "Compte de perte de change"
#. module: account_voucher
#: sql_constraint:account.invoice:0
@ -1089,9 +1090,9 @@ msgid ""
"Unable to create accounting entry for currency rate difference. You have to "
"configure the field 'Expense Currency Rate' on the company! "
msgstr ""
"Impossible de créer une entrée en comptabilité pour la différence de taux de "
"change. Vous devez configurer le champ \"Taux de change d'achat\" de la "
"société ! "
"Impossible de créer une écriture comptable à cause de la différence de taux "
"de change. Vous devez configurer le champ 'Compte de perte de change' au "
"niveau du formulaire de la société! "
#. module: account_voucher
#: field:account.voucher,type:0
@ -1156,7 +1157,7 @@ msgstr "Année"
#. module: account_voucher
#: field:account.voucher.line,amount_unreconciled:0
msgid "Open Balance"
msgstr "Solde initial"
msgstr "Restant dû"
#. module: account_voucher
#: view:account.voucher:0 field:account.voucher,amount:0

View File

@ -290,7 +290,7 @@
<group>
<group>
<field name="state" invisible="1"/>
<field name="partner_id" required="1" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" string="Customer" context="{'search_default_customer': 1}"/>
<field name="partner_id" required="1" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" string="Supplier" context="{'search_default_supplier': 1}"/>
<field name="currency_id" invisible="1"/>
<field name="amount" class="oe_inline"
string="Paid Amount"

View File

@ -180,7 +180,7 @@ class account_analytic_account(osv.osv):
'partner_id': fields.many2one('res.partner', 'Customer'),
'user_id': fields.many2one('res.users', 'Project Manager'),
'manager_id': fields.many2one('res.users', 'Account Manager'),
'date_start': fields.date('Date Start'),
'date_start': fields.date('Start Date'),
'date': fields.date('Date End', select=True),
'company_id': fields.many2one('res.company', 'Company', required=False), #not required because we want to allow different companies to use the same chart of account, except for leaf accounts.
'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'), ('cancelled', 'Cancelled'),('pending','To Renew'),('close','Closed')], 'Status', required=True,),
@ -305,7 +305,10 @@ class account_analytic_account(osv.osv):
def create_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
self.message_post(cr, uid, [obj.id], body=_("Contract for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name),
message = _("Contract <b>created</b>.")
if obj.partner_id:
message = _("Contract for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name,)
self.message_post(cr, uid, [obj.id], body=message,
subtype="analytic.mt_account_status", context=context)
account_analytic_account()

View File

@ -23,11 +23,11 @@
<group>
<field name="partner_id" on_change="on_change_partner_id(partner_id, name)"/>
<field name="manager_id"/>
<field name="code"/>
<field name="currency_id" attrs="{'invisible': ['|',('type', '&lt;&gt;', 'view'), ('company_id', '&lt;&gt;', False)]}"/>
</group>
<group>
<field name="type"/>
<field name="code"/>
<field name="type" invisible="context.get('default_type', False)"/>
<field name="parent_id" on_change="on_change_parent(parent_id)" attrs="{'invisible': [('type','in',['contract','template'])]}"/>
<field name="template_id" on_change="on_change_template(template_id,context)" domain="[('type','=','template')]" attrs="{'invisible': [('type','in',['view', 'normal','template'])]}" context="{'default_type' : 'template'}"/>
<field name="company_id" on_change="on_change_company(company_id)" widget="selection" groups="base.group_multi_company" attrs="{'required': [('type','&lt;&gt;','view')]}"/>
@ -40,7 +40,7 @@
Once the end date of the contract is
passed or the maximum number of service
units (e.g. support contract) is
reached, the account manager is warned
reached, the account manager is notified
by email to renew the contract with the
customer.
</p>

View File

@ -3,7 +3,7 @@ openerp.auth_anonymous = function(instance) {
instance.web.Login.include({
start: function() {
var self = this;
return $.when(this._super()).pipe(function() {
return $.when(this._super()).then(function() {
var dblist = self._db_list || [];
if (!self.session.session_is_valid() && dblist.length === 1) {
self.remember_credentials = false;

View File

@ -12,7 +12,7 @@ openerp.auth_oauth = function(instance) {
} else if(this.params.oauth_error === 2) {
this.do_warn("Authentication error","");
}
return d.then(this.do_oauth_load).fail(function() {
return d.done(this.do_oauth_load).fail(function() {
self.do_oauth_load([]);
});
},
@ -23,7 +23,7 @@ openerp.auth_oauth = function(instance) {
do_oauth_load: function() {
var db = this.$("form [name=db]").val();
if (db) {
this.rpc("/auth_oauth/list_providers", { dbname: db }).then(this.on_oauth_loaded);
this.rpc("/auth_oauth/list_providers", { dbname: db }).done(this.on_oauth_loaded);
}
},
on_oauth_loaded: function(result) {

View File

@ -69,7 +69,7 @@ instance.web.Login = instance.web.Login.extend({
_check_error: function() {
var self = this;
if (this.params.loginerror !== undefined) {
this.rpc('/auth_openid/login/status', {}).then(function(result) {
this.rpc('/auth_openid/login/status', {}).done(function(result) {
if (_.contains(['success', 'failure'], result.status) && result.message) {
self.do_warn('Invalid OpenID Login', result.message);
}
@ -106,7 +106,7 @@ instance.web.Login = instance.web.Login.extend({
do_openid_login: function(db, openid_url) {
var self = this;
this.rpc('/auth_openid/login/verify', {'db': db, 'url': openid_url}).then(function(result) {
this.rpc('/auth_openid/login/verify', {'db': db, 'url': openid_url}).done(function(result) {
if (result.error) {
self.do_warn(result.title, result.error);
return;

View File

@ -20,11 +20,10 @@
##############################################################################
import logging
import werkzeug
import openerp
from openerp.modules.registry import RegistryManager
from openerp.addons.web.controllers.main import login_and_redirect
from ..res_users import SignupError
_logger = logging.getLogger(__name__)
@ -41,22 +40,18 @@ class Controller(openerp.addons.web.http.Controller):
user_info = res_partner.signup_retrieve_info(cr, openerp.SUPERUSER_ID, token)
return user_info
@openerp.addons.web.http.httprequest
def signup(self, req, dbname, token, name, login, password, state=''):
""" sign up a user (new or existing), and log it in """
url = '/'
@openerp.addons.web.http.jsonrequest
def signup(self, req, dbname, token, name, login, password):
""" sign up a user (new or existing)"""
registry = RegistryManager.get(dbname)
with registry.cursor() as cr:
res_users = registry.get('res.users')
values = {'name': name, 'login': login, 'password': password}
try:
res_users = registry.get('res.users')
values = {'name': name, 'login': login, 'password': password}
credentials = res_users.signup(cr, openerp.SUPERUSER_ID, values, token)
cr.commit()
return login_and_redirect(req, *credentials, redirect_url='/#%s'%state)
except Exception as e:
# signup error
_logger.exception('error when signup')
url = "/#action=login&error_message=%s" % werkzeug.urls.url_quote(e.message)
return werkzeug.utils.redirect(url)
res_users.signup(cr, openerp.SUPERUSER_ID, values, token)
except SignupError, e:
return {'error': openerp.tools.exception_to_unicode(e)}
cr.commit()
return {}
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -29,6 +29,9 @@ from openerp import SUPERUSER_ID
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
from openerp.tools.safe_eval import safe_eval
class SignupError(Exception):
pass
def random_token():
# the token has an entropy of about 120 bits (6 bits/char * 20 chars)
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
@ -101,12 +104,12 @@ class res_partner(osv.Model):
partner_ids = self.search(cr, uid, [('signup_token', '=', token)], context=context)
if not partner_ids:
if raise_exception:
raise Exception("Signup token '%s' is not valid" % token)
raise SignupError("Signup token '%s' is not valid" % token)
return False
partner = self.browse(cr, uid, partner_ids[0], context)
if check_validity and not partner.signup_valid:
if raise_exception:
raise Exception("Signup token '%s' is no longer valid" % token)
raise SignupError("Signup token '%s' is no longer valid" % token)
return False
return partner
@ -194,7 +197,7 @@ class res_users(osv.Model):
# check that uninvited users may sign up
if 'partner_id' not in values:
if not safe_eval(ir_config_parameter.get_param(cr, uid, 'auth_signup.allow_uninvited', 'False')):
raise Exception('Signup is not allowed for uninvited users')
raise SignupError('Signup is not allowed for uninvited users')
# create a copy of the template user (attached to a specific partner_id if given)
values['active'] = True

View File

@ -8,12 +8,20 @@ openerp.auth_signup = function(instance) {
var d = this._super();
// to switch between the signup and regular login form
this.$('a.oe_signup_signup').click(function() {
this.$('a.oe_signup_signup').click(function(ev) {
if (ev) {
ev.preventDefault();
}
self.$el.addClass("oe_login_signup");
return false;
});
this.$('a.oe_signup_back').click(function() {
this.$('a.oe_signup_back').click(function(ev) {
if (ev) {
ev.preventDefault();
}
self.$el.removeClass("oe_login_signup");
delete self.params.token;
return false;
});
// if there is an error message in params, show it then forget it
@ -90,10 +98,19 @@ openerp.auth_signup = function(instance) {
name: name,
login: login,
password: password,
state: $.param(this.params)
//state: $.param(this.params)
};
var url = "/auth_signup/signup?" + $.param(params);
window.location = url;
var self = this,
super_ = this._super;
this.rpc('/auth_signup/signup', params)
.done(function(result) {
if (result.error) {
self.show_error(result.error);
} else {
super_.apply(self, [ev]);
}
});
} else {
// regular login
this._super(ev);

View File

@ -300,7 +300,7 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
write['date_action_last'] = time.strftime('%Y-%m-%d %H:%M:%S')
if hasattr(obj, 'state') and action.act_state:
write['state'] = action.act_state
model_obj.write(cr, uid, [obj.id], write, context)
if hasattr(obj, 'state') and hasattr(obj, 'message_post') and action.act_state:
model_obj.message_post(cr, uid, [obj], _(action.act_state), context=context)

View File

@ -16,10 +16,10 @@
<group col="4">
<field name="name"/>
<field name="model_id"/>
<field name="model" invisible="1"/>
<field name="filter_id" domain="[('model_id','=',model)]" context="{'default_model_id': model}"/>
<field name="sequence"/>
<field name="active"/>
<field name="model" invisible="1"/>
</group>
<notebook>
<page string="Conditions">

View File

@ -336,7 +336,7 @@ class calendar_attendee(osv.osv):
('non-participant', 'For information Purpose')], 'Role', \
help='Participation role for the calendar user'),
'state': fields.selection([('needs-action', 'Needs Action'),
('tentative', 'Tentative'),
('tentative', 'Uncertain'),
('declined', 'Declined'),
('accepted', 'Accepted'),
('delegated', 'Delegated')], 'Status', readonly=True, \
@ -559,7 +559,8 @@ property or property parameter."),
for vals in self.browse(cr, uid, ids, context=context):
if vals.ref and vals.ref.user_id:
mod_obj = self.pool.get(vals.ref._name)
defaults = {'user_id': vals.user_id.id, 'organizer_id': vals.ref.user_id.id}
res=mod_obj.read(cr,uid,[vals.ref.id],['duration','class'],context)
defaults = {'user_id': vals.user_id.id, 'organizer_id': vals.ref.user_id.id,'duration':res[0]['duration'],'class':res[0]['class']}
mod_obj.copy(cr, uid, vals.ref.id, default=defaults, context=context)
self.write(cr, uid, vals.id, {'state': 'accepted'}, context)
@ -1012,7 +1013,7 @@ class calendar_event(osv.osv):
'Show Time as', states={'done': [('readonly', True)]}),
'base_calendar_url': fields.char('Caldav URL', size=264),
'state': fields.selection([
('tentative', 'Tentative'),
('tentative', 'Uncertain'),
('cancelled', 'Cancelled'),
('confirmed', 'Confirmed'),
], 'Status', readonly=True),

View File

@ -89,7 +89,8 @@
<page string="Meeting Details">
<group>
<group>
<field name="date" string="Starting at"/>
<field name="date" string="Starting at"
on_change="onchange_dates(date, duration, False, allday)"/>
<label for="duration"/>
<div>
<field name="duration" widget="float_time"
@ -100,7 +101,7 @@
<label for="allday" string="All Day?"/>)
</div>
<field name="date_deadline" groups="base.group_no_one"
attrs="{'invisible': [('allday','=',True)]}"
attrs="{'invisible': ['|', ('allday','=',True), ('duration','&lt;', 24)]}"
on_change="onchange_dates(date,False,date_deadline)"/>
</group>
<group>

View File

@ -1146,7 +1146,7 @@ msgstr ""
#: selection:calendar.attendee,state:0
#: selection:calendar.event,state:0
#: selection:calendar.todo,state:0
msgid "Tentative"
msgid "Uncertain"
msgstr ""
#. module: base_calendar

View File

@ -26,7 +26,7 @@ Re-implement openerp's file import system:
'author': 'OpenERP SA',
'depends': ['base'],
'installable': True,
'auto_install': True,
'auto_install': False,
'css': [
'static/lib/select2/select2.css',
'static/src/css/import.css',

View File

@ -0,0 +1,15 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_base_import_tests_models_char,base.import.tests.models.char,model_base_import_tests_models_char,base.group_user,1,1,1,1
access_base_import_tests_models_char_required,base.import.tests.models.char.required,model_base_import_tests_models_char_required,base.group_user,1,1,1,1
access_base_import_tests_models_char_readonly,base.import.tests.models.char.readonly,model_base_import_tests_models_char_readonly,base.group_user,1,1,1,1
access_base_import_tests_models_char_states,base.import.tests.models.char.states,model_base_import_tests_models_char_states,base.group_user,1,1,1,1
access_base_import_tests_models_char_noreadonly,base.import.tests.models.char.noreadonly,model_base_import_tests_models_char_noreadonly,base.group_user,1,1,1,1
access_base_import_tests_models_char_stillreadonly,base.import.tests.models.char.stillreadonly,model_base_import_tests_models_char_stillreadonly,base.group_user,1,1,1,1
access_base_import_tests_models_m2o,base.import.tests.models.m2o,model_base_import_tests_models_m2o,base.group_user,1,1,1,1
access_base_import_tests_models_m2o_related,base.import.tests.models.m2o.related,model_base_import_tests_models_m2o_related,base.group_user,1,1,1,1
access_base_import_tests_models_m2o_required,base.import.tests.models.m2o.required,model_base_import_tests_models_m2o_required,base.group_user,1,1,1,1
access_base_import_tests_models_m2o_required_related,base.import.tests.models.m2o.required.related,model_base_import_tests_models_m2o_required_related,base.group_user,1,1,1,1
access_base_import_tests_models_o2m,base.import.tests.models.o2m,model_base_import_tests_models_o2m,base.group_user,1,1,1,1
access_base_import_tests_models_o2m_child,base.import.tests.models.o2m.child,model_base_import_tests_models_o2m_child,base.group_user,1,1,1,1
access_base_import_tests_models_preview,base.import.tests.models.preview,model_base_import_tests_models_preview,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_base_import_tests_models_char base.import.tests.models.char model_base_import_tests_models_char base.group_user 1 1 1 1
3 access_base_import_tests_models_char_required base.import.tests.models.char.required model_base_import_tests_models_char_required base.group_user 1 1 1 1
4 access_base_import_tests_models_char_readonly base.import.tests.models.char.readonly model_base_import_tests_models_char_readonly base.group_user 1 1 1 1
5 access_base_import_tests_models_char_states base.import.tests.models.char.states model_base_import_tests_models_char_states base.group_user 1 1 1 1
6 access_base_import_tests_models_char_noreadonly base.import.tests.models.char.noreadonly model_base_import_tests_models_char_noreadonly base.group_user 1 1 1 1
7 access_base_import_tests_models_char_stillreadonly base.import.tests.models.char.stillreadonly model_base_import_tests_models_char_stillreadonly base.group_user 1 1 1 1
8 access_base_import_tests_models_m2o base.import.tests.models.m2o model_base_import_tests_models_m2o base.group_user 1 1 1 1
9 access_base_import_tests_models_m2o_related base.import.tests.models.m2o.related model_base_import_tests_models_m2o_related base.group_user 1 1 1 1
10 access_base_import_tests_models_m2o_required base.import.tests.models.m2o.required model_base_import_tests_models_m2o_required base.group_user 1 1 1 1
11 access_base_import_tests_models_m2o_required_related base.import.tests.models.m2o.required.related model_base_import_tests_models_m2o_required_related base.group_user 1 1 1 1
12 access_base_import_tests_models_o2m base.import.tests.models.o2m model_base_import_tests_models_o2m base.group_user 1 1 1 1
13 access_base_import_tests_models_o2m_child base.import.tests.models.o2m.child model_base_import_tests_models_o2m_child base.group_user 1 1 1 1
14 access_base_import_tests_models_preview base.import.tests.models.preview model_base_import_tests_models_preview base.group_user 1 1 1 1

View File

@ -0,0 +1,6 @@
External ID,Name,Parent Category/External ID
a1,Expenses,product.product_category_all
a2,Other Products,product.product_category_all
a3,Sellable Products,product.product_category_all
a4,Tables,a1
a5,Seating furniture,a2
1 External ID Name Parent Category/External ID
2 a1 Expenses product.product_category_all
3 a2 Other Products product.product_category_all
4 a3 Sellable Products product.product_category_all
5 a4 Tables a1
6 a5 Seating furniture a2

View File

@ -0,0 +1,6 @@
External ID,Name,Internal Reference,Category/External ID,Can be Expensed,Can be Purchased,Can be Sold,Sale Price,Cost,Supply Method,Product Type,Procurement Method
a6,Aluminum Stool,ALS,a5,False,True,True,49.00,25.00,Buy,Stockable Product,Make to Stock
a7,Chair,CHR,a5,False,True,True,89.00,40.00,Buy,Stockable Product,Make to Stock
a8,Table,TBL,a4,False,True,True,169.00,100.00,Buy,Stockable Product,Make to Stock
a9,Software Book Tutorial,SBT,a2,False,True,False,19.00,8.00,Buy,Consumable,Make to Stock
a10,Fuel,FL,a1,True,False,False,0.30,0.25,Buy,Service,Make to Stock
1 External ID Name Internal Reference Category/External ID Can be Expensed Can be Purchased Can be Sold Sale Price Cost Supply Method Product Type Procurement Method
2 a6 Aluminum Stool ALS a5 False True True 49.00 25.00 Buy Stockable Product Make to Stock
3 a7 Chair CHR a5 False True True 89.00 40.00 Buy Stockable Product Make to Stock
4 a8 Table TBL a4 False True True 169.00 100.00 Buy Stockable Product Make to Stock
5 a9 Software Book Tutorial SBT a2 False True False 19.00 8.00 Buy Consumable Make to Stock
6 a10 Fuel FL a1 True False False 0.30 0.25 Buy Service Make to Stock

View File

@ -0,0 +1,6 @@
Name,Internal Reference,Can be Expensed,Can be Purchased,Can be Sold,Sale Price,Cost,Supply Method,Product Type,Procurement Method
Aluminum Stool,ALS,False,True,True,49.00,25.00,Buy,Stockable Product,Make to Stock
Chair,CHR,False,True,True,89.00,40.00,Buy,Stockable Product,Make to Stock
Table,TBL,False,True,True,169.00,100.00,Buy,Stockable Product,Make to Stock
Software Book Tutorial,SBT,False,True,False,19.00,8.00,Buy,Consumable,Make to Stock
Fuel,FL,True,False,False,0.30,0.25,Buy,Service,Make to Stock
1 Name Internal Reference Can be Expensed Can be Purchased Can be Sold Sale Price Cost Supply Method Product Type Procurement Method
2 Aluminum Stool ALS False True True 49.00 25.00 Buy Stockable Product Make to Stock
3 Chair CHR False True True 89.00 40.00 Buy Stockable Product Make to Stock
4 Table TBL False True True 169.00 100.00 Buy Stockable Product Make to Stock
5 Software Book Tutorial SBT False True False 19.00 8.00 Buy Consumable Make to Stock
6 Fuel FL True False False 0.30 0.25 Buy Service Make to Stock

View File

@ -0,0 +1,155 @@
--
-- PostgreSQL database dump
--
SET statement_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET escape_string_warning = off;
SET search_path = public, pg_catalog;
SET default_tablespace = '';
SET default_with_oids = false;
--
-- Name: companies; Type: TABLE; Schema: public; Owner: fp; Tablespace:
--
CREATE TABLE companies (
id integer NOT NULL,
company_name character varying
);
ALTER TABLE public.companies OWNER TO fp;
--
-- Name: companies_id_seq; Type: SEQUENCE; Schema: public; Owner: fp
--
CREATE SEQUENCE companies_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
ALTER TABLE public.companies_id_seq OWNER TO fp;
--
-- Name: companies_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: fp
--
ALTER SEQUENCE companies_id_seq OWNED BY companies.id;
--
-- Name: companies_id_seq; Type: SEQUENCE SET; Schema: public; Owner: fp
--
SELECT pg_catalog.setval('companies_id_seq', 3, true);
--
-- Name: persons; Type: TABLE; Schema: public; Owner: fp; Tablespace:
--
CREATE TABLE persons (
id integer NOT NULL,
company_id integer,
person_name character varying
);
ALTER TABLE public.persons OWNER TO fp;
--
-- Name: persons_id_seq; Type: SEQUENCE; Schema: public; Owner: fp
--
CREATE SEQUENCE persons_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
ALTER TABLE public.persons_id_seq OWNER TO fp;
--
-- Name: persons_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: fp
--
ALTER SEQUENCE persons_id_seq OWNED BY persons.id;
--
-- Name: persons_id_seq; Type: SEQUENCE SET; Schema: public; Owner: fp
--
SELECT pg_catalog.setval('persons_id_seq', 4, true);
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: fp
--
ALTER TABLE ONLY companies ALTER COLUMN id SET DEFAULT nextval('companies_id_seq'::regclass);
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: fp
--
ALTER TABLE ONLY persons ALTER COLUMN id SET DEFAULT nextval('persons_id_seq'::regclass);
--
-- Data for Name: companies; Type: TABLE DATA; Schema: public; Owner: fp
--
COPY companies (id, company_name) FROM stdin;
1 Bigees
2 Organi
3 Boum
\.
--
-- Data for Name: persons; Type: TABLE DATA; Schema: public; Owner: fp
--
COPY persons (id, company_id, person_name) FROM stdin;
1 1 Fabien
2 1 Laurence
3 2 Eric
4 3 Ramsy
\.
--
-- Name: companies_pkey; Type: CONSTRAINT; Schema: public; Owner: fp; Tablespace:
--
ALTER TABLE ONLY companies
ADD CONSTRAINT companies_pkey PRIMARY KEY (id);
--
-- Name: persons_company_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: fp
--
ALTER TABLE ONLY persons
ADD CONSTRAINT persons_company_id_fkey FOREIGN KEY (company_id) REFERENCES companies(id);
--
-- PostgreSQL database dump complete
--

View File

@ -0,0 +1,6 @@
Name,Reference,Tags,Customer,Street,City,Country
Credit & Leasing,3,Services,True,Central Avenue 814,Johannesburg,South Africa
Services & Finance,5,"Consultancy Services,IT Services",True,Grove Road 5,London,United Kingdom
Hydra Supplies,6,"Manufacturer,Retailer",True,Palm Street 9,Los Angeles,United States
Bolts & Screws,8,"Wholesaler,Components Buyer",True,Rua Américo 1000,Campinas,Brazil
National Parts & Supplies,18,"Manufacturer,Wholesaler",True,Guangdong Way 20,Shenzen,China
1 Name Reference Tags Customer Street City Country
2 Credit & Leasing 3 Services True Central Avenue 814 Johannesburg South Africa
3 Services & Finance 5 Consultancy Services,IT Services True Grove Road 5 London United Kingdom
4 Hydra Supplies 6 Manufacturer,Retailer True Palm Street 9 Los Angeles United States
5 Bolts & Screws 8 Wholesaler,Components Buyer True Rua Américo 1000 Campinas Brazil
6 National Parts & Supplies 18 Manufacturer,Wholesaler True Guangdong Way 20 Shenzen China

View File

@ -0,0 +1,10 @@
Order Date,Order Reference,Supplier,Destination,Pricelist,Order Lines / Product,Order Lines / Quantity
2012-12-15,PO00008,ASUSTeK,Stock,Default Purchase Pricelist,ADPT,20
,,,,,CARD,30
,,,,,C-Case,40
2012-12-15,PO00009,Axelor,Stock,Default Purchase Pricelist,CD,5
,,,,,CPUa8,15
2012-12-15,PO000010,China Export,Stock,Default Purchase Pricelist,HDD SH-1,10
,,,,,HDD SH-2,20
,,,,,LAP-CUS,35
,,,,,LAP-E5,40
1 Order Date Order Reference Supplier Destination Pricelist Order Lines / Product Order Lines / Quantity
2 2012-12-15 PO00008 ASUSTeK Stock Default Purchase Pricelist ADPT 20
3 CARD 30
4 C-Case 40
5 2012-12-15 PO00009 Axelor Stock Default Purchase Pricelist CD 5
6 CPUa8 15
7 2012-12-15 PO000010 China Export Stock Default Purchase Pricelist HDD SH-1 10
8 HDD SH-2 20
9 LAP-CUS 35
10 LAP-E5 40

View File

@ -0,0 +1,8 @@
Name,Address type,Street,City,Country,Tags,Supplier,Customer,Is a company,Companies that refers to partner / Parent company
Wood y Wood Pecker,,"Snow Street, 25",Kainuu,Finland,Supplier,1,0,1,
Roger Pecker,Default,"Snow Street, 27",Kainuu,Finland,Supplier,1,0,0,Wood y Wood Pecker
Sharon Pecker,Delivery,"Snow Street, 28",Kainuu,Finland,Supplier,1,0,0,Wood y Wood Pecker
Thomas Pecker,Contact,"Snow Street, 27",Kainuu,Finland,Supplier,1,0,0,Wood y Wood Pecker
Vicking Direct,,"Atonium Street, 45a",Brussels,Belgium,Supplier,1,0,1,
Yvan Holiday,Invoice,"Atonium Street, 45b",Brussels,Belgium,Supplier,1,0,0,Vicking Direct
Jack Unsworth,Contact,"Atonium Street, 45a",Brussels,Belgium,Supplier,1,0,0,Vicking Direct
1 Name Address type Street City Country Tags Supplier Customer Is a company Companies that refers to partner / Parent company
2 Wood y Wood Pecker Snow Street, 25 Kainuu Finland Supplier 1 0 1
3 Roger Pecker Default Snow Street, 27 Kainuu Finland Supplier 1 0 0 Wood y Wood Pecker
4 Sharon Pecker Delivery Snow Street, 28 Kainuu Finland Supplier 1 0 0 Wood y Wood Pecker
5 Thomas Pecker Contact Snow Street, 27 Kainuu Finland Supplier 1 0 0 Wood y Wood Pecker
6 Vicking Direct Atonium Street, 45a Brussels Belgium Supplier 1 0 1
7 Yvan Holiday Invoice Atonium Street, 45b Brussels Belgium Supplier 1 0 0 Vicking Direct
8 Jack Unsworth Contact Atonium Street, 45a Brussels Belgium Supplier 1 0 0 Vicking Direct

View File

@ -0,0 +1,6 @@
"Order Reference","Supplier","Destination","Pricelist","Order Lines / Product","Order Lines / Quantity"
"PO000020","ASUSTeK","Stock","Default Purchase Pricelist","ADPT",20
,,,,"CARD",30
,,,,"C-Case",40
"PO000021","Axelor","Stock","Default Purchase Pricelist","CD",5
,,,,"CPUa8",15
1 Order Reference Supplier Destination Pricelist Order Lines / Product Order Lines / Quantity
2 PO000020 ASUSTeK Stock Default Purchase Pricelist ADPT 20
3 CARD 30
4 C-Case 40
5 PO000021 Axelor Stock Default Purchase Pricelist CD 5
6 CPUa8 15

View File

@ -1,14 +1,17 @@
.oe_import{
display: inline-block;
width: 600px;
padding: 16px;
}
.oe_import > p {
margin-left: 8px;
margin-right: 8px;
text-align: justify
}
.oe_import h2 {
margin-top: 0;
margin-bottom: 5px;
}
.oe_padding {
padding: 13px;
}
/* ----------- IMPORT BOX ----------- */
.oe_import .oe_import_box{
@ -17,6 +20,7 @@
background: #F0EEEE;
border-radius: 3px;
border: solid 1px #dddddd;
width: 600px;
}
.oe_import .oe_import_toggle{
margin-top: 8px;

View File

@ -123,10 +123,10 @@ openerp.base_import = function (instance) {
this.exit();
}
},
init: function (parent, params) {
init: function (parent, action) {
var self = this;
this._super.apply(this, arguments);
this.res_model = params.model;
this.res_model = action.params.model;
// import object id
this.id = null;
this.Import = new instance.web.Model('base_import.import');
@ -139,7 +139,7 @@ openerp.base_import = function (instance) {
this._super(),
this.Import.call('create', [{
'res_model': this.res_model
}]).then(function (id) {
}]).done(function (id) {
self.id = id;
self.$('input[name=import_id]').val(id);
})
@ -179,7 +179,8 @@ openerp.base_import = function (instance) {
//- File & settings change section
onfile_loaded: function () {
this.$('.oe_import_button').prop('disabled', true);
this.$('.oe_import_button, .oe_import_file_reload')
.prop('disabled', true);
if (!this.$('input.oe_import_file').val()) { return; }
this.$el.removeClass('oe_import_preview oe_import_error');
@ -189,7 +190,8 @@ openerp.base_import = function (instance) {
},
onpreviewing: function () {
var self = this;
this.$('.oe_import_button').prop('disabled', true);
this.$('.oe_import_button, .oe_import_file_reload')
.prop('disabled', true);
this.$el.addClass('oe_import_with_file');
// TODO: test that write // succeeded?
this.$el.removeClass('oe_import_preview_error oe_import_error');
@ -198,13 +200,14 @@ openerp.base_import = function (instance) {
!this.$('input.oe_import_has_header').prop('checked'));
this.Import.call(
'parse_preview', [this.id, this.import_options()])
.then(function (result) {
.done(function (result) {
var signal = result.error ? 'preview_failed' : 'preview_succeeded';
self[signal](result);
});
},
onpreview_error: function (event, from, to, result) {
this.$('.oe_import_options').show();
this.$('.oe_import_file_reload').prop('disabled', false);
this.$el.addClass('oe_import_preview_error oe_import_error');
this.$('.oe_import_error_report').html(
QWeb.render('ImportView.preview.error', result));
@ -212,7 +215,8 @@ openerp.base_import = function (instance) {
onpreview_success: function (event, from, to, result) {
this.$('.oe_import_import').removeClass('oe_highlight');
this.$('.oe_import_validate').addClass('oe_highlight');
this.$('.oe_import_button').prop('disabled', false);
this.$('.oe_import_button, .oe_import_file_reload')
.prop('disabled', false);
this.$el.addClass('oe_import_preview');
this.$('table').html(QWeb.render('ImportView.preview', result));
@ -337,11 +341,11 @@ openerp.base_import = function (instance) {
},
onvalidate: function () {
return this.call_import({ dryrun: true })
.then(this.proxy('validated'));
.done(this.proxy('validated'));
},
onimport: function () {
var self = this;
return this.call_import({ dryrun: false }).then(function (message) {
return this.call_import({ dryrun: false }).done(function (message) {
if (!_.any(message, function (message) {
return message.type === 'error' })) {
self['import_succeeded']();

View File

@ -2,20 +2,25 @@
<t t-name="ImportView">
<t t-set="_id" t-value="_.uniqueId('export')"/>
<form action="" method="post" enctype="multipart/form-data" class="oe_import">
<header>
<button type="button" disabled="disabled"
class="oe_button oe_import_button oe_import_validate oe_highlight"
>Validate</button>
<button type="button" disabled="disabled"
class="oe_button oe_import_button oe_import_import"
>Import</button>
<span class="oe_fade">or</span>
<a class="oe_import_cancel" href="#">Cancel</a>
</header>
<input type="hidden" name="session_id"
t-att-value="widget.session.session_id"/>
<input type="hidden" name="import_id"/>
<h2>Upload your file</h2>
<div class="oe_view_manager oe_view_manager_current">
<div class="oe_view_manager_header oe_padding">
<h2>
Import a CSV File
</h2>
<input type="hidden" name="session_id"
t-att-value="widget.session.session_id"/>
<input type="hidden" name="import_id"/>
<button type="button" disabled="disabled"
class="oe_button oe_import_button oe_import_validate oe_highlight"
>Validate</button>
<button type="button" disabled="disabled"
class="oe_button oe_import_button oe_import_import"
>Import</button>
<span class="oe_fade">or</span>
<a class="oe_import_cancel" href="#">Cancel</a>
</div>
</div>
<p>Select the <a
href="http://en.wikipedia.org/wiki/Comma-separated_values"
class="oe_import_csv" target="_blank">.CSV</a>
@ -25,7 +30,9 @@
<label t-attf-for="file_#{_id}" autofocus="autofocus">CSV File:</label>
<input type="file" id-attf-id="file_#{_id}"
name="file" class="oe_import_file"/>
<button type="button" class="oe_import_file_reload">
<button type="button" class="oe_import_file_reload"
disabled="disabled"
title="Reload data to check changes.">
<img src="/web/static/src/img/icons/gtk-refresh.png"/>
</button>
<div class="oe_import_with_file">
@ -44,7 +51,7 @@
</div>
</div>
<div class="oe_import_with_file">
<div class="oe_import_with_file oe_padding">
<h2>Map your data to OpenERP</h2>
<input type="checkbox" class="oe_import_has_header"
id="oe_import_has_header" checked="checked"/>
@ -59,6 +66,7 @@
<table class="oe_import_grid" />
<h2>Frequently Asked Questions</h2>
<dl>
<dt><a href="#" class="oe_import_toggle">
Need to import data from an other application?</a></dt>
@ -78,9 +86,259 @@
whenever possible</p>
</dd>
</dl>
<dl>
<dt><a href="#" class="oe_import_toggle">
What can I do when the Import preview table isn't
displayed correctly?</a></dt>
<dd>
<p>By default the Import preview is set on commas as
field separators and quotation marks as text
delimiters. If your csv file does not have these
settings, you can modify the File Format Options
(displayed under the Browse CSV file bar after you
select your file).</p> <p>Note that if your CSV file
has a tabulation as separator, OpenERP will not
detect the separations. You will need to change the
file format options in your spreadsheet application.
See the following question.</p>
</dd>
</dl>
<dl>
<dt><a href="#" class="oe_import_toggle">
How can I change the CSV file format options when
saving in my spreadsheet application?</a></dt>
<dd>
<p>If you edit and save CSV files in speadsheet
applications, your computer's regional settings will
be applied for the separator and delimiter.
We suggest you use OpenOffice or LibreOffice Calc
as they will allow you to modify all three options
(in 'Save As' dialog box > Check the box 'Edit filter
settings' > Save).</p> <p>Microsoft Excel will allow
you to modify only the encoding when saving
(in 'Save As' dialog box > click 'Tools' dropdown
list > Encoding tab).</p>
</dd>
</dl>
<dl>
<dt><a href="#" class="oe_import_toggle">
What's the difference between Database ID and
External ID?</a></dt>
<dd>
<p>Some fields define a relationship with another
object. For example, the country of a contact is a
link to a record of the 'Country' object. When you
want to import such fields, OpenERP will have to
recreate links between the different records.
To help you import such fields, OpenERP provides 3
mechanisms. You must use one and only one mechanism
per field you want to import.</p> <p>For example, to
reference the country of a contact, OpenERP proposes
you 3 different fields to import: <ul>
<li>Country: the name or code of the country</li>
<li>Country/Database ID: the unique OpenERP ID for a
record, defined by the ID postgresql column</li>
<li>Country/External ID: the ID of this record
referenced in another application (or the .XML file
that imported it)</li> </ul></p> <p>For the country
Belgium, you can use one of these 3 ways to import:
<ul> <li>Country: Belgium</li> <li>Country/Database
ID: 21</li> <li>Country/External ID: base.be</li>
</ul></p> <p>According to your need, you should use
one of these 3 ways to reference records in relations.
Here is when you should use one or the other,
according to your need: <ul> <li>Use Country: This is
the easiest way when your data come from CSV files
that have been created manually.</li> <li>Use
Country/Database ID: You should rarely use this
notation. It's mostly used by developers as it's main
advantage is to never have conflicts (you may have
several records with the same name, but they always
have a unique Database ID)</li> <li>Use
Country/External ID: Use External ID when you import
data from a third party application.</li> </ul></p>
<p>When you use External IDs, you can import CSV files
with the "External ID" column to define the External
ID of each record you import. Then, you will be able
to make a reference to that record with columns like
"Field/External ID". The following two CSV files give
you an example for Products and their Categories.</p>
<a href="/base_import/static/csv/External_id_3rd_party_application_product_categories.csv">CSV file for categories</a><br/>
<a href="/base_import/static/csv/External_id_3rd_party_application_products.csv">CSV file for Products</a>
</dd>
</dl>
<dl>
<dt><a href="#" class="oe_import_toggle">
What can I do if I have multiple matches for a field?
</a></dt>
<dd>
<p>If for example you have two product categories
with the child name "Sellable" (ie. "Misc.
Products/Sellable" &amp; "Other Products/Sellable"),
your validation is halted but you may still import
your data. However, we recommend you do not import the
data because they will all be linked to the first
'Sellable' category found in the Product Category list
("Misc. Products/Sellable"). We recommend you modify
one of the duplicates' values or your product category
hierarchy.<br/>
However if you do not wish to change your
configuration of product categories, we recommend you
use make use of the external ID for this field
'Category'.</p>
</dd>
</dl>
<dl>
<dt><a href="#" class="oe_import_toggle">
How can I import a many2many relationship field
(e.g. a customer that has multiple tags)?</a></dt>
<dd>
<p>The tags should be separated by a comma without any
spacing. For example, if you want you customer to be
lined to both tags 'Manufacturer' and 'Retailer'
then you will encode it as follow "Manufacturer,
Retailer" in the same column of your CSV file.</p>
<a href="/base_import/static/csv/m2m_customers_tags.csv">
CSV file for Manufacturer, Retailer</a><br/>
</dd>
</dl>
<dl>
<dt><a href="#" class="oe_import_toggle">
How can I import a one2many relationship (e.g. several
Order Lines of a Sale Order)?</a></dt>
<dd>
<p>If you want to import sales order having several
order lines; for each order line, you need to reserve
a specific row in the CSV file. The first order line
will be imported on the same row as the information
relative to order. Any additional lines will need an
addtional row that does not have any information in
the fields relative to the order.</p>
<p>As an example, here is
purchase.order_functional_error_line_cant_adpat.CSV
file of some quotations you can import, based on demo
data.</p>
<a href="/base_import/static/csv/purchase.order_functional_error_line_cant_adpat.csv">File for some Quotations</a>
<p>The following CSV file shows how to import purchase
orders with their respective purchase order lines:</p>
<a href="/base_import/static/csv/o2m_purchase_order_lines.csv">Purchase orders with their respective purchase order lines</a>
<p>The following CSV file shows how to import
suppliers and their respective contacts</p>
<a href="/base_import/static/csv/o2m_suppliers_contacts.csv">Suppliers and their respective contacts</a>
</dd>
</dl>
<dl>
<dt><a href="#" class="oe_import_toggle">
Can I import several times the same record?</a></dt>
<dd>
<p>If you import a file that contains one of the
column "External ID" or "Database ID", records that
have already been imported will be modified instead of
being created. This is very usefull as it allows you
to import several times the same CSV file while having
made some changes in between two imports. OpenERP will
take care of creating or modifying each record
depending if it's new or not.</p> <p> This feature
allows you to use the Import/Export tool of OpenERP to
modify a batch of records in your favorite spreadsheet
application.</p>
</dd>
</dl>
<dl>
<dt><a href="#" class="oe_import_toggle">
What happens if I do not provide a value for a
specific field?</a></dt>
<dd>
<p>If you do not set all fields in your CSV file,
OpenERP will assign the default value for every non
defined fields. But if you
set fields with empty values in your CSV file, OpenERP
will set the EMPTY value in the field, instead of
assigning the default value.</p>
</dd>
</dl>
<dl>
<dt><a href="#" class="oe_import_toggle">
How to export/import different tables from an SQL
application to OpenERP?</a></dt>
<dd>
<p>If you need to import data from different tables,
you will have to recreate relations between records
belonging to different tables. (e.g. if you import
companies and persons, you will have to recreate the
link between each person and the company they work
for).</p> <p>To manage relations between tables,
you can use the "External ID" facilities of OpenERP.
The "External ID" of a record is the unique identifier
of this record in another application. This "External
ID" must be unique accoss all the records of all
objects, so it's a good practice to prefix this
"External ID" with the name of the application or
table. (like 'company_1', 'person_1' instead of '1')
</p> <p>As an example, suppose you have a SQL database
with two tables you want to import: companies and
persons. Each person belong to one company, so you
will have to recreate the link between a person and
the company he work for. (If you want to test this
example, here is a <a href="/base_import/static/csv/database_import_test.sql">
dump of such a PostgreSQL database</a>).</p>
<p>We will first export all companies and their
"External ID". In PSQL, write the following command:
</p> <p>&#160;&#160;&#160;&#160;copy
(select 'company_'||id as "External ID",company_name
as "Name",'True' as "Is a Company" from companies) TO
'/tmp/company.csv' with CSV HEADER;</p>
<p>This SQL command will create the following CSV file:
<br/>&#160;&#160;&#160;&#160;External ID,Name,Is a Company
<br/>&#160;&#160;&#160;&#160;company_1,Bigees,True
<br/>&#160;&#160;&#160;&#160;company_2,Organi,True
<br/>&#160;&#160;&#160;&#160;company_3,Boum,True</p>
<p>To create the CSV file for persons, linked to
companies, we will use the following SQL command in
PSQL:</p> <p>&#160;&#160;&#160;&#160;copy (select
'person_'||id as "External ID",person_name as
"Name",'False' as "Is a Company",'company_'||company_id
as "Related Company/External ID" from persons) TO
'/tmp/person.csv' with CSV</p>
<p>It will produce the following CSV file:
<br/>&#160;&#160;&#160;&#160;External ID,Name,Is a
Company,Related Company/External ID
<br/>&#160;&#160;&#160;&#160;person_1,Fabien,False,company_1
<br/>&#160;&#160;&#160;&#160;person_2,Laurence,False,company_1
<br/>&#160;&#160;&#160;&#160;person_3,Eric,False,company_2
<br/>&#160;&#160;&#160;&#160;person_4,Ramsy,False,company_3</p>
<p>As you can see in this file, Fabien and Laurence
are working for the Bigees company (company_1) and
Eric is working for the Organi company. The relation
between persons and companies is done using the
External ID of the companies. We had to prefix the
"External ID" by the name of the table to avoid a
conflict of ID between persons and companies (person_1
and company_1 who shared the same ID 1 in the orignial
database).</p>
<p>The two files produced are ready to be imported in
OpenERP without any modifications. After having
imported these two CSV files, you will have 4 contacts
and 3 companies. (the firsts two contacts are linked
to the first company). You must first import the
companies and then the persons.</p>
</dd>
</dl>
</div>
</form>
</t>
<t t-name="ImportView.preview">
<tr t-if="headers" class="oe_import_grid-header">
<td t-foreach="headers" t-as="header" class="oe_import_grid-cell"

View File

@ -60,14 +60,14 @@ class sale_config_settings(osv.osv_memory):
'module_web_linkedin': fields.boolean('Get contacts automatically from linkedIn',
help="""When you create a new contact (person or company), you will be able to load all the data from LinkedIn (photos, address, etc)."""),
'module_crm': fields.boolean('CRM'),
'module_plugin_thunderbird': fields.boolean('Enable Thunderbird plugin',
'module_plugin_thunderbird': fields.boolean('Enable Thunderbird plug-in',
help="""The plugin allows you archive email and its attachments to the selected
OpenERP objects. You can select a partner, or a lead and
attach the selected mail as a .eml file in
the attachment of a selected record. You can create documents for CRM Lead,
Partner from the selected emails.
This installs the module plugin_thunderbird."""),
'module_plugin_outlook': fields.boolean('Enable Outlook plugin',
'module_plugin_outlook': fields.boolean('Enable Outlook plug-in',
help="""The Outlook plugin allows you to select an object that you would like to add
to your email and its attachments from MS Outlook. You can select a partner,
or a lead object and archive a selected

View File

@ -9,7 +9,7 @@
<field name="arch" type="xml">
<field name="property_account_position" position="after" version="7.0">
<label for="vat"/>
<div>
<div name="vat_info">
<field name="vat" on_change="vat_change(vat)" placeholder="e.g. BE0477472701" class="oe_inline"/>
<button colspan="2" name="button_check_vat" string="Check Validity" type="object" icon="gtk-execute" class="oe_inline"/>
<field name="vat_subjected" class="oe_inline"/>

View File

@ -46,7 +46,7 @@ instance.web.form.DashBoard = instance.web.form.FormWidget.extend({
delete(action.attrs.colspan);
var action_id = _.str.toNumber(action.attrs.name);
if (!_.isNaN(action_id)) {
self.rpc('/web/action/load', {action_id: action_id}).then(function(result) {
self.rpc('/web/action/load', {action_id: action_id}).done(function(result) {
self.on_load_action(result, column_index + '_' + action_index, action.attrs);
});
}
@ -81,7 +81,7 @@ instance.web.form.DashBoard = instance.web.form.FormWidget.extend({
this.rpc('/web/view/undo_custom', {
view_id: this.view.fields_view.view_id,
reset: true
}).then(this.do_reload);
}).done(this.do_reload);
},
on_change_layout: function() {
var self = this;
@ -242,7 +242,7 @@ instance.web.form.DashBoard = instance.web.form.FormWidget.extend({
};
var list = am.inner_widget.views.list;
if (list) {
list.deferred.then(function() {
list.deferred.done(function() {
$(list.controller.groups).off('row_link').on('row_link', function(e, id) {
new_form_action(id);
});
@ -250,7 +250,7 @@ instance.web.form.DashBoard = instance.web.form.FormWidget.extend({
}
var kanban = am.inner_widget.views.kanban;
if (kanban) {
kanban.deferred.then(function() {
kanban.deferred.done(function() {
kanban.controller.open_record = function(id, editable) {
new_form_action(id, editable);
};
@ -335,7 +335,7 @@ instance.board.AddToDashboard = instance.web.search.Input.extend({
e.preventDefault();
self.add_dashboard();
});
return this.load_data().then(this.proxy("render_data"));
return this.load_data().done(this.proxy("render_data"));
},
load_data:function(){
var board = new instance.web.Model('board.board');
@ -347,7 +347,7 @@ instance.board.AddToDashboard = instance.web.search.Input.extend({
return new instance.web.Model('ir.model.data')
.query(['res_id'])
.filter([['name','=','menu_reporting_dashboard']])
.first().pipe(function (result) {
.first().then(function (result) {
var menu = _(dashboard_menu).chain()
.pluck('children')
.flatten(true)
@ -382,7 +382,7 @@ instance.board.AddToDashboard = instance.web.search.Input.extend({
domain: domain,
view_mode: view_parent.active_view,
name: this.$el.find("input").val()
}).then(function(r) {
}).done(function(r) {
if (r === false) {
self.do_warn("Could not add filter to dashboard");
} else {

View File

@ -188,7 +188,7 @@ class crm_lead(base_stage, format_address, osv.osv):
_columns = {
'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null',
select=True, help="Optional linked partner, usually after conversion of the lead"),
select=True, help="Linked partner (optional). Usually created when converting the lead."),
'id': fields.integer('ID', readonly=True),
'name': fields.char('Subject', size=64, required=True, select=1),
@ -236,7 +236,7 @@ class crm_lead(base_stage, format_address, osv.osv):
'ref': fields.reference('Reference', selection=crm._links_get, size=128),
'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
'phone': fields.char("Phone", size=64),
'date_deadline': fields.date('Expected Closing'),
'date_deadline': fields.date('Expected Closing', help="Estimate of the date on which the opportunity will be won."),
'date_action': fields.date('Next Action Date', select=True),
'title_action': fields.char('Next Action', size=64),
'color': fields.integer('Color Index'),
@ -251,7 +251,7 @@ class crm_lead(base_stage, format_address, osv.osv):
'street2': fields.char('Street2', size=128),
'zip': fields.char('Zip', change_default=True, size=24),
'city': fields.char('City', size=128),
'state_id': fields.many2one("res.country.state", 'State', domain="[('country_id','=',country_id)]"),
'state_id': fields.many2one("res.country.state", 'State'),
'country_id': fields.many2one('res.country', 'Country'),
'phone': fields.char('Phone', size=64),
'fax': fields.char('Fax', size=64),
@ -610,9 +610,9 @@ class crm_lead(base_stage, format_address, osv.osv):
}
def convert_opportunity(self, cr, uid, ids, partner_id, user_ids=False, section_id=False, context=None):
partner = self.pool.get('res.partner')
customer = False
if partner_id:
partner = self.pool.get('res.partner')
customer = partner.browse(cr, uid, partner_id, context=context)
for lead in self.browse(cr, uid, ids, context=context):
if lead.state in ('done', 'cancel'):
@ -676,19 +676,17 @@ class crm_lead(base_stage, format_address, osv.osv):
def convert_partner(self, cr, uid, ids, action='create', partner_id=False, context=None):
"""
This function convert partner based on action.
Convert partner based on action.
if action is 'create', create new partner with contact and assign lead to new partner_id.
otherwise assign lead to specified partner_id
"""
if context is None:
context = {}
partner_ids = {}
force_partner_id = partner_id
for lead in self.browse(cr, uid, ids, context=context):
if action == 'create':
if not partner_id:
partner_id = self._create_lead_partner(cr, uid, lead, context)
partner_id = force_partner_id or self._create_lead_partner(cr, uid, lead, context=context)
self._lead_set_partner(cr, uid, lead, partner_id, context=context)
partner_ids[lead.id] = partner_id
return partner_ids
@ -896,6 +894,10 @@ class crm_lead(base_stage, format_address, osv.osv):
lead.message_post(body=message)
return True
crm_lead()
def onchange_state(self, cr, uid, ids, state_id, context=None):
if state_id:
country_id=self.pool.get('res.country.state').browse(cr, uid, state_id, context).country_id.id
return {'value':{'country_id':country_id}}
return {}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -160,7 +160,7 @@
<field name="street2"/>
<div class="address_format">
<field name="city" placeholder="City" style="width: 40%%"/>
<field name="state_id" options='{"no_open": True}' placeholder="State" style="width: 24%%"/>
<field name="state_id" on_change="onchange_state(state_id)" options='{"no_open": True}' placeholder="State" style="width: 24%%"/>
<field name="zip" placeholder="ZIP" style="width: 34%%"/>
</div>
<field name="country_id" placeholder="Country" options='{"no_open": True}'/>
@ -477,7 +477,7 @@
<field name="street2"/>
<div class="address_format">
<field name="city" placeholder="City" style="width: 40%%"/>
<field name="state_id" options='{"no_open": True}' placeholder="State" style="width: 24%%"/>
<field name="state_id" options='{"no_open": True}' on_change="onchange_state(state_id)" placeholder="State" style="width: 24%%"/>
<field name="zip" placeholder="ZIP" style="width: 34%%"/>
</div>
<field name="country_id" placeholder="Country" options='{"no_open": True}'/>

View File

@ -2,14 +2,6 @@
<openerp>
<data>
<act_window
id="crm_case_categ_phone_create_partner"
name="Schedule a Call"
res_model="crm.phonecall"
view_mode="tree,form,calendar"
context="{'search_default_partner_id': active_id, 'default_duration': 1.0, 'default_partner_id': active_id}"
groups="base.group_sale_salesman"
/>
<!-- TO CONFIRM: This is fine -->
<!-- act_window

View File

@ -56,6 +56,7 @@ added to partners that match the segmentation criterions after computation.'),
@param uid: the current users ID for security checks,
@param ids: List of Process continues IDs"""
partner_obj = self.pool.get('res.partner')
categs = self.read(cr, uid, ids, ['categ_id', 'exclusif', 'partner_id',\
'sales_purchase_active', 'profiling_active'])
for categ in categs:
@ -80,9 +81,11 @@ added to partners that match the segmentation criterions after computation.'),
for pid in to_remove_list:
partners.remove(pid)
for partner_id in partners:
cr.execute('insert into res_partner_res_partner_category_rel (category_id,partner_id) \
values (%s,%s)', (categ['categ_id'][0], partner_id))
for partner in partner_obj.browse(cr, uid, partners):
category_ids = [categ_id.id for categ_id in partner.category_id]
if categ['categ_id'][0] not in category_ids:
cr.execute('insert into res_partner_res_partner_category_rel (category_id,partner_id) \
values (%s,%s)', (categ['categ_id'][0], partner.id))
self.write(cr, uid, [id], {'state':'not running', 'partner_id':0})
return True

View File

@ -115,7 +115,7 @@
name="%(base_calendar.action_crm_meeting)d"
context="{'search_default_partner_ids': active_id, 'default_partner_ids' : [active_id]}"/>
<button type="action" string="Calls"
name="%(crm.crm_case_categ_phone_create_partner)d"
name="%(crm.crm_case_categ_phone_incoming0)d"
context="{'search_default_partner_id': active_id, 'default_duration': 1.0}" />
<button type="action" string="Opportunities" attrs="{'invisible': [('customer', '=', False)]}"
name="%(crm.crm_case_category_act_oppor11)d" context="{'search_default_partner_id': active_id}"/>

View File

@ -175,12 +175,19 @@ class crm_lead2opportunity_mass_convert(osv.osv_memory):
return res
def _convert_opportunity(self, cr, uid, ids, vals, context=None):
"""
When "massively" (more than one at a time) converting leads to
opportunities, check the salesteam_id and salesmen_ids and update
the values before calling super.
"""
if context is None:
context = {}
data = self.browse(cr, uid, ids, context=context)[0]
salesteam_id = data.section_id and data.section_id.id or False
salesman = []
salesmen_ids = []
if data.user_ids:
salesman = [x.id for x in data.user_ids]
vals.update({'user_ids': salesman, 'section_id': salesteam_id})
salesmen_ids = [x.id for x in data.user_ids]
vals.update({'user_ids': salesmen_ids, 'section_id': salesteam_id})
return super(crm_lead2opportunity_mass_convert, self)._convert_opportunity(cr, uid, ids, vals, context=context)
def mass_convert(self, cr, uid, ids, context=None):

View File

@ -35,7 +35,7 @@ class crm_lead2partner(osv.osv_memory):
}
def view_init(self, cr, uid, fields, context=None):
"""
This function checks for precondition before wizard executes
Check for precondition before wizard executes.
"""
if context is None:
context = {}
@ -69,22 +69,19 @@ class crm_lead2partner(osv.osv_memory):
return partner_id
def default_get(self, cr, uid, fields, context=None):
"""
This function gets default values
"""
res = super(crm_lead2partner, self).default_get(cr, uid, fields, context=context)
res = super(crm_lead2partner, self).default_get(cr, uid, fields, context=context)
partner_id = self._select_partner(cr, uid, context=context)
if 'partner_id' in fields:
res.update({'partner_id': partner_id})
if 'action' in fields:
res.update({'action': partner_id and 'exist' or 'create'})
return res
def open_create_partner(self, cr, uid, ids, context=None):
"""
This function Opens form of create partner.
Open form of create partner.
"""
view_obj = self.pool.get('ir.ui.view')
view_id = view_obj.search(cr, uid, [('model', '=', self._name), \
@ -101,21 +98,21 @@ class crm_lead2partner(osv.osv_memory):
def _create_partner(self, cr, uid, ids, context=None):
"""
This function Creates partner based on action.
Create partner based on action.
"""
if context is None:
context = {}
lead = self.pool.get('crm.lead')
lead_ids = context and context.get('active_ids') or []
lead_ids = context.get('active_ids', [])
data = self.browse(cr, uid, ids, context=context)[0]
partner_id = data.partner_id and data.partner_id.id or False
return lead.convert_partner(cr, uid, lead_ids, data.action, partner_id, context=context)
def make_partner(self, cr, uid, ids, context=None):
"""
This function Makes partner based on action.
Make a partner based on action.
Only called from form view, so only meant to convert one lead at a time.
"""
# Only called from Form view, so only meant to convert one Lead.
lead_id = context and context.get('active_id') or False
partner_ids_map = self._create_partner(cr, uid, ids, context=context)
return self.pool.get('res.partner').redirect_partner_form(cr, uid, partner_ids_map.get(lead_id, False), context=context)

View File

@ -96,13 +96,13 @@ class crm_claim(base_stage, osv.osv):
'user_id': fields.many2one('res.users', 'Responsible'),
'user_fault': fields.char('Trouble Responsible', size=64),
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
select=True, help="Sales team to which Case belongs to."\
"Define Responsible user and Email account for"\
select=True, help="Responsible sales team."\
" Define Responsible user and Email account for"\
" mail gateway."),
'company_id': fields.many2one('res.company', 'Company'),
'partner_id': fields.many2one('res.partner', 'Partner'),
'email_cc': fields.text('Watchers Emails', size=252, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
'email_from': fields.char('Email', size=128, help="These people will receive email."),
'email_from': fields.char('Email', size=128, help="Destination email for email gateway."),
'partner_phone': fields.char('Phone', size=32),
'stage_id': fields.many2one ('crm.claim.stage', 'Stage',
domain="['|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),

View File

@ -106,12 +106,6 @@
states="draft,pending" groups="base.group_user"/>
<button name="case_close" string="Done" type="object" class="oe_highlight"
states="open,pending" groups="base.group_user"/>
<button name="case_refuse" string="Refuse" type="object" class="oe_highlight"
states="draft,open,pending" groups="base.group_user"/>
<button name="stage_previous" string="Previous Stage" type="object" groups="base.group_user"
states="open,pending" icon="gtk-go-back" attrs="{'invisible': [('stage_id','=', False)]}"/>
<button name="stage_next" string="Next Stage" type="object" groups="base.group_user"
states="open,pending" icon="gtk-go-forward" attrs="{'invisible': [('stage_id','=', False)]}"/>
<button name="case_reset" string="Reset to Draft" type="object" groups="base.group_user"
states="cancel,done"/>
<button name="case_cancel" string="Cancel" type="object" groups="base.group_user"
@ -123,13 +117,12 @@
<field name="name"/>
<field name="date"/>
</group>
<group colspan="4" col="6">
<group colspan="4" col="4">
<field name="user_id"/>
<field name="section_id" widget="selection"/>
<field name="state" groups="base.group_no_one"/>
<newline/>
<field name="priority" groups="base.group_user"/>
<field name="section_id"/>
<field name="date_deadline"/>
<field name="state" groups="base.group_no_one"/>
</group>
<group colspan="4" col="4">
<notebook>

View File

@ -53,13 +53,12 @@ class crm_helpdesk(base_state, base_stage, osv.osv):
'date_deadline': fields.date('Deadline'),
'user_id': fields.many2one('res.users', 'Responsible'),
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
select=True, help='Sales team to which Case belongs to.\
Define Responsible user and Email account for mail gateway.'),
select=True, help='Responsible sales team. Define Responsible user and Email account for mail gateway.'),
'company_id': fields.many2one('res.company', 'Company'),
'date_closed': fields.datetime('Closed', readonly=True),
'partner_id': fields.many2one('res.partner', 'Partner'),
'email_cc': fields.text('Watchers Emails', size=252 , help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
'email_from': fields.char('Email', size=128, help="These people will receive email."),
'email_from': fields.char('Email', size=128, help="Destination email for email gateway"),
'date': fields.datetime('Date'),
'ref' : fields.reference('Reference', selection=crm._links_get, size=128),
'ref2' : fields.reference('Reference 2', selection=crm._links_get, size=128),

View File

@ -244,6 +244,7 @@ class crm_segmentation(osv.osv):
@param uid: the current users ID for security checks,
@param ids: List of crm segmentations IDs """
partner_obj = self.pool.get('res.partner')
categs = self.read(cr,uid,ids,['categ_id','exclusif','partner_id', \
'sales_purchase_active', 'profiling_active'])
for categ in categs:
@ -280,8 +281,10 @@ class crm_segmentation(osv.osv):
for pid in to_remove_list:
partners.remove(pid)
for partner_id in partners:
cr.execute('insert into res_partner_res_partner_category_rel (category_id,partner_id) values (%s,%s)', (categ['categ_id'][0],partner_id))
for partner in partner_obj.browse(cr, uid, partners):
category_ids = [categ_id.id for categ_id in partner.category_id]
if categ['categ_id'][0] not in category_ids:
cr.execute('insert into res_partner_res_partner_category_rel (category_id,partner_id) values (%s,%s)', (categ['categ_id'][0],partner.id))
self.write(cr, uid, [id], {'state':'not running', 'partner_id':0})
return True

View File

@ -0,0 +1,96 @@
# 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-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-11-06 15:26+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\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: 2012-11-07 04:38+0000\n"
"X-Generator: Launchpad (build 16232)\n"
#. module: crm_todo
#: model:ir.model,name:crm_todo.model_project_task
msgid "Task"
msgstr "Tarea"
#. module: crm_todo
#: view:crm.lead:0
msgid "Timebox"
msgstr "Periodo de tiempo"
#. module: crm_todo
#: view:crm.lead:0
msgid "For cancelling the task"
msgstr "Para cancelar la tarea"
#. module: crm_todo
#: constraint:project.task:0
msgid "Error ! Task end-date must be greater then task start-date"
msgstr ""
"¡ Error ! La fecha final de la tarea debe ser mayor que la fecha de inicio"
#. module: crm_todo
#: model:ir.model,name:crm_todo.model_crm_lead
msgid "crm.lead"
msgstr "crm.iniciativa"
#. module: crm_todo
#: view:crm.lead:0
msgid "Next"
msgstr "Siguiente"
#. module: crm_todo
#: model:ir.actions.act_window,name:crm_todo.crm_todo_action
#: model:ir.ui.menu,name:crm_todo.menu_crm_todo
msgid "My Tasks"
msgstr "Mis tareas"
#. module: crm_todo
#: view:crm.lead:0
#: field:crm.lead,task_ids:0
msgid "Tasks"
msgstr "Tareas"
#. module: crm_todo
#: view:crm.lead:0
msgid "Done"
msgstr "Realizado"
#. module: crm_todo
#: constraint:project.task:0
msgid "Error ! You cannot create recursive tasks."
msgstr "¡Error! No se pueden crear tareas recursivas."
#. module: crm_todo
#: view:crm.lead:0
msgid "Cancel"
msgstr "Cancelar"
#. module: crm_todo
#: view:crm.lead:0
msgid "Extra Info"
msgstr "Información extra"
#. module: crm_todo
#: field:project.task,lead_id:0
msgid "Lead / Opportunity"
msgstr "Iniciativa / Oportunidad"
#. module: crm_todo
#: view:crm.lead:0
msgid "For changing to done state"
msgstr "Para cambiar a estado 'Realizada'"
#. module: crm_todo
#: view:crm.lead:0
msgid "Previous"
msgstr "Anterior"

View File

@ -322,7 +322,6 @@
<record id="view_picking_withcarrier_in_form" model="ir.ui.view">
<field name="name">delivery.stock.picking_withcarrier.in.form.view</field>
<field name="type">form</field>
<field name="model">stock.picking.in</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-02-17 03:56+0000\n"
"Last-Translator: Jeff Wang <wjfonhand@hotmail.com>\n"
"PO-Revision-Date: 2012-11-02 01:52+0000\n"
"Last-Translator: Joshua Jan(SHINEIT) <popkar77@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-10-30 04:51+0000\n"
"X-Generator: Launchpad (build 16206)\n"
"X-Launchpad-Export-Date: 2012-11-03 05:03+0000\n"
"X-Generator: Launchpad (build 16218)\n"
#. module: delivery
#: report:sale.shipping:0
@ -332,13 +332,13 @@ msgstr "重量"
msgid ""
"Check this box if you want to manage delivery prices that depends on the "
"destination, the weight, the total of the order, etc."
msgstr "如果要根据目的地、重量、订单总价来管理运费,请勾选这里。"
msgstr "如果要根据目的地、重量、订单总价来管理运费,请勾选这里。"
#. module: delivery
#: help:delivery.carrier,normal_price:0
msgid ""
"Keep empty if the pricing depends on the advanced pricing per destination"
msgstr "如果价格基于每个目的地的固定价格,这里留空。"
msgstr "默认的运费的价格,如果根据目的地定价,这里留空。"
#. module: delivery
#: constraint:stock.move:0
@ -576,7 +576,7 @@ msgstr "一次性交货"
#. module: delivery
#: field:delivery.carrier,use_detailed_pricelist:0
msgid "Advanced Pricing per Destination"
msgstr "每个目的地的固定价格"
msgstr "根据目的地定价"
#. module: delivery
#: view:delivery.carrier:0

View File

@ -5,6 +5,19 @@ openerp.document = function (instance) {
this._super.apply(this, arguments);
this.sections.splice(1, 0, { 'name' : 'files', 'label' : _t('Attachment(s)'), });
this.items['files'] = [];
}
},
on_attachments_loaded: function(attachments) {
//to display number in name if more then one attachment which has same name.
var self = this;
_.chain(attachments.reverse())
.groupBy(function(attachment) { return attachment.name})
.each(function(attachment){
if(attachment.length > 1)
_.map(attachment, function(attachment, i){
attachment.name = _.str.sprintf(_t("%s (%s)"), attachment.name, i+1)
})
})
self._super(attachments);
},
});
};
};

View File

@ -15,7 +15,7 @@ openerp.edi.EdiView = openerp.web.Widget.extend({
this._super();
var self = this;
var param = {"db": self.db, "token": self.token};
return self.rpc('/edi/get_edi_document', param).then(this.on_document_loaded, this.on_document_failed);
return self.rpc('/edi/get_edi_document', param).done(this.on_document_loaded).fail(this.on_document_failed);
},
on_document_loaded: function(docs){
this.doc = docs[0];
@ -108,7 +108,7 @@ openerp.edi.EdiView = openerp.web.Widget.extend({
});
openerp.edi.edi_view = function (db, token) {
openerp.session.session_bind().then(function () {
openerp.session.session_bind().done(function () {
new openerp.edi.EdiView(null,db,token).appendTo($("body").addClass('openerp'));
});
}
@ -149,11 +149,11 @@ openerp.edi.EdiImport = openerp.web.Widget.extend({
},
do_import: function() {
this.rpc('/edi/import_edi_url', {url: this.url}).then(this.on_imported, this.on_imported_error);
this.rpc('/edi/import_edi_url', {url: this.url}).done(this.on_imported).fail(this.on_imported_error);
},
on_imported: function(response) {
if ('action' in response) {
this.rpc("/web/session/save_session_action", {the_action: response.action}).then(function(key) {
this.rpc("/web/session/save_session_action", {the_action: response.action}).done(function(key) {
window.location = "/#sa="+encodeURIComponent(key);
});
}
@ -188,7 +188,7 @@ openerp.edi.EdiImport = openerp.web.Widget.extend({
});
openerp.edi.edi_import = function (url) {
openerp.session.session_bind().then(function () {
openerp.session.session_bind().done(function () {
new openerp.edi.EdiImport(null,url).appendTo($("body").addClass('openerp'));
});
}

View File

@ -338,7 +338,7 @@ class event_registration(osv.osv):
'date_closed': fields.datetime('Attended Date', readonly=True),
'date_open': fields.datetime('Registration Date', readonly=True),
'reply_to': fields.related('event_id','reply_to',string='Reply-to Email', type='char', size=128, readonly=True,),
'log_ids': fields.one2many('mail.message', 'res_id', 'Logs', domain=[('email_from', '=', False),('model','=',_name)]),
'log_ids': fields.one2many('mail.message', 'res_id', 'Logs', domain=[('model','=',_name)]),
'event_end_date': fields.related('event_id','date_end', type='datetime', string="Event End Date", readonly=True),
'event_begin_date': fields.related('event_id', 'date_begin', type='datetime', string="Event Start Date", readonly=True),
'user_id': fields.many2one('res.users', 'User', states={'done': [('readonly', True)]}),

View File

@ -101,7 +101,7 @@
<form string="Events" version="7.0">
<header>
<button string="Confirm Event" name="button_confirm" states="draft" type="object" class="oe_highlight" groups="base.group_user"/>
<button string="Event Ended" name="button_done" states="confirm" type="object" class="oe_highlight" groups="base.group_user"/>
<button string="Finish Event" name="button_done" states="confirm" type="object" class="oe_highlight" groups="base.group_user"/>
<button string="Set To Draft" name="button_draft" states="cancel,done" type="object" groups="base.group_user"/>
<button string="Cancel Event" name="button_cancel" states="draft,confirm" type="object" groups="base.group_user"/>
<field name="state" widget="statusbar" statusbar_visible="draft,confirm,done"/>
@ -288,7 +288,7 @@
<t t-if="record.is_subscribed.raw_value">
<button type="object" name="unsubscribe_to_event" class="oe_unsubscribe_button ">
<span>Subscribed</span>
<span class="unsubscribe">Unsubscribe</span>
<span class="oe_unsubscribe">Unsubscribe</span>
</button>
</t>
</div>
@ -313,20 +313,6 @@
</field>
</record>
<!-- Event Graph view -->
<record model="ir.ui.view" id="view_event_graph">
<field name="name">Event Graph</field>
<field name="model">event.event</field>
<field name="arch" type="xml">
<graph string="Event by Registration" type="bar" orientation="horizontal">
<field name="name"/>
<field name="register_current" operator="+"/>
<field name="register_prospect" operator="+"/>
</graph>
</field>
</record>
<!-- Event Search View -->
<record model="ir.ui.view" id="view_event_search">
@ -362,7 +348,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">event.event</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,calendar,tree,form,graph</field>
<field name="view_mode">kanban,calendar,tree,form</field>
<field name="context">{"search_default_upcoming":1}</field>
<field name="search_view_id" ref="view_event_search"/>
<field name="help" type="html">
@ -524,7 +510,7 @@
<field name="model">event.registration</field>
<field name="arch" type="xml">
<search string="Event Registration">
<field name="name" string="Participant" filter_domain="['|','|','|',('name','ilike',self),('partner_id','ilike',self),('email','ilike',self),('origin','ilike',self)]"/>
<field name="name" string="Participant" filter_domain="['|','|',('name','ilike',self),('email','ilike',self),('origin','ilike',self)]"/>
<filter icon="terp-mail-message-new" string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
<separator/>
<filter icon="terp-check" string="New" name="draft" domain="[('state','=','draft')]" help="Registrations in unconfirmed state"/>
@ -533,6 +519,7 @@
<filter icon="terp-personal" string="My Registrations" help="My Registrations" domain="[('user_id','=',uid)]"/>
<field name="event_id"/>
<field name="user_id"/>
<field name="partner_id"/>
<group expand="0" string="Group By...">
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>

View File

@ -25,7 +25,7 @@ class res_partner(osv.osv):
_inherit = 'res.partner'
_columns = {
'speaker': fields.boolean('Speaker'),
'speaker': fields.boolean('Speaker', help="Check this box if this contact is a speaker."),
'event_ids': fields.one2many('event.event','main_speaker_id', readonly=True),
'event_registration_ids': fields.one2many('event.registration','partner_id', readonly=True),
}

View File

@ -23,7 +23,7 @@
<separator string="Connection with username and password" colspan="4"/>
<label string="Another approach is to create a user for OpenERP in Moodle. If you do so, make sure that this user has appropriate access rights." colspan="4"/>
<field name="moodle_username"/>
<field name="moodle_password"/>
<field name="moodle_password" password="True"/>
</group>
</form>
</field>

View File

@ -24,9 +24,9 @@
<field name="arch" type="xml">
<form string="Incoming Mail Server" version="7.0">
<header attrs="{'invisible' : [('type', '=', 'local')]}">
<button string="Test &amp; Confirm" type="object" name="button_confirm_login" states="draft" icon="gtk-apply"/>
<button string="Fetch Now" type="object" name="fetch_mail" states="done" icon="gtk-network"/>
<button string="Reset Confirmation" type="object" name="set_draft" icon="gtk-convert" states="done"/>
<button string="Test &amp; Confirm" type="object" name="button_confirm_login" states="draft"/>
<button string="Fetch Now" type="object" name="fetch_mail" states="done"/>
<button string="Reset Confirmation" type="object" name="set_draft" states="done"/>
<field name="state" widget="statusbar"/>
</header>
<sheet>

View File

@ -18,9 +18,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import stock_planning
import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
import fleet

View File

@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name' : 'Fleet Management',
'version' : '0.1',
'author' : 'OpenERP S.A.',
'category': 'Managing vehicles and contracts',
'website' : 'http://www.openerp.com',
'summary' : 'Vehicle, leasing, insurances, costs',
'description' : """
Vehicle, leasing, insurances, cost
==================================
With this module, OpenERP helps you managing all your vehicles, the
contracts associated to those vehicle as well as services, fuel log
entries, costs and many other features necessary to the management
of your fleet of vehicle(s)
Main Features
-------------
* Add vehicles to your fleet
* Manage contracts for vehicles
* Reminder when a contract reach its expiration date
* Add services, fuel log entry, odometer values for all vehicles
* Show all costs associated to a vehicle or to a type of service
* Analysis graph for costs
""",
'depends' : [
'base',
'mail',
'board'
],
'data' : [
'fleet_view.xml',
'fleet_data.xml',
'fleet_board_view.xml',
],
'update_xml' : ['security/ir.model.access.csv'],
'demo': ['fleet_cars.xml','fleet_demo.xml'],
'installable' : True,
'application' : True,
}

818
addons/fleet/fleet.py Normal file
View File

@ -0,0 +1,818 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv, fields
import time
import datetime
import tools
from osv.orm import except_orm
from tools.translate import _
from dateutil.relativedelta import relativedelta
def str_to_datetime(strdate):
return datetime.datetime.strptime(strdate, tools.DEFAULT_SERVER_DATE_FORMAT)
class fleet_vehicle_cost(osv.Model):
_name = 'fleet.vehicle.cost'
_description = 'Cost related to a vehicle'
_order = 'date desc, vehicle_id asc'
def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
res = dict.fromkeys(ids, False)
for record in self.browse(cr,uid,ids,context=context):
if record.odometer_id:
res[record.id] = record.odometer_id.value
return res
def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
if not value:
raise except_orm(_('Operation not allowed!'), _('Emptying the odometer value of a vehicle is not allowed.'))
date = self.browse(cr, uid, id, context=context).date
if not(date):
date = fields.date.context_today(self, cr, uid, context=context)
vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
data = {'value': value, 'date': date, 'vehicle_id': vehicle_id.id}
odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
return self.write(cr, uid, id, {'odometer_id': odometer_id}, context=context)
def _year_get_fnc(self, cr, uid, ids, name, unknow_none, context=None):
res = {}
for record in self.browse(cr, uid, ids, context=context):
res[record.id] = str(time.strptime(record.date, tools.DEFAULT_SERVER_DATE_FORMAT).tm_year)
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.name:
name += ' / '+ record.cost_subtype.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),
'vehicle_id': fields.many2one('fleet.vehicle', 'Vehicle', required=True, help='Vehicle concerned by this log'),
'cost_subtype': fields.many2one('fleet.service.type', 'Type', help='Cost type purchased with this cost'),
'amount': fields.float('Total Price'),
'cost_type': fields.selection([('contract', 'Contract'), ('services','Services'), ('fuel','Fuel'), ('other','Other')], 'Category of the cost', help='For internal purpose only', required=True),
'parent_id': fields.many2one('fleet.vehicle.cost', 'Parent', help='Parent cost to this current cost'),
'cost_ids': fields.one2many('fleet.vehicle.cost', 'parent_id', 'Included Services'),
'odometer_id': fields.many2one('fleet.vehicle.odometer', 'Odometer', help='Odometer measure of the vehicle at the moment of this log'),
'odometer': fields.function(_get_odometer, fnct_inv=_set_odometer, type='float', string='Odometer Value', help='Odometer measure of the vehicle at the moment of this log'),
'odometer_unit': fields.related('vehicle_id', 'odometer_unit', type="char", string="Unit", readonly=True),
'date' :fields.date('Date',help='Date when the cost has been executed'),
'contract_id': fields.many2one('fleet.vehicle.log.contract', 'Contract', help='Contract attached to this cost'),
'auto_generated': fields.boolean('Automatically Generated', readonly=True, required=True),
'year': fields.function(_year_get_fnc, type="char", string='Year', store=True),
}
_defaults ={
'cost_type': 'other',
}
def create(self, cr, uid, data, context=None):
#make sure that the data are consistent with values of parent and contract records given
if 'parent_id' in data and data['parent_id']:
parent = self.browse(cr, uid, data['parent_id'], context=context)
data['vehicle_id'] = parent.vehicle_id.id
data['date'] = parent.date
data['cost_type'] = parent.cost_type
if 'contract_id' in data and data['contract_id']:
contract = self.pool.get('fleet.vehicle.log.contract').browse(cr, uid, data['contract_id'], context=context)
data['vehicle_id'] = contract.vehicle_id.id
data['cost_subtype'] = contract.cost_subtype.id
data['cost_type'] = contract.cost_type
if 'odometer' in data and not data['odometer']:
#if received value for odometer is 0, then remove it from the data as it would result to the creation of a
#odometer log with 0, which is to be avoided
del(data['odometer'])
return super(fleet_vehicle_cost, self).create(cr, uid, data, context=context)
class fleet_vehicle_tag(osv.Model):
_name = 'fleet.vehicle.tag'
_columns = {
'name': fields.char('Name', required=True, translate=True),
}
class fleet_vehicle_state(osv.Model):
_name = 'fleet.vehicle.state'
_order = 'sequence asc'
_columns = {
'name': fields.char('Name', required=True),
'sequence': fields.integer('Order', help="Used to order the note stages")
}
_sql_constraints = [('fleet_state_name_unique','unique(name)', 'State name already exists')]
class fleet_vehicle_model(osv.Model):
def _model_name_get_fnc(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for record in self.browse(cr, uid, ids, context=context):
name = record.modelname
if record.brand.name:
name = record.brand.name + ' / ' + name
res[record.id] = name
return res
def on_change_brand(self, cr, uid, ids, model_id, context=None):
if not model_id:
return {'value': {'image_medium': False}}
brand = self.pool.get('fleet.vehicle.model.brand').browse(cr, uid, model_id, context=context)
return {
'value': {
'image_medium': brand.image,
}
}
_name = 'fleet.vehicle.model'
_description = 'Model of a vehicle'
_order = 'name asc'
_columns = {
'name': fields.function(_model_name_get_fnc, type="char", string='Name', store=True),
'modelname': fields.char('Model name', size=32, required=True),
'brand': fields.many2one('fleet.vehicle.model.brand', 'Model Brand', required=True, help='Brand of the vehicle'),
'vendors': fields.many2many('res.partner', 'fleet_vehicle_model_vendors', 'model_id', 'partner_id', string='Vendors'),
'image': fields.related('brand', 'image', type="binary", string="Logo"),
'image_medium': fields.related('brand', 'image_medium', type="binary", string="Logo"),
'image_small': fields.related('brand', 'image_small', type="binary", string="Logo"),
}
class fleet_vehicle_model_brand(osv.Model):
_name = 'fleet.vehicle.model.brand'
_description = 'Brand model of the vehicle'
_order = 'name asc'
def _get_image(self, cr, uid, ids, name, args, context=None):
result = dict.fromkeys(ids, False)
for obj in self.browse(cr, uid, ids, context=context):
result[obj.id] = tools.image_get_resized_images(obj.image)
return result
def _set_image(self, cr, uid, id, name, value, args, context=None):
return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
_columns = {
'name': fields.char('Brand Name', size=64, required=True),
'image': fields.binary("Logo",
help="This field holds the image used as logo for the brand, limited to 1024x1024px."),
'image_medium': fields.function(_get_image, fnct_inv=_set_image,
string="Medium-sized photo", type="binary", multi="_get_image",
store = {
'fleet.vehicle.model.brand': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
},
help="Medium-sized logo of the brand. It is automatically "\
"resized as a 128x128px image, with aspect ratio preserved. "\
"Use this field in form views or some kanban views."),
'image_small': fields.function(_get_image, fnct_inv=_set_image,
string="Smal-sized photo", type="binary", multi="_get_image",
store = {
'fleet.vehicle.model.brand': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
},
help="Small-sized photo of the brand. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required."),
}
class fleet_vehicle(osv.Model):
_inherit = 'mail.thread'
def _vehicle_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
res = {}
for record in self.browse(cr, uid, ids, context=context):
res[record.id] = record.model_id.brand.name + '/' + record.model_id.modelname + ' / ' + record.license_plate
return res
def return_action_to_open(self, cr, uid, ids, context=None):
""" This opens the xml view specified in xml_id for the current vehicle """
if context is None:
context = {}
if context.get('xml_id'):
res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet', context['xml_id'], context=context)
res['context'] = context
res['context'].update({'default_vehicle_id': ids[0]})
res['domain'] = [('vehicle_id','=', ids[0])]
return res
return False
def act_show_log_cost(self, cr, uid, ids, context=None):
""" This opens log view to view and add new log for this vehicle, groupby default to only show effective costs
@return: the costs log view
"""
if context is None:
context = {}
res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_costs_act', context=context)
res['context'] = context
res['context'].update({
'default_vehicle_id': ids[0],
'search_default_parent_false': True
})
res['domain'] = [('vehicle_id','=', ids[0])]
return res
def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
res = dict.fromkeys(ids, 0)
for record in self.browse(cr,uid,ids,context=context):
ids = self.pool.get('fleet.vehicle.odometer').search(cr, uid, [('vehicle_id', '=', record.id)], limit=1, order='value desc')
if len(ids) > 0:
res[record.id] = self.pool.get('fleet.vehicle.odometer').browse(cr, uid, ids[0], context=context).value
return res
def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
if value:
date = fields.date.context_today(self, cr, uid, context=context)
data = {'value': value, 'date': date, 'vehicle_id': id}
return self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
def _search_get_overdue_contract_reminder(self, cr, uid, obj, name, args, context):
res = []
today = fields.date.today(self, cr, uid, context=context)
for field, operator, value in args:
assert operator in ('=', '!=', '<>') and value in (True, False), 'Operation not supported'
if (operator == '=' and value == True) or (operator in ('<>', '!=') and value == False):
search_operator = 'in'
else:
search_operator = 'not in'
today = fields.date.context_today(self, cr, uid, context=context)
cr.execute('select cost.vehicle_id, count(contract.id) as contract_number FROM fleet_vehicle_cost cost left join fleet_vehicle_log_contract contract on contract.cost_id = cost.id WHERE contract.expiration_date is not null AND contract.expiration_date < %s AND contract.state IN (\'open\', \'toclose\') GROUP BY cost.vehicle_id', (today,))
res_ids = [x[0] for x in cr.fetchall()]
res.append(('id', search_operator, res_ids))
return res
def _search_contract_renewal_due_soon(self, cr, uid, obj, name, args, context):
res = []
for field, operator, value in args:
assert operator in ('=', '!=', '<>') and value in (True, False), 'Operation not supported'
if (operator == '=' and value == True) or (operator in ('<>', '!=') and value == False):
search_operator = 'in'
else:
search_operator = 'not in'
today = fields.date.context_today(self, cr, uid, context=context)
datetime_today = datetime.datetime.strptime(today, tools.DEFAULT_SERVER_DATE_FORMAT)
limit_date = str((datetime_today + relativedelta(days=+15)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT))
cr.execute('select cost.vehicle_id, count(contract.id) as contract_number FROM fleet_vehicle_cost cost left join fleet_vehicle_log_contract contract on contract.cost_id = cost.id WHERE contract.expiration_date is not null AND contract.expiration_date > %s AND contract.expiration_date < %s AND contract.state IN (\'open\', \'toclose\') GROUP BY cost.vehicle_id', (today, limit_date))
res_ids = [x[0] for x in cr.fetchall()]
res.append(('id', search_operator, res_ids))
return res
def _get_contract_reminder_fnc(self, cr, uid, ids, field_names, unknow_none, context=None):
res= {}
for record in self.browse(cr, uid, ids, context=context):
overdue = False
due_soon = False
total = 0
name = ''
for element in record.log_contracts:
if element.state in ('open', 'toclose') and element.expiration_date:
current_date_str = fields.date.context_today(self, cr, uid, context=context)
due_time_str = element.expiration_date
current_date = str_to_datetime(current_date_str)
due_time = str_to_datetime(due_time_str)
diff_time = (due_time-current_date).days
if diff_time < 0:
overdue = True
total += 1
if diff_time < 15 and diff_time >= 0:
due_soon = True;
total += 1
if overdue or due_soon:
ids = self.pool.get('fleet.vehicle.log.contract').search(cr,uid,[('vehicle_id', '=', record.id), ('state', 'in', ('open', 'toclose'))], limit=1, order='expiration_date asc')
if len(ids) > 0:
#we display only the name of the oldest overdue/due soon contract
name=(self.pool.get('fleet.vehicle.log.contract').browse(cr, uid, ids[0], context=context).cost_subtype.name)
res[record.id] = {
'contract_renewal_overdue': overdue,
'contract_renewal_due_soon': due_soon,
'contract_renewal_total': (total - 1), #we remove 1 from the real total for display purposes
'contract_renewal_name': name,
}
return res
def _get_default_state(self, cr, uid, context):
try:
model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'vehicle_state_active')
except ValueError:
model_id = False
return model_id
_name = 'fleet.vehicle'
_description = 'Information on a vehicle'
_order= 'license_plate asc'
_columns = {
'name': fields.function(_vehicle_name_get_fnc, type="char", string='Name', store=True),
'company_id': fields.many2one('res.company', 'Company'),
'license_plate': fields.char('License Plate', size=32, required=True, help='License plate number of the vehicle (ie: plate number for a car)'),
'vin_sn': fields.char('Chassis Number', size=32, help='Unique number written on the vehicle motor (VIN/SN number)'),
'driver': fields.many2one('res.partner', 'Driver', help='Driver of the vehicle'),
'model_id': fields.many2one('fleet.vehicle.model', 'Model', required=True, help='Model of the vehicle'),
'log_fuel': fields.one2many('fleet.vehicle.log.fuel', 'vehicle_id', 'Fuel Logs'),
'log_services': fields.one2many('fleet.vehicle.log.services', 'vehicle_id', 'Services Logs'),
'log_contracts': fields.one2many('fleet.vehicle.log.contract', 'vehicle_id', 'Contracts'),
'acquisition_date': fields.date('Acquisition Date', required=False, help='Date when the vehicle has been bought'),
'color': fields.char('Color', size=32, help='Color of the vehicle'),
'state': fields.many2one('fleet.vehicle.state', 'State', help='Current state of the vehicle', ondelete="set null"),
'location': fields.char('Location', size=128, help='Location of the vehicle (garage, ...)'),
'seats': fields.integer('Seats Number', help='Number of seats of the vehicle'),
'doors': fields.integer('Doors Number', help='Number of doors of the vehicle'),
'tag_ids' :fields.many2many('fleet.vehicle.tag', 'fleet_vehicle_vehicle_tag_rel', 'vehicle_tag_id','tag_id', 'Tags'),
'odometer': fields.function(_get_odometer, fnct_inv=_set_odometer, type='float', string='Odometer Value', help='Odometer measure of the vehicle at the moment of this log'),
'odometer_unit': fields.selection([('kilometers', 'Kilometers'),('miles','Miles')], 'Odometer Unit', help='Unit of the odometer ',required=True),
'transmission': fields.selection([('manual', 'Manual'), ('automatic', 'Automatic')], 'Transmission', help='Transmission Used by the vehicle'),
'fuel_type': fields.selection([('gasoline', 'Gasoline'), ('diesel', 'Diesel'), ('electric', 'Electric'), ('hybrid', 'Hybrid')], 'Fuel Type', help='Fuel Used by the vehicle'),
'horsepower': fields.integer('Horsepower'),
'horsepower_tax': fields.float('Horsepower Taxation'),
'power': fields.integer('Power (kW)', help='Power in kW of the vehicle'),
'co2': fields.float('CO2 Emissions', help='CO2 emissions of the vehicle'),
'image': fields.related('model_id', 'image', type="binary", string="Logo"),
'image_medium': fields.related('model_id', 'image_medium', type="binary", string="Logo"),
'image_small': fields.related('model_id', 'image_small', type="binary", string="Logo"),
'contract_renewal_due_soon': fields.function(_get_contract_reminder_fnc, fnct_search=_search_contract_renewal_due_soon, type="boolean", string='Has Contracts to renew', multi='contract_info'),
'contract_renewal_overdue': fields.function(_get_contract_reminder_fnc, fnct_search=_search_get_overdue_contract_reminder, type="boolean", string='Has Contracts Overdued', multi='contract_info'),
'contract_renewal_name': fields.function(_get_contract_reminder_fnc, type="text", string='Name of contract to renew soon', multi='contract_info'),
'contract_renewal_total': fields.function(_get_contract_reminder_fnc, type="integer", string='Total of contracts due or overdue minus one', multi='contract_info'),
'car_value': fields.float('Car Value', help='Value of the bought vehicle'),
}
_defaults = {
'doors': 5,
'odometer_unit': 'kilometers',
'state': _get_default_state,
}
def copy(self, cr, uid, id, default=None, context=None):
if not default:
default = {}
default.update({
'log_fuel':[],
'log_contracts':[],
'log_services':[],
'tag_ids':[],
'vin_sn':'',
})
return super(fleet_vehicle, self).copy(cr, uid, id, default, context=context)
def on_change_model(self, cr, uid, ids, model_id, context=None):
if not model_id:
return {}
model = self.pool.get('fleet.vehicle.model').browse(cr, uid, model_id, context=context)
return {
'value': {
'image_medium': model.image,
}
}
def create(self, cr, uid, data, context=None):
vehicle_id = super(fleet_vehicle, self).create(cr, uid, data, context=context)
vehicle = self.browse(cr, uid, vehicle_id, context=context)
self.message_post(cr, uid, [vehicle_id], body=_('Vehicle %s has been added to the fleet!') % (vehicle.license_plate), context=context)
return vehicle_id
def write(self, cr, uid, ids, vals, context=None):
"""
This function write an entry in the openchatter whenever we change important information
on the vehicle like the model, the drive, the state of the vehicle or its license plate
"""
for vehicle in self.browse(cr, uid, ids, context):
changes = []
if 'model_id' in vals and vehicle.model_id.id != vals['model_id']:
value = self.pool.get('fleet.vehicle.model').browse(cr,uid,vals['model_id'],context=context).name
oldmodel = vehicle.model_id.name or _('None')
changes.append(_("Model: from '%s' to '%s'") %(oldmodel, value))
if 'driver' in vals and vehicle.driver.id != vals['driver']:
value = self.pool.get('res.partner').browse(cr,uid,vals['driver'],context=context).name
olddriver = (vehicle.driver.name) or _('None')
changes.append(_("Driver: from '%s' to '%s'") %(olddriver, value))
if 'state' in vals and vehicle.state.id != vals['state']:
value = self.pool.get('fleet.vehicle.state').browse(cr,uid,vals['state'],context=context).name
oldstate = vehicle.state.name or _('None')
changes.append(_("State: from '%s' to '%s'") %(oldstate, value))
if 'license_plate' in vals and vehicle.license_plate != vals['license_plate']:
old_license_plate = vehicle.license_plate or _('None')
changes.append(_("License Plate: from '%s' to '%s'") %(old_license_plate, vals['license_plate']))
if len(changes) > 0:
self.message_post(cr, uid, [vehicle.id], body=", ".join(changes), context=context)
vehicle_id = super(fleet_vehicle,self).write(cr, uid, ids, vals, context)
return True
class fleet_vehicle_odometer(osv.Model):
_name='fleet.vehicle.odometer'
_description='Odometer log for a vehicle'
_order='date desc'
def _vehicle_log_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
res = {}
for record in self.browse(cr, uid, ids, context=context):
name = record.vehicle_id.name
if record.date:
name = name+ ' / '+ str(record.date)
res[record.id] = name
return res
def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
if not vehicle_id:
return {}
odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
return {
'value': {
'unit': odometer_unit,
}
}
_columns = {
'name': fields.function(_vehicle_log_name_get_fnc, type="char", string='Name', store=True),
'date': fields.date('Date'),
'value': fields.float('Odometer Value', group_operator="max"),
'vehicle_id': fields.many2one('fleet.vehicle', 'Vehicle', required=True),
'unit': fields.related('vehicle_id', 'odometer_unit', type="char", string="Unit", readonly=True),
}
_defaults = {
'date': fields.date.context_today,
}
class fleet_vehicle_log_fuel(osv.Model):
def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
if not vehicle_id:
return {}
odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
return {
'value': {
'odometer_unit': odometer_unit,
}
}
def on_change_liter(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
#need to cast in float because the value receveid from web client maybe an integer (Javascript and JSON do not
#make any difference between 3.0 and 3). This cause a problem if you encode, for example, 2 liters at 1.5 per
#liter => total is computed as 3.0, then trigger an onchange that recomputes price_per_liter as 3/2=1 (instead
#of 3.0/2=1.5)
liter = float(liter)
price_per_liter = float(price_per_liter)
amount = float(amount)
if liter > 0 and price_per_liter > 0:
return {'value' : {'amount' : liter * price_per_liter,}}
elif liter > 0 and amount > 0:
return {'value' : {'price_per_liter' : amount / liter,}}
elif price_per_liter > 0 and amount > 0:
return {'value' : {'liter' : amount / price_per_liter,}}
else :
return {}
def on_change_price_per_liter(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
#need to cast in float because the value receveid from web client maybe an integer (Javascript and JSON do not
#make any difference between 3.0 and 3). This cause a problem if you encode, for example, 2 liters at 1.5 per
#liter => total is computed as 3.0, then trigger an onchange that recomputes price_per_liter as 3/2=1 (instead
#of 3.0/2=1.5)
liter = float(liter)
price_per_liter = float(price_per_liter)
amount = float(amount)
if price_per_liter > 0 and liter > 0:
return {'value' : {'amount' : liter * price_per_liter,}}
elif price_per_liter > 0 and amount > 0:
return {'value' : {'liter' : amount / price_per_liter,}}
elif liter > 0 and amount > 0:
return {'value' : {'price_per_liter' : amount / liter,}}
else :
return {}
def on_change_amount(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
#need to cast in float because the value receveid from web client maybe an integer (Javascript and JSON do not
#make any difference between 3.0 and 3). This cause a problem if you encode, for example, 2 liters at 1.5 per
#liter => total is computed as 3.0, then trigger an onchange that recomputes price_per_liter as 3/2=1 (instead
#of 3.0/2=1.5)
liter = float(liter)
price_per_liter = float(price_per_liter)
amount = float(amount)
if amount > 0 and liter > 0:
return {'value': {'price_per_liter': amount / liter,}}
elif amount > 0 and price_per_liter > 0:
return {'value': {'liter': amount / price_per_liter,}}
elif liter > 0 and price_per_liter > 0:
return {'value': {'amount': liter * price_per_liter,}}
return {}
def _get_default_service_type(self, cr, uid, context):
try:
model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'type_service_refueling')
except ValueError:
model_id = False
return model_id
_name = 'fleet.vehicle.log.fuel'
_description = 'Fuel log for vehicles'
_inherits = {'fleet.vehicle.cost': 'cost_id'}
_columns = {
'liter': fields.float('Liter'),
'price_per_liter': fields.float('Price Per Liter'),
'purchaser_id': fields.many2one('res.partner', 'Purchaser', domain="['|',('customer','=',True),('employee','=',True)]"),
'inv_ref': fields.char('Invoice Reference', size=64),
'vendor_id': fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
'notes': fields.text('Notes'),
'cost_amount': fields.related('cost_id', 'amount', string='Amount', type='float', store=True), #we need to keep this field as a related with store=True because the graph view doesn't support (1) to address fields from inherited table and (2) fields that aren't stored in database
}
_defaults = {
'purchaser_id': lambda self, cr, uid, ctx: uid,
'date': fields.date.context_today,
'cost_subtype': _get_default_service_type,
'cost_type': 'fuel',
}
class fleet_vehicle_log_services(osv.Model):
def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
if not vehicle_id:
return {}
odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
return {
'value': {
'odometer_unit': odometer_unit,
}
}
def _get_default_service_type(self, cr, uid, context):
try:
model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'type_service_service_8')
except ValueError:
model_id = False
return model_id
_inherits = {'fleet.vehicle.cost': 'cost_id'}
_name = 'fleet.vehicle.log.services'
_description = 'Services for vehicles'
_columns = {
'purchaser_id': fields.many2one('res.partner', 'Purchaser', domain="['|',('customer','=',True),('employee','=',True)]"),
'inv_ref': fields.char('Invoice Reference', size=64),
'vendor_id': fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
'cost_amount': fields.related('cost_id', 'amount', string='Amount', type='float', store=True), #we need to keep this field as a related with store=True because the graph view doesn't support (1) to address fields from inherited table and (2) fields that aren't stored in database
'notes': fields.text('Notes'),
}
_defaults = {
'purchaser_id': lambda self, cr, uid, ctx: uid,
'date': fields.date.context_today,
'cost_subtype': _get_default_service_type,
'cost_type': 'services'
}
class fleet_service_type(osv.Model):
_name = 'fleet.service.type'
_description = 'Type of services available on a vehicle'
_columns = {
'name': fields.char('Name', required=True, translate=True),
'category': fields.selection([('contract', 'Contract'), ('service', 'Service'), ('both', 'Both')], 'Category', required=True, help='Choose wheter the service refer to contracts, vehicle services or both'),
}
class fleet_vehicle_log_contract(osv.Model):
def scheduler_manage_auto_costs(self, cr, uid, context=None):
#This method is called by a cron task
#It creates costs for contracts having the "recurring cost" field setted, depending on their frequency
#For example, if a contract has a reccuring cost of 200 with a weekly frequency, this method creates a cost of 200 on the first day of each week, from the date of the last recurring costs in the database to today
#If the contract has not yet any recurring costs in the database, the method generates the recurring costs from the start_date to today
#The created costs are associated to a contract thanks to the many2one field contract_id
#If the contract has no start_date, no cost will be created, even if the contract has recurring costs
vehicle_cost_obj = self.pool.get('fleet.vehicle.cost')
d = datetime.datetime.strptime(fields.date.context_today(self, cr, uid, context=context), tools.DEFAULT_SERVER_DATE_FORMAT).date()
contract_ids = self.pool.get('fleet.vehicle.log.contract').search(cr, uid, [('state','!=','closed')], offset=0, limit=None, order=None,context=None, count=False)
deltas = {'yearly': relativedelta(years=+1), 'monthly': relativedelta(months=+1), 'weekly': relativedelta(weeks=+1), 'daily': relativedelta(days=+1)}
for contract in self.pool.get('fleet.vehicle.log.contract').browse(cr, uid, contract_ids, context=context):
if not contract.start_date or contract.cost_frequency == 'no':
continue
found = False
last_cost_date = contract.start_date
if contract.generated_cost_ids:
last_autogenerated_cost_id = vehicle_cost_obj.search(cr, uid, ['&', ('contract_id','=',contract.id), ('auto_generated','=',True)], offset=0, limit=1, order='date desc',context=context, count=False)
if last_autogenerated_cost_id:
found = True
last_cost_date = vehicle_cost_obj.browse(cr, uid, last_autogenerated_cost_id[0], context=context).date
startdate = datetime.datetime.strptime(last_cost_date, tools.DEFAULT_SERVER_DATE_FORMAT).date()
if found:
startdate += deltas.get(contract.cost_frequency)
while (startdate < d) & (startdate < datetime.datetime.strptime(contract.expiration_date, tools.DEFAULT_SERVER_DATE_FORMAT).date()):
data = {
'amount': contract.cost_generated,
'date': startdate.strftime(tools.DEFAULT_SERVER_DATE_FORMAT),
'vehicle_id': contract.vehicle_id.id,
'cost_subtype': contract.cost_subtype.id,
'contract_id': contract.id,
'auto_generated': True
}
cost_id = self.pool.get('fleet.vehicle.cost').create(cr, uid, data, context=context)
startdate += deltas.get(contract.cost_frequency)
return True
def scheduler_manage_contract_expiration(self, cr, uid, context=None):
#This method is called by a cron task
#It manages the state of a contract, possibly by posting a message on the vehicle concerned and updating its status
datetime_today = datetime.datetime.strptime(fields.date.context_today(self, cr, uid, context=context), tools.DEFAULT_SERVER_DATE_FORMAT)
limit_date = (datetime_today + relativedelta(days=+15)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
ids = self.search(cr, uid, ['&', ('state', '=', 'open'), ('expiration_date', '<', limit_date)], offset=0, limit=None, order=None, context=context, count=False)
res = {}
for contract in self.browse(cr, uid, ids, context=context):
if contract.vehicle_id.id in res:
res[contract.vehicle_id.id] += 1
else:
res[contract.vehicle_id.id] = 1
for vehicle, value in res.items():
self.pool.get('fleet.vehicle').message_post(cr, uid, vehicle, body=_('%s contract(s) need(s) to be renewed and/or closed!') % (str(value)), context=context)
return self.write(cr, uid, ids, {'state': 'toclose'}, context=context)
def run_scheduler(self, cr, uid, context=None):
self.scheduler_manage_auto_costs(cr, uid, context=context)
self.scheduler_manage_contract_expiration(cr, uid, context=context)
return True
def _vehicle_contract_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
res = {}
for record in self.browse(cr, uid, ids, context=context):
name = record.vehicle_id.name
if record.cost_subtype.name:
name += ' / '+ record.cost_subtype.name
if record.date:
name += ' / '+ record.date
res[record.id] = name
return res
def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
if not vehicle_id:
return {}
odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
return {
'value': {
'odometer_unit': odometer_unit,
}
}
def compute_next_year_date(self, strdate):
oneyear = datetime.timedelta(days=365)
curdate = str_to_datetime(strdate)
return datetime.datetime.strftime(curdate + oneyear, tools.DEFAULT_SERVER_DATE_FORMAT)
def on_change_start_date(self, cr, uid, ids, strdate, enddate, context=None):
if (strdate):
return {'value': {'expiration_date': self.compute_next_year_date(strdate),}}
return {}
def get_days_left(self, cr, uid, ids, prop, unknow_none, context=None):
"""return a dict with as value for each contract an integer
if contract is in an open state and is overdue, return 0
if contract is in a closed state, return -1
otherwise return the number of days before the contract expires
"""
res = {}
for record in self.browse(cr, uid, ids, context=context):
if (record.expiration_date and (record.state == 'open' or record.state == 'toclose')):
today = str_to_datetime(time.strftime(tools.DEFAULT_SERVER_DATE_FORMAT))
renew_date = str_to_datetime(record.expiration_date)
diff_time = (renew_date-today).days
res[record.id] = diff_time > 0 and diff_time or 0
else:
res[record.id] = -1
return res
def act_renew_contract(self, cr, uid, ids, context=None):
assert len(ids) == 1, "This operation should only be done for 1 single contract at a time, as it it suppose to open a window as result"
for element in self.browse(cr, uid, ids, context=context):
#compute end date
startdate = str_to_datetime(element.start_date)
enddate = str_to_datetime(element.expiration_date)
diffdate = (enddate - startdate)
default = {
'date': fields.date.context_today(self, cr, uid, context=context),
'start_date': datetime.datetime.strftime(str_to_datetime(element.expiration_date) + datetime.timedelta(days=1), tools.DEFAULT_SERVER_DATE_FORMAT),
'expiration_date': datetime.datetime.strftime(enddate + diffdate, tools.DEFAULT_SERVER_DATE_FORMAT),
}
newid = super(fleet_vehicle_log_contract, self).copy(cr, uid, [element.id], default, context=context)
mod, modid = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'fleet_vehicle_log_contract_form')
return {
'name':_("Renew Contract"),
'view_mode': 'form',
'view_id': modid,
'view_type': 'tree,form',
'res_model': 'fleet.vehicle.log.contract',
'type': 'ir.actions.act_window',
'nodestroy': True,
'domain': '[]',
'res_id': newid,
'context': {'active_id':newid},
}
def _get_default_contract_type(self, cr, uid, context=None):
try:
model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'type_contract_leasing')
except ValueError:
model_id = False
return model_id
def on_change_indic_cost(self, cr, uid, ids, cost_ids, context=None):
totalsum = 0.0
for element in cost_ids:
if element and len(element) == 3 and element[2] is not False:
totalsum += element[2].get('amount', 0.0)
return {
'value': {
'sum_cost': totalsum,
}
}
def _get_sum_cost(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for contract in self.browse(cr, uid, ids, context=context):
totalsum = 0
for cost in contract.cost_ids:
totalsum += cost.amount
res[contract.id] = totalsum
return res
_inherits = {'fleet.vehicle.cost': 'cost_id'}
_name = 'fleet.vehicle.log.contract'
_description = 'Contract information on a vehicle'
_order='state desc,expiration_date'
_columns = {
'name': fields.function(_vehicle_contract_name_get_fnc, type="text", string='Name', store=True),
'start_date': fields.date('Contract Start Date', help='Date when the coverage of the contract begins'),
'expiration_date': fields.date('Contract Expiration Date', help='Date when the coverage of the contract expirates (by default, one year after begin date)'),
'days_left': fields.function(get_days_left, type='integer', string='Warning Date'),
'insurer_id' :fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
'purchaser_id': fields.many2one('res.partner', 'Contractor', domain="['|', ('customer','=',True), ('employee','=',True)]",help='Person to which the contract is signed for'),
'ins_ref': fields.char('Contract Reference', size=64),
'state': fields.selection([('open', 'In Progress'), ('toclose','To Close'), ('closed', 'Terminated')], 'Status', readonly=True, help='Choose wheter the contract is still valid or not'),
'notes': fields.text('Terms and Conditions', help='Write here all supplementary informations relative to this contract'),
'cost_generated': fields.float('Recurring Cost Amount', help="Costs paid at regular intervals, depending on the cost frequency. If the cost frequency is set to unique, the cost will be logged at the start date"),
'cost_frequency': fields.selection([('no','No'), ('daily', 'Daily'), ('weekly','Weekly'), ('monthly','Monthly'), ('yearly','Yearly')], 'Recurring Cost Frequency', help='Frequency of the recuring cost', required=True),
'generated_cost_ids': fields.one2many('fleet.vehicle.cost', 'contract_id', 'Generated Costs', ondelete='cascade'),
'sum_cost': fields.function(_get_sum_cost, type='float', string='Indicative Costs Total'),
'cost_amount': fields.related('cost_id', 'amount', string='Amount', type='float', store=True), #we need to keep this field as a related with store=True because the graph view doesn't support (1) to address fields from inherited table and (2) fields that aren't stored in database
}
_defaults = {
'purchaser_id': lambda self, cr, uid, ctx: uid,
'date': fields.date.context_today,
'start_date': fields.date.context_today,
'state':'open',
'expiration_date': lambda self, cr, uid, ctx: self.compute_next_year_date(fields.date.context_today(self, cr, uid, context=ctx)),
'cost_frequency': 'no',
'cost_subtype': _get_default_contract_type,
'cost_type': 'contract',
}
def copy(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
today = fields.date.context_today(self, cr, uid, context=context)
default['date'] = today
default['start_date'] = today
default['expiration_date'] = self.compute_next_year_date(today)
default['ins_ref'] = ''
default['state'] = 'open'
default['notes'] = ''
return super(fleet_vehicle_log_contract, self).copy(cr, uid, id, default, context=context)
def contract_close(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state': 'closed'}, context=context)
def contract_open(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state': 'open'}, context=context)
class fleet_contract_state(osv.Model):
_name = 'fleet.contract.state'
_description = 'Contains the different possible status of a leasing contract'
_columns = {
'name':fields.char('Contract Status', size=64, required=True),
}

View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.actions.act_window" id="action_fleet_vehicle_log_fuel_graph">
<field name="name">Fuel Costs by Month</field>
<field name="res_model">fleet.vehicle.cost</field>
<field name="view_id" ref="fleet_vehicle_costs_graph"></field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="domain">['&amp;',('parent_id','=',False),('cost_type','=','fuel')]</field>
</record>
<record model="ir.actions.act_window" id="action_fleet_vehicle_log_services_graph">
<field name="name">Services Costs by Month</field>
<field name="res_model">fleet.vehicle.cost</field>
<field name="view_id" ref="fleet_vehicle_costs_graph" />
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="domain">['&amp;',('parent_id','=',False),('cost_type','=','services')]</field>
</record>
<record model="ir.actions.act_window" id="action_fleet_vehicle_log_contract_graph">
<field name="name">Contracts Costs by Month</field>
<field name="res_model">fleet.vehicle.cost</field>
<field name="view_id" ref="fleet_vehicle_costs_graph"></field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="domain">['&amp;',('parent_id','=',False),('cost_type','=','contract')]</field>
</record>
<record model="ir.actions.act_window" id="action_fleet_vehicle_costs_graph">
<field name="name">Costs by Month</field>
<field name="res_model">fleet.vehicle.cost</field>
<field name="view_id" ref="fleet_vehicle_costs_graph"></field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="domain">[('parent_id','=',False)]</field>
</record>
<record model="ir.actions.act_window" id="action_fleet_vehicle_kanban">
<field name="name">Vehicles with alerts</field>
<field name="res_model">fleet.vehicle</field>
<field name="view_id" ref="fleet_vehicle_kanban"></field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="domain">['|',('contract_renewal_due_soon','>',0),('contract_renewal_overdue','>',0)]</field>
<field name="help" type="html">
<p>
Here are displayed vehicles for which one or more contracts need to be renewed. If you see this message, then there is no contracts to renew.
</p>
</field>
</record>
<record model="ir.actions.act_window" id="action_fleet_reporting_costs">
<field name="name">Costs Analysis</field>
<field name="res_model">fleet.vehicle.cost</field>
<field name="view_id" ref="fleet_vehicle_costs_tree"></field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="context">{"search_default_parent_false" : True,"search_default_groupby_year" : True,"search_default_groupby_cost_type" : True,"search_default_groupby_cost_subtype" : True, "search_default_groupby_vehicle_id" : True,}</field>
<field name="help" type="html">
<p>
OpenERP helps you managing the costs for your different vehicles
Costs are generally created from services and contract and appears here.
</p>
<p>
Thanks to the different filters, OpenERP can only print the effective
costs, sort them by type and by vehicle.
</p>
</field>
</record>
<record model="ir.actions.act_window" id="action_fleet_reporting_costs_non_effective">
<field name="name">Indicative Costs Analysis</field>
<field name="res_model">fleet.vehicle.cost</field>
<field name="view_id" ref="fleet_vehicle_costs_tree"></field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="context">{"search_default_parent_true" : True,"search_default_groupby_cost_subtype" : True,"search_default_groupby_cost_type" : True,"search_default_groupby_parent_id" : True,}</field>
<field name="help" type="html">
<p>
OpenERP helps you managing the costs for your different vehicles
Costs are generally created from services and contract and appears here.
</p>
<p>
Thanks to the different filters, OpenERP can only print the effective
costs, sort them by type and by vehicle.
</p>
</field>
</record>
<record id="board_fleet_form" model="ir.ui.view">
<field name="name">board.fleet.form</field>
<field name="model">board.board</field>
<field name="arch" type="xml">
<form string="Fleet Dashboard" version="7.0">
<board style="2-1">
<column>
<action string="Vehicles With Alerts" name="%(fleet.action_fleet_vehicle_kanban)d" view_mode="kanban"/>
<action string="Costs by Month" name="%(fleet.action_fleet_vehicle_costs_graph)d" view_mode="graph,tree"/>
</column>
<column>
<action string="Fuel Costs" name="%(fleet.action_fleet_vehicle_log_fuel_graph)d" view_mode="graph,tree"/>
<action string="Services Costs" name="%(fleet.action_fleet_vehicle_log_services_graph)d" view_mode="graph,tree"/>
<action string="Contracts Costs" name="%(fleet.action_fleet_vehicle_log_contract_graph)d" view_mode="graph,tree"/>
</column>
</board>
</form>
</field>
</record>
<record id="open_board_fleet" model="ir.actions.act_window">
<field name="name">Fleet</field>
<field name="res_model">board.board</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="usage">menu</field>
<field name="view_id" ref="board_fleet_form"/>
<field name="help" type="html">
<div class="oe_empty_custom_dashboard">
<p>
<b>Fleet dashboard is empty.</b>
</p><p>
To add your first report into this dashboard, go to any
menu, switch to list or graph view, and click <i>'Add to
Dashboard'</i> in the extended search options.
</p><p>
You can filter and group data before inserting into the
dashboard using the search options.
</p>
</div>
</field>
</record>
<menuitem id="menu_fleet_dashboard"
parent="base.menu_reporting_dashboard"
action="open_board_fleet"
sequence="50"/>
<menuitem name="Fleet" parent="base.menu_reporting" id="menu_fleet_reporting" sequence="50" />
<menuitem id="menu_fleet_reporting_costs"
parent="menu_fleet_reporting"
action="action_fleet_reporting_costs"
sequence="1"/>
<menuitem id="menu_fleet_reporting_indicative_costs"
parent="menu_fleet_reporting"
action="action_fleet_reporting_costs_non_effective"
sequence="2"/>
</data>
</openerp>

13736
addons/fleet/fleet_cars.xml Normal file

File diff suppressed because it is too large Load Diff

440
addons/fleet/fleet_data.xml Normal file
View File

@ -0,0 +1,440 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<!--
<record forcecreate="True" id="ir_cron_service_services_reminders" model="ir.cron">
<field name="name">Creation of Vehicle services and Services renewals reminders</field>
<field eval="True" name="active" />
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
<field eval="'fleet.vehicle'" name="model" />
<field eval="'run_scheduler'" name="function" />
<field eval="'()'" name="args" />
</record>
-->
<record forcecreate="True" id="ir_cron_contract_costs_generator" model="ir.cron">
<field name="name">Generation of contracts costs based on the costs frequency</field>
<field eval="True" name="active" />
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
<field eval="'fleet.vehicle.log.contract'" name="model" />
<field eval="'run_scheduler'" name="function" />
<field eval="'()'" name="args" />
</record>
<record id="type_service_service_1" model="fleet.service.type">
<field name="name">Calculation Benefit In Kind</field>
<field name="category">service</field>
</record>
<record id="type_service_service_2" model="fleet.service.type">
<field name="name">Depreciation and Interests</field>
<field name="category">service</field>
</record>
<record id="type_service_service_3" model="fleet.service.type">
<field name="name">Tax roll</field>
<field name="category">service</field>
</record>
<record id="type_service_service_5" model="fleet.service.type">
<field name="name">Summer tires</field>
<field name="category">service</field>
</record>
<record id="type_service_service_6" model="fleet.service.type">
<field name="name">Snow tires</field>
<field name="category">service</field>
</record>
<record id="type_service_service_7" model="fleet.service.type">
<field name="name">Summer tires</field>
<field name="category">service</field>
</record>
<record id="type_service_service_8" model="fleet.service.type">
<field name="name">Repair and maintenance</field>
<field name="category">service</field>
</record>
<record id="type_service_service_9" model="fleet.service.type">
<field name="name">Assistance</field>
<field name="category">service</field>
</record>
<record id="type_service_service_10" model="fleet.service.type">
<field name="name">Replacement Vehicle</field>
<field name="category">service</field>
</record>
<record id="type_service_service_11" model="fleet.service.type">
<field name="name">Management Fee</field>
<field name="category">service</field>
</record>
<record id="type_service_service_12" model="fleet.service.type">
<field name="name">Rent (Excluding VAT)</field>
<field name="category">service</field>
</record>
<record id="type_service_service_13" model="fleet.service.type">
<field name="name">Entry into service tax</field>
<field name="category">service</field>
</record>
<record id="type_service_service_14" model="fleet.service.type">
<field name="name">Total expenses (Excluding VAT)</field>
<field name="category">service</field>
</record>
<record id="type_service_service_15" model="fleet.service.type">
<field name="name">Residual value (Excluding VAT)</field>
<field name="category">service</field>
</record>
<record id="type_service_service_16" model="fleet.service.type">
<field name="name">Options</field>
<field name="category">service</field>
</record>
<record id="type_service_service_17" model="fleet.service.type">
<field name="name">Emissions</field>
<field name="category">service</field>
</record>
<record id="type_service_service_18" model="fleet.service.type">
<field name="name">Touring Assistance</field>
<field name="category">service</field>
</record>
<record id="type_service_service_19" model="fleet.service.type">
<field name="name">Residual value in %</field>
<field name="category">service</field>
</record>
<record id="type_service_1" model="fleet.service.type">
<field name="name">A/C Compressor Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_2" model="fleet.service.type">
<field name="name">A/C Condenser Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_3" model="fleet.service.type">
<field name="name">A/C Diagnosis</field>
<field name="category">service</field>
</record>
<record id="type_service_4" model="fleet.service.type">
<field name="name">A/C Evaporator Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_5" model="fleet.service.type">
<field name="name">A/C Recharge</field>
<field name="category">service</field>
</record>
<record id="type_service_6" model="fleet.service.type">
<field name="name">Air Filter Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_7" model="fleet.service.type">
<field name="name">Alternator Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_8" model="fleet.service.type">
<field name="name">Ball Joint Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_9" model="fleet.service.type">
<field name="name">Battery Inspection</field>
<field name="category">service</field>
</record>
<record id="type_service_10" model="fleet.service.type">
<field name="name">Battery Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_11" model="fleet.service.type">
<field name="name">Brake Caliper Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_12" model="fleet.service.type">
<field name="name">Brake Inspection</field>
<field name="category">service</field>
</record>
<record id="type_service_13" model="fleet.service.type">
<field name="name">Brake Pad(s) Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_14" model="fleet.service.type">
<field name="name">Car Wash</field>
<field name="category">service</field>
</record>
<record id="type_service_15" model="fleet.service.type">
<field name="name">Catalytic Converter Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_16" model="fleet.service.type">
<field name="name">Charging System Diagnosis</field>
<field name="category">service</field>
</record>
<record id="type_service_17" model="fleet.service.type">
<field name="name">Door Window Motor/Regulator Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_18" model="fleet.service.type">
<field name="name">Engine Belt Inspection</field>
<field name="category">service</field>
</record>
<record id="type_service_19" model="fleet.service.type">
<field name="name">Engine Coolant Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_20" model="fleet.service.type">
<field name="name">Engine/Drive Belt(s) Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_21" model="fleet.service.type">
<field name="name">Exhaust Manifold Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_22" model="fleet.service.type">
<field name="name">Fuel Injector Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_23" model="fleet.service.type">
<field name="name">Fuel Pump Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_24" model="fleet.service.type">
<field name="name">Head Gasket(s) Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_25" model="fleet.service.type">
<field name="name">Heater Blower Motor Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_26" model="fleet.service.type">
<field name="name">Heater Control Valve Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_27" model="fleet.service.type">
<field name="name">Heater Core Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_28" model="fleet.service.type">
<field name="name">Heater Hose Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_29" model="fleet.service.type">
<field name="name">Ignition Coil Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_30" model="fleet.service.type">
<field name="name">Intake Manifold Gasket Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_31" model="fleet.service.type">
<field name="name">Oil Change</field>
<field name="category">service</field>
</record>
<record id="type_service_32" model="fleet.service.type">
<field name="name">Oil Pump Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_33" model="fleet.service.type">
<field name="name">Other Maintenance</field>
<field name="category">service</field>
</record>
<record id="type_service_34" model="fleet.service.type">
<field name="name">Oxygen Sensor Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_35" model="fleet.service.type">
<field name="name">Power Steering Hose Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_36" model="fleet.service.type">
<field name="name">Power Steering Pump Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_37" model="fleet.service.type">
<field name="name">Radiator Repair</field>
<field name="category">service</field>
</record>
<record id="type_service_38" model="fleet.service.type">
<field name="name">Resurface Rotors</field>
<field name="category">service</field>
</record>
<record id="type_service_39" model="fleet.service.type">
<field name="name">Rotate Tires</field>
<field name="category">service</field>
</record>
<record id="type_service_40" model="fleet.service.type">
<field name="name">Rotor Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_41" model="fleet.service.type">
<field name="name">Spark Plug Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_42" model="fleet.service.type">
<field name="name">Starter Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_43" model="fleet.service.type">
<field name="name">Thermostat Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_44" model="fleet.service.type">
<field name="name">Tie Rod End Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_45" model="fleet.service.type">
<field name="name">Tire Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_46" model="fleet.service.type">
<field name="name">Tire Service</field>
<field name="category">service</field>
</record>
<record id="type_service_47" model="fleet.service.type">
<field name="name">Transmission Filter Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_48" model="fleet.service.type">
<field name="name">Transmission Fluid Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_49" model="fleet.service.type">
<field name="name">Transmission Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_50" model="fleet.service.type">
<field name="name">Water Pump Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_51" model="fleet.service.type">
<field name="name">Wheel Alignment</field>
<field name="category">service</field>
</record>
<record id="type_service_52" model="fleet.service.type">
<field name="name">Wheel Bearing Replacement</field>
<field name="category">service</field>
</record>
<record id="type_service_53" model="fleet.service.type">
<field name="name">Windshield Wiper(s) Replacement</field>
<field name="category">service</field>
</record>
<record id="type_contract_omnium" model="fleet.service.type">
<field name="name">Omnium</field>
<field name="category">contract</field>
</record>
<record id="type_contract_leasing" model="fleet.service.type">
<field name="name">Leasing</field>
<field name="category">contract</field>
</record>
<record id="type_contract_repairing" model="fleet.service.type">
<field name="name">Repairing</field>
<field name="category">both</field>
</record>
<record id="type_service_refueling" model="fleet.service.type">
<field name="name">Refueling</field>
<field name="category">service</field>
</record>
<record id="vehicle_tag_junior" model="fleet.vehicle.tag" >
<field name="name">Junior</field>
</record>
<record id="vehicle_tag_senior" model="fleet.vehicle.tag" >
<field name="name">Senior</field>
</record>
<record id="vehicle_tag_leasing" model="fleet.vehicle.tag" >
<field name="name">Employee Car</field>
</record>
<record id="vehicle_tag_purchased" model="fleet.vehicle.tag" >
<field name="name">Purchased</field>
</record>
<record id="vehicle_tag_compact" model="fleet.vehicle.tag" >
<field name="name">Compact</field>
</record>
<record id="vehicle_tag_sedan" model="fleet.vehicle.tag" >
<field name="name">Sedan</field>
</record>
<record id="vehicle_tag_convertible" model="fleet.vehicle.tag" >
<field name="name">Convertible</field>
</record>
<record id="vehicle_tag_break" model="fleet.vehicle.tag" >
<field name="name">Break</field>
</record>
</data>
</openerp>

1166
addons/fleet/fleet_demo.xml Normal file

File diff suppressed because it is too large Load Diff

907
addons/fleet/fleet_view.xml Normal file
View File

@ -0,0 +1,907 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record model='ir.ui.view' id='fleet_vehicle_model_form'>
<field name="name">fleet.vehicle.model.form</field>
<field name="model">fleet.vehicle.model</field>
<field name="arch" type="xml">
<form string="Model" version="7.0">
<sheet>
<field name="image_medium" widget='image' class="oe_left oe_avatar"/>
<group col="2">
<group>
<field name="brand" on_change="on_change_brand(brand)"/>
</group>
<group>
<field name="modelname" />
</group>
</group>
<notebook>
<page string="Vendors">
<field name="vendors" widget="many2many_kanban"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_model_tree'>
<field name="name">fleet.vehicle.model.tree</field>
<field name="model">fleet.vehicle.model</field>
<field name="arch" type="xml">
<tree string="Models" version="7.0">
<field name="brand" />
<field name="modelname" />
</tree>
</field>
</record>
<record model='ir.actions.act_window' id='fleet_vehicle_model_act'>
<field name="name">Vehicle Model</field>
<field name="res_model">fleet.vehicle.model</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new model.
</p><p>
You can define several models (e.g. A3, A4) for each brand (Audi).
</p>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_model_brand_tree'>
<field name="name">fleet.vehicle.model.brand.tree</field>
<field name="model">fleet.vehicle.model.brand</field>
<field name="arch" type="xml">
<tree string="Model Brand" version="7.0">
<field name="name" />
</tree>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_model_brand_form'>
<field name="name">fleet.vehicle.model.brand.form</field>
<field name="model">fleet.vehicle.model.brand</field>
<field name="arch" type="xml">
<form string="Model Brand" version="7.0">
<sheet>
<group>
<div>
<field name="image_medium" widget="image" class="oe_left oe_avatar"/>
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name" class="oe_inline" />
</h1>
</div>
</group>
</sheet>
</form>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_model_brand_kanban'>
<field name="name">fleet.vehicle.model.brandkanban</field>
<field name="model">fleet.vehicle.model.brand</field>
<field name="arch" type="xml">
<kanban>
<field name="name" />
<field name="image" />
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_vignette oe_semantic_html_override">
<a type="open" href="#" class="oe_kanban_action oe_kanban_action_a">
<img t-att-src="kanban_image('fleet.vehicle.model.brand', 'image_small', record.id.value)" class="oe_employee_picture"/>
</a>
<div style="text-align:center;">
<h4 class="oe_partner_heading">
<a type="open">
<field name="name"/>
</a>
</h4>
</div>
</div>
<script>
$('.oe_picture').load(function() { if($(this).width() > $(this).height()) { $(this).addClass('oe_employee_picture_wide') } });
</script>
</t>
</templates>
</kanban>
</field>
</record>
<record model='ir.actions.act_window' id='fleet_vehicle_model_brand_act'>
<field name="name">Model brand of Vehicle</field>
<field name="res_model">fleet.vehicle.model.brand</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new brand.
</p>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_state_tree'>
<field name="name">fleet.vehicle.state.tree</field>
<field name="model">fleet.vehicle.state</field>
<field name="arch" type="xml">
<tree string="State" version="7.0" editable="bottom">
<field name="sequence" widget="handler" invisible="1"/>
<field name="name" />
</tree>
</field>
</record>
<record model='ir.actions.act_window' id='fleet_vehicle_state_act'>
<field name="name">States of Vehicle</field>
<field name="res_model">fleet.vehicle.state</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a vehicule status.
</p><p>
You can customize available status to track the evolution of
each vehicule. Example: Active, Being Repaired, Sold.
</p>
</field>
</record>
<menuitem name="Fleet" id="menu_root" sequence="70" />
<menuitem name="Configuration" parent="menu_root" id="fleet_configuration" sequence="3" />
<menuitem action="fleet_vehicle_model_act" parent="fleet_configuration" id="fleet_vehicle_model_menu" groups="base.group_no_one"/>
<menuitem action="fleet_vehicle_model_brand_act" parent="fleet_configuration" id="fleet_vehicle_model_brand_menu" groups="base.group_no_one"/>
<menuitem action="fleet_vehicle_state_act" parent="fleet_configuration" id="fleet_vehicle_state_menu" />
<record model='ir.ui.view' id='fleet_vehicle_form'>
<field name="name">fleet.vehicle.form</field>
<field name="model">fleet.vehicle</field>
<field name="arch" type="xml">
<form string="Vehicle" version="7.0">
<header>
<field name="state" widget="statusbar" clickable="True" />
</header>
<sheet>
<field name="image_medium" widget='image' class="oe_left oe_avatar"/>
<div class="oe_title">
<label for="model_id" class="oe_edit_only"/>
<h1>
<field name="model_id" class="oe_inline" on_change="on_change_model(model_id)"/>
</h1>
<label for="license_plate" class="oe_edit_only"/>
<h2>
<field name="license_plate" class="oe_inline"/>
</h2>
<label for="tag_ids" class="oe_edit_only"/>
<field name="tag_ids" widget="many2many_tags" />
</div>
<div class="oe_right oe_button_box">
<button name="return_action_to_open" type="object" context="{'xml_id':'fleet_vehicle_log_contract_act'}" string="Contracts" help="show the contract for this vehicle" />
<button name="act_show_log_cost" type="object" string="Costs" help="show all the costs for this vehicle" />
<button name="return_action_to_open" type="object" context="{'xml_id':'fleet_vehicle_log_services_act'}" string="Services" help="show the services logs for this vehicle" />
<button name="return_action_to_open" type="object" context="{'xml_id':'fleet_vehicle_log_fuel_act'}" string="Fuel Logs" help="show the fuel logs for this vehicle" />
<button name="return_action_to_open" type="object" context="{'xml_id':'fleet_vehicle_odometer_act'}" string="Odometer Logs" help="show the odometer logs for this vehicle" />
</div>
<group col="2" string="General Properties">
<group >
<field name="driver" />
<field name="location" />
<field name="vin_sn" />
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group >
<label for="odometer" />
<div>
<field name="odometer" class="oe_inline"/>
<field name="odometer_unit" class="oe_inline"/>
</div>
<field name="acquisition_date" />
<field name="car_value" />
</group>
</group>
<group col="2">
<group string="Additional Properties">
<field name="seats" />
<field name="doors" />
<field name="color" />
</group>
<group string="Engine Options">
<field name="transmission" />
<field name="fuel_type" />
<field name="co2" />
<field name="horsepower" />
<field name="horsepower_tax" />
<field name="power" />
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_ids" widget="mail_thread" options='{"thread_level": 1}'/>
<field name="message_follower_ids" widget="mail_followers"/>
</div>
</form>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_tree'>
<field name="name">fleet.vehicle.tree</field>
<field name="model">fleet.vehicle</field>
<field name="sequence">1</field>
<field name="arch" type="xml">
<tree string="Vehicle" version="7.0" colors="orange:contract_renewal_due_soon and not contract_renewal_overdue;red:contract_renewal_overdue">
<field name="license_plate" />
<field name="model_id" />
<field name="driver" />
<field name="vin_sn" />
<field name="acquisition_date" />
<field name="state"/>
<field name="odometer" />
<field name="odometer_unit" />
<field name="contract_renewal_due_soon" invisible="1"/>
<field name="contract_renewal_overdue" invisible="1" />
<field name="contract_renewal_total" invisible="1"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="fleet_vehicle_search">
<field name="name">fleet.vehicle.search</field>
<field name="model">fleet.vehicle</field>
<field name="arch" type="xml">
<search string="All vehicles">
<field name="name" filter_domain="['|', ('name','ilike',self), ('license_plate','ilike',self)]" string="Vehicle"/>
<field name="driver"/>
<field name="tag_ids"/>
<field name="location"/>
<field name="state" />
<field name="state" />
<filter name="alert_true" domain="['|',('contract_renewal_due_soon','>',0),('contract_renewal_overdue','>',0)]" string="Has Alert(s)"/>
</search>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_kanban'>
<field name="name">fleet.vehicle.kanban</field>
<field name="model">fleet.vehicle</field>
<field name="arch" type="xml">
<kanban>
<field name="license_plate" />
<field name="model_id" />
<field name="driver" />
<field name="location" />
<field name="state" />
<field name="image" />
<field name="tag_ids" />
<field name="contract_renewal_due_soon" />
<field name="contract_renewal_overdue" />
<field name="contract_renewal_name" />
<field name="contract_renewal_total" />
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_vignette oe_semantic_html_override">
<a type="open" href="#" class="oe_kanban_action oe_kanban_action_a">
<img t-att-src="kanban_image('fleet.vehicle', 'image_small', record.id.value)"/>
</a>
<div class="oe_kanban_details">
<h4 class="oe_partner_heading">
<a type="open">
<field name="license_plate"/><br/>
<field name="model_id" />
</a>
</h4>
<t t-if="record.contract_renewal_due_soon.raw_value and !record.contract_renewal_overdue.raw_value">
<a data-type="object" data-name="return_action_to_open" href="#" class="oe_kanban_action oe_kanban_action_a" data-context='{"xml_id":"fleet_vehicle_log_contract_act"}'>
<span class="oe_tag oe_kanban_color_3"><field name="contract_renewal_name" />
<t t-if="record.contract_renewal_total.raw_value > 0"> and <field name="contract_renewal_total" /> other(s) </t>
</span>
</a>
</t>
<t t-if="record.contract_renewal_overdue.raw_value">
<a data-type="object" data-name="return_action_to_open" href="#" class="oe_kanban_action oe_kanban_action_a" data-context='{"xml_id":"fleet_vehicle_log_contract_act"}'>
<span class="oe_tag oe_kanban_color_2"><field name="contract_renewal_name" />
<t t-if="record.contract_renewal_total.raw_value > 0"> and <field name="contract_renewal_total" /> other(s) </t>
</span>
</a>
</t>
<ul>
<li>
<t t-if="record.driver.raw_value"><field name="driver"/></t>
</li>
<li>
<t t-if="record.location.raw_value"><field name="location"/></t>
</li>
</ul>
<div class="oe_kanban_partner_categories">
<span class="oe_kanban_list_many2many">
<div modifiers="{}" name="tag_ids" class="oe_form_field oe_tags" model="fleet.vehicle.tag" t-att-data="record.tag_ids.raw_value" />
</span>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record model='ir.actions.act_window' id='fleet_vehicle_act'>
<field name="name">Vehicles</field>
<field name="res_model">fleet.vehicle</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new vehicle.
</p><p>
You will be able to manage your fleet by keeping track of the
contracts, services, fixed and recurring costs, odometers and
fuel logs associated to each vehicle.
</p><p>
OpenERP will warn you when services or contract have to be
renewed.
</p>
</field>
</record>
<menuitem name="Vehicles" parent="menu_root" id="fleet_vehicles" sequence="2" />
<menuitem action="fleet_vehicle_act" parent="fleet_vehicles" id="fleet_vehicle_menu" />
<record model='ir.ui.view' id='fleet_vehicle_log_contract_form'>
<field name="name">fleet.vehicle.log_contract.form</field>
<field name="model">fleet.vehicle.log.contract</field>
<field name="arch" type="xml">
<form string="Contract logs" version="7.0">
<header>
<button modifiers="{'invisible': [['state', '=', 'closed']]}" name="contract_close" states="open" type="object" class="oe_highlight" string="Terminate Contract"/>
<button modifiers="{'invisible': [['state', '=', 'closed']]}" name="contract_close" states="toclose" type="object" class="oe_highlight" string="Terminate Contract"/>
<button modifiers="{'invisible': [['state', 'not in', ['closed']]]}" name="contract_open" states="closed" type="object" class="oe_highlight" string="Set Contract In Progress"/>
<button class="oe_highlight" name="act_renew_contract" type="object" string="Renew Contract" help="Create a new contract automatically with all the same informations except for the date that will start at the end of current contract" />
<field name="state" widget="statusbar" />
</header>
<sheet>
<group col="2">
<group string="Contract details">
<field name="vehicle_id" on_change="on_change_vehicle(vehicle_id)"/>
<field name="cost_subtype" required="1" domain="['|',('category','=','contract'),('category','=','both')]"/>
<field name="amount" string="Activation Cost"/>
<label for="cost_generated"/>
<div>
<field name="cost_generated" class="oe_inline" attrs="{'invisible': [('cost_frequency','=','no')]}" />
<field name="cost_frequency" class="oe_inline" />
</div>
</group>
<group string="Odometer details">
<label for="odometer"/>
<div>
<field name="odometer" class="oe_inline"/>
<field name="odometer_unit" class="oe_inline"/>
</div>
</group>
</group>
<group col="2">
<group>
<field name="date" string="Invoice Date"/>
<field name="start_date"/>
<field name="expiration_date" />
</group>
<group>
<field name="insurer_id" />
<field name="purchaser_id" />
<field name="ins_ref" />
</group>
</group>
<notebook>
<page string="Included Services">
<group>
<field name="cost_ids" context="{'vehicle_id': vehicle_id}" nolabel="1" on_change="on_change_indic_cost(cost_ids)">
<tree version="7.0" editable="bottom">
<field name="cost_subtype" string="Service" domain="[('category','=','service')]"/>
<field name="amount" sum="Price" string="Indicative Cost" />
</tree>
</field>
</group>
<div class="oe_right"><group><field name="sum_cost" string="Indicative Costs Total"/></group></div>
</page>
<page string="Generated Costs">
<group>
<field name="generated_cost_ids" context="{'vehicle_id': vehicle_id}" nolabel="1" sum="amount">
<tree version="7.0" editable="bottom" >
<field name="date" />
<field name="amount" sum="amount"/>
</tree>
</field>
</group>
</page>
</notebook>
<group string="Terms and Conditions">
<field name="notes" nolabel="1" placeholder="Write here all other information relative to this contract" />
</group>
</sheet>
</form>
</field>
</record>
<act_window
id="act_renew_contract"
name="Renew Contract"
res_model="fleet.vehicle.log.contract"
src_model="fleet.vehicle.log.contract"
view_mode="form"
view_type="form"
/>
<record model='ir.ui.view' id='fleet_vehicle_log_contract_tree'>
<field name="name">fleet.vehicle.log.contract.tree</field>
<field name="model">fleet.vehicle.log.contract</field>
<field name="arch" type="xml">
<tree string="Contract logs" version="7.0" colors="orange:days_left>0 and days_left&lt;15;red:days_left==0;grey:state=='closed'">
<field name="start_date" />
<field name="expiration_date" />
<field name="days_left" invisible="1"/>
<field name="vehicle_id" />
<field name="cost_subtype"/>
<field name="insurer_id" />
<field name="amount" string="Activation Cost"/>
<field name="cost_generated"/>
<field name="cost_frequency"/>
<field name="state" />
</tree>
</field>
</record>
<record model="ir.ui.view" id="fleet_vehicle_log_contract_graph">
<field name="name">fleet.vehicle.log.contract.graph</field>
<field name="model">fleet.vehicle.log.contract</field>
<!--<field name="type">graph</field>-->
<field name="arch" type="xml">
<graph string="Contract Costs Per Month">
<field name="date" />
<field name="cost_amount" operator="+"/>
<field name="vehicle_id" group="True"/>
</graph>
</field>
</record>
<record model='ir.actions.act_window' id='fleet_vehicle_log_contract_act'>
<field name="name">Vehicles Contracts</field>
<field name="res_model">fleet.vehicle.log.contract</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,graph</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new contract.
</p><p>
Manage all your contracts (leasing, insurances, etc.) with
their related services, costs. OpenERP will automatically warn
you when some contracts have to be renewed.
</p><p>
Each contract (e.g.: leasing) may include several services
(reparation, insurances, periodic maintenance).
</p>
</field>
</record>
<menuitem action="fleet_vehicle_log_contract_act" parent="fleet_vehicles" id="fleet_vehicle_log_contract_menu" />
<record model='ir.ui.view' id='fleet_vehicle_odometer_form'>
<field name="name">fleet.vehicle.odometer.form</field>
<field name="model">fleet.vehicle.odometer</field>
<field name="arch" type="xml">
<form string="Odometer Logs" version="7.0">
<sheet>
<group>
<field name="vehicle_id" on_change="on_change_vehicle(vehicle_id)"/>
<div>
<field name="value" class="oe_inline"/>
<field name="unit" class="oe_inline"/>
</div>
<field name="date" />
</group>
</sheet>
</form>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_odometer_tree'>
<field name="name">fleet.vehicle.odometer.tree</field>
<field name="model">fleet.vehicle.odometer</field>
<field name="arch" type="xml">
<tree string="Odometer Logs" version="7.0" editable="bottom">
<field name="date" />
<field name="vehicle_id" on_change="on_change_vehicle(vehicle_id)"/>
<field name="value" />
<field name="unit" />
</tree>
</field>
</record>
<!--
<record model='ir.ui.view' id='fleet_vehicle_odometer_search'>
<field name="name">fleet.vehicle.odometer.search</field>
<field name="model">fleet.vehicle.odometer</field>
<field name="arch" type="xml">
<search string="Vehicles odometers" >
<field name="vehicle_id" />
<field name="value"/>
<field name="unit"/>
<field name="date"/>
<filter name="groupby_vehicle" context="{'group_by' : 'vehicle_id'}" string="Vehicle"/>
</search>
</field>
</record>
-->
<record model="ir.ui.view" id="fleet_vehicle_odometer_graph">
<field name="name">fleet.vehicle.odometer.graph</field>
<field name="model">fleet.vehicle.odometer</field>
<!--<field name="type">graph</field>-->
<field name="arch" type="xml">
<graph string="Odometer Values Per Month">
<field name="date" />
<field name="value" operator="+"/>
<field name="vehicle_id" group="True"/>
</graph>
</field>
</record>
<record model='ir.actions.act_window' id='fleet_vehicle_odometer_act'>
<field name="name">Vehicles Odometer</field>
<field name="res_model">fleet.vehicle.odometer</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,graph</field>
<field name="context">{"search_default_groupby_vehicle" : True}</field>
<field name="help" type="html">
<p>
Here you can add various odometer entries for all vehicles.
You can also show odometer value for a particular vehicle using
the search field.
</p>
</field>
</record>
<menuitem action="fleet_vehicle_odometer_act" parent="fleet_vehicles" id="fleet_vehicle_odometer_menu" />
<record model='ir.ui.view' id='fleet_vehicle_log_fuel_form'>
<field name="name">fleet.vehicle.log.fuel.form</field>
<field name="model">fleet.vehicle.log.fuel</field>
<field name="arch" type="xml">
<form string="Fuel Logs" version="7.0">
<sheet>
<group col="2">
<group string="Vehicle Details">
<field name="vehicle_id" on_change="on_change_vehicle(vehicle_id)"/>
</group>
<group string="Refueling Details">
<field name="liter" on_change="on_change_liter(liter,price_per_liter,amount)"/>
<field name="price_per_liter" on_change="on_change_price_per_liter(liter,price_per_liter,amount)" />
<field name="amount" on_change="on_change_amount(liter,price_per_liter,amount)"/>
</group>
</group>
<group col="2">
<group string="Odometer Details">
<label for="odometer"/>
<div>
<field name="odometer" class="oe_inline"/>
<field name="odometer_unit" class="oe_inline"/>
</div>
</group>
<group string="Additional Details">
<field name="date" />
<field name="purchaser_id" />
<field name="inv_ref" />
<field name="vendor_id" />
</group>
</group>
<group string="Notes">
<field nolabel="1" name="notes" placeholder="Write here any other information"/>
</group>
</sheet>
</form>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_log_fuel_tree'>
<field name="name">fleet.vehicle.log.fuel.tree</field>
<field name="model">fleet.vehicle.log.fuel</field>
<field name="arch" type="xml">
<tree string="Fuel Logs">
<field name="date" />
<field name="vehicle_id" />
<field name="odometer" invisible="1"/>
<field name="odometer_unit" invisible="1"/>
<field name="purchaser_id" />
<field name="inv_ref" invisible="1"/>
<field name="vendor_id" invisible="1"/>
<field name="liter" />
<field name="price_per_liter" invisible="1"/>
<field name="amount" sum="Price"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="fleet_vehicle_log_fuel_graph">
<field name="name">fleet.vehicle.log.fuel.graph</field>
<field name="model">fleet.vehicle.log.fuel</field>
<!--<field name="type">graph</field>-->
<field name="arch" type="xml">
<graph string="Fuel Costs Per Month">
<field name="date" />
<field name="cost_amount" operator="+"/>
<field name="vehicle_id" group="True"/>
</graph>
</field>
</record>
<record model='ir.actions.act_window' id='fleet_vehicle_log_fuel_act'>
<field name="name">Vehicles Fuel Logs</field>
<field name="res_model">fleet.vehicle.log.fuel</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,graph</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new fuel log.
</p><p>
Here you can add refuelling entries for all vehicles. You can
also filter logs of a particular vehicle using the search
field.
</p>
</field>
</record>
<menuitem action="fleet_vehicle_log_fuel_act" parent="fleet_vehicles" id="fleet_vehicle_log_fuel_menu" />
<record model='ir.ui.view' id='fleet_vehicle_log_services_form'>
<field name="name">fleet.vehicle.log.services.form</field>
<field name="model">fleet.vehicle.log.services</field>
<field name="arch" type="xml">
<form string="Services Logs" version="7.0">
<sheet>
<group col="2">
<group string="Services Details">
<field name="vehicle_id" on_change="on_change_vehicle(vehicle_id)"/>
<field name="cost_subtype" string="Service Type" domain="['|',('category','=','service'),('category','=','both')]" required="1"/>
<field name="amount" string="Price"/>
</group>
<group string="Odometer Details">
<label for="odometer"/>
<div>
<field name="odometer" class="oe_inline"/>
<field name="odometer_unit" class="oe_inline"/>
</div>
</group>
</group>
<group col="2">
<group string="Additional Details">
<field name="date" />
<field name="purchaser_id" />
<field name="vendor_id" />
<field name="inv_ref" />
</group>
</group>
<group string="Included Services">
<field name="cost_ids" nolabel="1">
<tree string="Included Services" version="7.0" editable="bottom">
<field name="cost_subtype" string="Service" domain="[('category','=','service')]"/>
<field name="amount" sum="Price" string="Cost"/>
</tree>
</field>
</group>
<group string="Notes">
<field nolabel="1" name="notes" placeholder="Write here any other information related to the service completed."/>
</group>
</sheet>
</form>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_log_services_tree'>
<field name="name">fleet.vehicle.log.services.tree</field>
<field name="model">fleet.vehicle.log.services</field>
<field name="arch" type="xml">
<tree string="Services Logs">
<field name="date" />
<field name="vehicle_id" />
<field name="cost_subtype"/>
<field name="purchaser_id"/>
<field name="vendor_id" />
<field name="inv_ref" />
<field name="notes" />
<field name="amount" sum="Total"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="fleet_vehicle_log_services_graph">
<field name="name">fleet.vehicle.log.services.graph</field>
<field name="model">fleet.vehicle.log.services</field>
<field name="arch" type="xml">
<graph string="Services Costs Per Month">
<field name="date" />
<field name="cost_amount" operator="+"/>
<field name="vehicle_id" group="True"/>
</graph>
</field>
</record>
<record model='ir.actions.act_window' id='fleet_vehicle_log_services_act'>
<field name="name">Vehicles Services Logs</field>
<field name="res_model">fleet.vehicle.log.services</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,graph</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new service entry.
</p><p>
OpenERP helps you keeping track of all the services done
on your vehicle. Services can be of many type: occasional
repair, fixed maintenance, etc.
</p>
</field>
</record>
<menuitem action="fleet_vehicle_log_services_act" parent="fleet_vehicles" id="fleet_vehicle_log_services_menu" />
<record model='ir.ui.view' id='fleet_vehicle_service_types_tree'>
<field name="name">fleet.service.type.tree</field>
<field name="model">fleet.service.type</field>
<field name="arch" type="xml">
<tree string="Service types" editable="bottom">
<field name="name" />
<field name="category"/>
</tree>
</field>
</record>
<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>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new type of service.
</p><p>
Each service can used in contracts, as a standalone service or both.
</p>
</field>
</record>
<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_costs_tree'>
<field name="name">fleet.vehicle.cost.tree</field>
<field name="model">fleet.vehicle.cost</field>
<field name="arch" type="xml">
<tree string="Vehicles costs" >
<field name="date"/>
<field name="vehicle_id" />
<field name="cost_type"/>
<field name="cost_subtype"/>
<field name="amount" sum="Total Cost"/>
<field name="parent_id" invisible="1" />
<field name="year" invisible="1"/>
</tree>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_costs_search'>
<field name="name">fleet.vehicle.cost.search</field>
<field name="model">fleet.vehicle.cost</field>
<field name="arch" type="xml">
<search string="Vehicles costs" >
<field name="vehicle_id" />
<field name="cost_subtype"/>
<field name="year"/>
<field name="date"/>
<field name="parent_id"/>
<filter name="parent_false" domain="[('parent_id','=',False)]" string="Effective Costs"/>
<filter name="parent_true" domain="[('parent_id','!=',False)]" string="Indicative Costs"/>
<group expand="1" string="Group By...">
<filter name="groupby_year" context="{'group_by' : 'year'}" string="Year"/>
<filter name="groupby_date" context="{'group_by' : 'date'}" string="Date"/>
<filter name="groupby_cost_type" context="{'group_by' : 'cost_type'}" string="Cost Type"/>
<filter name="groupby_cost_subtype" context="{'group_by' : 'cost_subtype'}" string="Cost Subtype"/>
<filter name="groupby_vehicle_id" context="{'group_by' : 'vehicle_id'}" string="Vehicle"/>
<filter name="groupby_parent_id" context="{'group_by' : 'parent_id'}" string="Parent"/>
</group>
</search>
</field>
</record>
<record model='ir.ui.view' id='fleet_vehicle_costs_form'>
<field name="name">fleet.vehicle.cost.form</field>
<field name="model">fleet.vehicle.cost</field>
<field name="arch" type="xml">
<form string="Vehicle costs" version="7.0">
<sheet>
<group col="2" string="Cost Details">
<group>
<field name="vehicle_id" />
<field name="cost_subtype"/>
<field name="amount"/>
</group>
<group>
<field name="date"/>
<field name="parent_id"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="fleet_vehicle_costs_graph">
<field name="name">fleet.vehicle.cost.graph</field>
<field name="model">fleet.vehicle.cost</field>
<field name="arch" type="xml">
<graph string="Costs Per Month">
<field name="date" />
<field name="amount"/>
<field name="vehicle_id" group="True"/>
</graph>
</field>
</record>
<record model='ir.actions.act_window' id='fleet_vehicle_costs_act'>
<field name="name">Vehicle Costs</field>
<field name="res_model">fleet.vehicle.cost</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,graph</field>
<field name="context">{"search_default_parent_false" : True, "search_default_groupby_vehicle_id" : True,}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new cost.
</p><p>
OpenERP helps you managing the costs for your different
vehicles. Costs are created automatically from services,
contracts (fixed or recurring) and fuel logs.
</p>
</field>
</record>
<menuitem action="fleet_vehicle_costs_act" parent="fleet_vehicles" id="fleet_vehicle_costs_menu" />
<!--
<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>

View File

@ -0,0 +1,11 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
fleet_vehicle_model_access_right,fleet_vehicle_model_access_right,model_fleet_vehicle_model,,1,1,1,1
fleet_vehicle_tag_access_right,fleet_vehicle_tag_access_right,model_fleet_vehicle_tag,,1,1,1,1
fleet_vehicle_state_access_right,fleet_vehicle_state_access_right,model_fleet_vehicle_state,,1,1,1,1
fleet_vehicle_odometer_access_right,fleet_vehicle_odometer_access_right,model_fleet_vehicle_odometer,,1,1,1,1
fleet_vehicle_model_brand_access_right,fleet_vehicle_model_brand_access_right,model_fleet_vehicle_model_brand,,1,1,1,1
fleet_vehicle_access_right,fleet_vehicle_access_right,model_fleet_vehicle,,1,1,1,1
fleet_vehicle_log_fuel_access_right,fleet_vehicle_log_fuel_access_right,model_fleet_vehicle_log_fuel,,1,1,1,1
fleet_vehicle_log_services_access_right,fleet_vehicle_log_services_access_right,model_fleet_vehicle_log_services,,1,1,1,1
fleet_vehicle_log_contract_access_right,fleet_vehicle_log_contract_access_right,model_fleet_vehicle_log_contract,,1,1,1,1
fleet_service_type_access_right,fleet_service_type_access_right,model_fleet_service_type,,1,1,1,1
1 id name model_id/id group_id/id perm_read perm_write perm_create perm_unlink
2 fleet_vehicle_model_access_right fleet_vehicle_model_access_right model_fleet_vehicle_model 1 1 1 1
3 fleet_vehicle_tag_access_right fleet_vehicle_tag_access_right model_fleet_vehicle_tag 1 1 1 1
4 fleet_vehicle_state_access_right fleet_vehicle_state_access_right model_fleet_vehicle_state 1 1 1 1
5 fleet_vehicle_odometer_access_right fleet_vehicle_odometer_access_right model_fleet_vehicle_odometer 1 1 1 1
6 fleet_vehicle_model_brand_access_right fleet_vehicle_model_brand_access_right model_fleet_vehicle_model_brand 1 1 1 1
7 fleet_vehicle_access_right fleet_vehicle_access_right model_fleet_vehicle 1 1 1 1
8 fleet_vehicle_log_fuel_access_right fleet_vehicle_log_fuel_access_right model_fleet_vehicle_log_fuel 1 1 1 1
9 fleet_vehicle_log_services_access_right fleet_vehicle_log_services_access_right model_fleet_vehicle_log_services 1 1 1 1
10 fleet_vehicle_log_contract_access_right fleet_vehicle_log_contract_access_right model_fleet_vehicle_log_contract 1 1 1 1
11 fleet_service_type_access_right fleet_service_type_access_right model_fleet_service_type 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,124 @@
# 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-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-11-07 12:33+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\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: 2012-11-08 04:47+0000\n"
"X-Generator: Launchpad (build 16232)\n"
#. module: google_base_account
#: field:res.users,gmail_user:0
msgid "Username"
msgstr "Nombre de usuario"
#. module: google_base_account
#: model:ir.actions.act_window,name:google_base_account.act_google_login_form
msgid "Google Login"
msgstr "Acceso de Google"
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:29
#, python-format
msgid "Google Contacts Import Error!"
msgstr "¡Error en la importacion de los contactos de Google!"
#. module: google_base_account
#: view:res.users:0
msgid " Synchronization "
msgstr " Sincronización "
#. module: google_base_account
#: sql_constraint:res.users:0
msgid "You can not have two users with the same login !"
msgstr "¡No puede tener dos usuarios con el mismo identificador!"
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:75
#, python-format
msgid "Error"
msgstr "Error"
#. module: google_base_account
#: view:google.login:0
msgid "Google login"
msgstr "Acceso Google"
#. module: google_base_account
#: model:ir.model,name:google_base_account.model_res_users
msgid "res.users"
msgstr "Usuarios"
#. module: google_base_account
#: field:google.login,password:0
msgid "Google Password"
msgstr "Contraseña de Google"
#. module: google_base_account
#: view:google.login:0
msgid "_Cancel"
msgstr "_Cancelar"
#. module: google_base_account
#: view:res.users:0
msgid "Google Account"
msgstr "Cuenta de Google"
#. module: google_base_account
#: field:google.login,user:0
msgid "Google Username"
msgstr "Usuario de Google"
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:29
#, python-format
msgid ""
"Please install gdata-python-client from http://code.google.com/p/gdata-"
"python-client/downloads/list"
msgstr ""
"Por favor, instale gdata-python-client de http://code.google.com/p/gdata-"
"python-client/downloads/list o desde el administrador de paquetes de su "
"distribución"
#. module: google_base_account
#: model:ir.model,name:google_base_account.model_google_login
msgid "Google Contact"
msgstr "Contacto Google"
#. module: google_base_account
#: view:google.login:0
msgid "_Login"
msgstr "Iniciar _sesión"
#. module: google_base_account
#: constraint:res.users:0
msgid "The chosen company is not in the allowed companies for this user"
msgstr ""
"La compañía seleccionada no está entre las companías permitidas para este "
"usuario"
#. module: google_base_account
#: field:res.users,gmail_password:0
msgid "Password"
msgstr "Contraseña"
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:75
#, python-format
msgid "Authentication fail check the user and password !"
msgstr "Fallo en la autenticación. ¡Compruebe el usuario y la contraseña!"
#. module: google_base_account
#: view:google.login:0
msgid "ex: user@gmail.com"
msgstr "ejemplo: usuario@gmail.com"

View File

@ -0,0 +1,119 @@
# Mongolian 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-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-11-08 03:11+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: 2012-11-08 04:47+0000\n"
"X-Generator: Launchpad (build 16232)\n"
#. module: google_base_account
#: field:res.users,gmail_user:0
msgid "Username"
msgstr "Хэрэглэгчийн нэр"
#. module: google_base_account
#: model:ir.actions.act_window,name:google_base_account.act_google_login_form
msgid "Google Login"
msgstr ""
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:29
#, python-format
msgid "Google Contacts Import Error!"
msgstr ""
#. module: google_base_account
#: view:res.users:0
msgid " Synchronization "
msgstr ""
#. module: google_base_account
#: sql_constraint:res.users:0
msgid "You can not have two users with the same login !"
msgstr "Ижил нэвтрэх нэртэй хоёр хэрэглэгч байж болохгүй!"
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:75
#, python-format
msgid "Error"
msgstr "Алдаа"
#. module: google_base_account
#: view:google.login:0
msgid "Google login"
msgstr ""
#. module: google_base_account
#: model:ir.model,name:google_base_account.model_res_users
msgid "res.users"
msgstr "res.users"
#. module: google_base_account
#: field:google.login,password:0
msgid "Google Password"
msgstr ""
#. module: google_base_account
#: view:google.login:0
msgid "_Cancel"
msgstr "_Цуцлах"
#. module: google_base_account
#: view:res.users:0
msgid "Google Account"
msgstr ""
#. module: google_base_account
#: field:google.login,user:0
msgid "Google Username"
msgstr ""
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:29
#, python-format
msgid ""
"Please install gdata-python-client from http://code.google.com/p/gdata-"
"python-client/downloads/list"
msgstr ""
#. module: google_base_account
#: model:ir.model,name:google_base_account.model_google_login
msgid "Google Contact"
msgstr ""
#. module: google_base_account
#: view:google.login:0
msgid "_Login"
msgstr ""
#. module: google_base_account
#: constraint:res.users:0
msgid "The chosen company is not in the allowed companies for this user"
msgstr ""
#. module: google_base_account
#: field:res.users,gmail_password:0
msgid "Password"
msgstr ""
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:75
#, python-format
msgid "Authentication fail check the user and password !"
msgstr ""
#. module: google_base_account
#: view:google.login:0
msgid "ex: user@gmail.com"
msgstr ""

View File

@ -0,0 +1,121 @@
# Polish 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-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-11-02 14:30+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: 2012-11-03 05:04+0000\n"
"X-Generator: Launchpad (build 16218)\n"
#. module: google_base_account
#: field:res.users,gmail_user:0
msgid "Username"
msgstr ""
#. module: google_base_account
#: model:ir.actions.act_window,name:google_base_account.act_google_login_form
msgid "Google Login"
msgstr ""
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:29
#, python-format
msgid "Google Contacts Import Error!"
msgstr ""
#. module: google_base_account
#: view:res.users:0
msgid " Synchronization "
msgstr ""
#. module: google_base_account
#: sql_constraint:res.users:0
msgid "You can not have two users with the same login !"
msgstr ""
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:75
#, python-format
msgid "Error"
msgstr ""
#. module: google_base_account
#: view:google.login:0
msgid "Google login"
msgstr ""
#. module: google_base_account
#: model:ir.model,name:google_base_account.model_res_users
msgid "res.users"
msgstr "res.users"
#. module: google_base_account
#: field:google.login,password:0
msgid "Google Password"
msgstr ""
#. module: google_base_account
#: view:google.login:0
msgid "_Cancel"
msgstr ""
#. module: google_base_account
#: view:res.users:0
msgid "Google Account"
msgstr ""
#. module: google_base_account
#: field:google.login,user:0
msgid "Google Username"
msgstr ""
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:29
#, python-format
msgid ""
"Please install gdata-python-client from http://code.google.com/p/gdata-"
"python-client/downloads/list"
msgstr ""
"Zainstaluj gdata-python-client z http://code.google.com/p/gdata-python-"
"client/downloads/list"
#. module: google_base_account
#: model:ir.model,name:google_base_account.model_google_login
msgid "Google Contact"
msgstr ""
#. module: google_base_account
#: view:google.login:0
msgid "_Login"
msgstr ""
#. module: google_base_account
#: constraint:res.users:0
msgid "The chosen company is not in the allowed companies for this user"
msgstr ""
#. module: google_base_account
#: field:res.users,gmail_password:0
msgid "Password"
msgstr ""
#. module: google_base_account
#: code:addons/google_base_account/wizard/google_login.py:75
#, python-format
msgid "Authentication fail check the user and password !"
msgstr ""
#. module: google_base_account
#: view:google.login:0
msgid "ex: user@gmail.com"
msgstr "np: user@gmail.com"

View File

@ -28,11 +28,12 @@
'installable': True,
'auto_install': False,
'js': ['static/src/js/gdocs.js'],
'qweb': ['static/src/xml/gdocs.xml'],
'data': [
'security/ir.model.access.csv',
'res_config_user_view.xml'
],
'depends': ['google_base_account'],
'depends': ['google_base_account','document'],
'description': """
Module to attach a google document to any model.
================================================

View File

@ -17,7 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from datetime import datetime
from tools import DEFAULT_SERVER_DATETIME_FORMAT
from osv import osv, fields
from tools.translate import _
try:
@ -61,7 +62,8 @@ class google_docs_ir_attachment(osv.osv):
#login with the base account google module
client = self._auth(cr, uid, context=context)
# create the document in google docs
local_resource = gdata.docs.data.Resource(gdata.docs.data.DOCUMENT_LABEL)
title = "%s %s" % (context.get("name","Untitled Document."), datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT))
local_resource = gdata.docs.data.Resource(gdata.docs.data.DOCUMENT_LABEL,title=title)
#create a new doc in Google Docs
gdocs_resource = client.post(entry=local_resource, uri='https://docs.google.com/feeds/default/private/full/')
# create an ir.attachment into the db
@ -69,10 +71,12 @@ class google_docs_ir_attachment(osv.osv):
'res_model': res_model,
'res_id': res_id,
'type': 'url',
'name': _('Google Doc'),
'name': title,
'url': gdocs_resource.get_alternate_link().href,
}, context=context)
return gdocs_resource.resource_id.text
return {'resource_id': gdocs_resource.resource_id.text,
'title': title,
'url': gdocs_resource.get_alternate_link().href}
def copy_gdoc(self, cr, uid, res_model, res_id, name_gdocs, gdoc_template_id, context=None):
'''
@ -89,7 +93,7 @@ class google_docs_ir_attachment(osv.osv):
try:
original_resource = client.get_resource_by_id(gdoc_template_id)
#copy the document you choose in the configuration
copy_resource = client.copy_resource(original_resource, 'copy_%s' % original_resource.title.text)
copy_resource = client.copy_resource(original_resource, name_gdocs)
except:
raise osv.except_osv(_('Google Docs Error!'), _("Your resource id is not correct. You can find the id in the google docs URL."))
# create an ir.attachment
@ -114,7 +118,8 @@ class google_docs_ir_attachment(osv.osv):
a length of 1 element only (batch processing is not supported in the code, though nothing really prevent it)
:return: the google document object created
'''
assert len(ids) == 1, 'Creating google docs may only be done by one at a time'
if len(ids) != 1:
raise osv.except_osv(_('Google Docs Error!'), _("Creating google docs may only be done by one at a time."))
res_id = ids[0]
pool_ir_attachment = self.pool.get('ir.attachment')
pool_gdoc_config = self.pool.get('google.docs.config')
@ -125,7 +130,10 @@ class google_docs_ir_attachment(osv.osv):
google_docs_config = pool_gdoc_config.search(cr, uid, [('model_id', '=', res_model)], context=context)
if google_docs_config:
name_gdocs = pool_gdoc_config.browse(cr, uid, google_docs_config, context=context)[0].name_template
name_gdocs = name_gdocs % model_fields_dic
try:
name_gdocs = name_gdocs % model_fields_dic
except:
raise osv.except_osv(_('Key Error!'), _("Your Google Doc Name Pattern's key does not found in object."))
google_template_id = pool_gdoc_config.browse(cr, uid, google_docs_config[0], context=context).gdocs_resource_id
google_document = pool_ir_attachment.copy_gdoc(cr, uid, res_model, res_id, name_gdocs, google_template_id, context=context)
else:
@ -138,15 +146,15 @@ class config(osv.osv):
_columns = {
'model_id': fields.many2one('ir.model', 'Model', required=True),
'gdocs_resource_id': fields.char('Google Resource ID to Use as Template', size=64,help='''
'gdocs_resource_id': fields.char('Google Resource ID to Use as Template', size=64, help='''
This is the id of the template document, on google side. You can find it thanks to its URL:
*for a text document with url like `https://docs.google.com/a/openerp.com/document/d/123456789/edit`, the ID is `document:123456789`
*for a spreadsheet document with url like `https://docs.google.com/a/openerp.com/spreadsheet/ccc?key=123456789#gid=0`, the ID is `spreadsheet:123456789`
*for a presentation (slide show) document with url like `https://docs.google.com/a/openerp.com/presentation/d/123456789/edit#slide=id.p`, the ID is `presentation:123456789`
*for a drawing document with url like `https://docs.google.com/a/openerp.com/drawings/d/123456789/edit`, the ID is `drawings:123456789`
...
'''),
'name_template': fields.char('Google Doc Name Pattern', size=64, help='Choose how the new google docs will be named, on google side'),
''', required=True),
'name_template': fields.char('Google Doc Name Pattern', size=64, help='Choose how the new google docs will be named, on google side. Eg. gdoc_%(field_name)s', required=True),
}
_defaults = {

Some files were not shown because too many files have changed in this diff Show More