[MERGE]merge with trunk

bzr revid: kbh@tinyerp.com-20121109052919-q1oo1us9il2jrqf4
This commit is contained in:
Khushboo Bhatt (Open ERP) 2012-11-09 10:59:19 +05:30
commit d251e8e63f
191 changed files with 22184 additions and 10238 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

@ -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

@ -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);
});
},

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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

@ -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

@ -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

@ -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

@ -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

@ -30,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" title="Reload data to check changes.">
<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">

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

@ -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

@ -619,9 +619,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'):
@ -685,19 +685,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

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

@ -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

@ -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

@ -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

@ -510,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"/>
@ -519,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'}"/>

21
addons/fleet/__init__.py Normal file
View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import 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-09 04:39+0000\n"
"X-Generator: Launchpad (build 16250)\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

@ -16,9 +16,9 @@ var _t = instance.web._t,
var view = self.getParent();
var ids = ( view.fields_view.type != "form" )? view.groups.get_selection().ids : [ view.datarecord.id ];
if( !_.isEmpty(ids) ){
view.sidebar_context().then(function (context) {
view.sidebar_context().done(function (context) {
var ds = new instance.web.DataSet(this, 'ir.attachment', context);
ds.call('google_doc_get', [view.dataset.model, ids, context]).then(function(r) {
ds.call('google_doc_get', [view.dataset.model, ids, context]).done(function(r) {
if (r == 'False') {
var params = {
error: response,

View File

@ -24,7 +24,7 @@
'version': '1.1',
'author': 'OpenERP SA',
'category': 'Human Resources',
'sequence': 12,
'sequence': 21,
'website': 'http://www.openerp.com',
'summary': 'Jobs, Departments, Employees Details',
'description': """

View File

@ -57,7 +57,7 @@ openerp.hr_attendance = function (instance) {
var employee = new instance.web.DataSetSearch(self, 'hr.employee', self.session.user_context, [
['user_id', '=', self.session.uid]
]);
return employee.read_slice(['id', 'name', 'state', 'last_sign', 'attendance_access']).pipe(function (res) {
return employee.read_slice(['id', 'name', 'state', 'last_sign', 'attendance_access']).then(function (res) {
if (_.isEmpty(res) )
return;
if (res[0].attendance_access == false){
@ -75,7 +75,7 @@ openerp.hr_attendance = function (instance) {
do_update: function () {
this._super();
var self = this;
this.update_promise = this.update_promise.then(function () {
this.update_promise = this.update_promise.done(function () {
if (self.attendanceslider)
return;
self.attendanceslider = new instance.hr_attendance.AttendanceSlider(self);

View File

@ -24,6 +24,7 @@
'version': '0.1',
'author': 'OpenERP SA',
'category': 'Human Resources',
'sequence': 31,
'website': 'http://www.openerp.com',
'summary': 'Periodical Evaluations, Appraisals, Surveys',
'images': ['images/hr_evaluation_analysis.jpeg','images/hr_evaluation.jpeg'],

View File

@ -291,6 +291,7 @@ survey_request()
class hr_evaluation_interview(osv.osv):
_name = 'hr.evaluation.interview'
_inherits = {'survey.request': 'request_id'}
_inherit = 'mail.thread'
_rec_name = 'request_id'
_description = 'Appraisal Interview'
_columns = {

View File

@ -266,7 +266,7 @@
Each employee may be assigned an Appraisal Plan. Such a plan
defines the frequency and the way you manage your periodic
personnel evaluation. You will be able to define steps and
attach interviews to each step. OpenERP manages all kind of
attach interviews to each step. OpenERP manages all kinds of
evaluations: bottom-up, top-down, self-evaluation and final
evaluation by the manager.
</p>

View File

@ -24,7 +24,7 @@
'name': 'Expense Management',
'version': '1.0',
'category': 'Human Resources',
'sequence': 30,
'sequence': 29,
'summary': 'Expenses Validation, Invoicing',
'description': """
Manage expenses by Employees

View File

@ -123,8 +123,8 @@
<separator string="Notes"/>
<field name="note" placeholder="Free Notes"/>
</div>
<group class="oe_subtotal_footer">
<field name="amount" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<group class="oe_subtotal_footer oe_right">
<field name="amount" widget="monetary" options="{'currency_field': 'currency_id'}" class="oe_subtotal_footer_separator"/>
</group>
</group>
</page>
@ -211,8 +211,7 @@
<field name="search_view_id" ref="product.product_search_form_view"/>
</record>
<menuitem id="menu_product_hr_config_expense" name="Expenses" parent="hr.menu_hr_configuration"/>
<menuitem id="menu_hr_product" name="Products" parent="menu_product_hr_config_expense" action="hr_expense_product"/>
<menuitem id="menu_hr_product" name="Type of Expenses" parent="hr.menu_hr_configuration" action="hr_expense_product"/>
<menuitem id="next_id_49" name="Expenses" sequence="15" parent="hr.menu_hr_root"/>
<menuitem action="expense_all" id="menu_expense_all" name="Expenses" parent="next_id_49"/>

View File

@ -25,7 +25,7 @@
'version': '1.5',
'author': 'OpenERP SA',
'category': 'Human Resources',
'sequence': 28,
'sequence': 27,
'summary': 'Holidays, Allocation and Leave Requests',
'website': 'http://www.openerp.com',
'description': """

View File

@ -27,6 +27,7 @@ from operator import itemgetter
import math
import netsvc
import tools
from osv import fields, osv
from tools.translate import _
@ -112,6 +113,13 @@ class hr_holidays(osv.osv):
result[hol.id] = hol.number_of_days_temp
return result
def _check_date(self, cr, uid, ids):
for holiday in self.browse(cr, uid, ids):
holiday_ids = self.search(cr, uid, [('date_from', '<=', holiday.date_to), ('date_to', '>=', holiday.date_from), ('employee_id', '=', holiday.employee_id.id), ('id', '<>', holiday.id)])
if holiday_ids:
return False
return True
_columns = {
'name': fields.char('Description', size=64),
'state': fields.selection([('draft', 'To Submit'), ('cancel', 'Cancelled'),('confirm', 'To Approve'), ('refuse', 'Refused'), ('validate1', 'Second Approval'), ('validate', 'Approved')],
@ -145,12 +153,16 @@ class hr_holidays(osv.osv):
'user_id': lambda obj, cr, uid, context: uid,
'holiday_type': 'employee'
}
_constraints = [
(_check_date, 'You can not have 2 leaves that overlaps on same day!', ['date_from','date_to']),
]
_sql_constraints = [
('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))", "The employee or employee category of this request is missing."),
('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be before the end date !"),
('date_check', "CHECK ( number_of_days_temp >= 0 )", "The number of days must be greater than 0 !"),
('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be anterior to the end date."),
('date_check', "CHECK ( number_of_days_temp >= 0 )", "The number of days must be greater than 0."),
]
def _create_resource_leave(self, cr, uid, leaves, context=None):
'''This method will create entry in resource calendar leave object at the time of holidays validated '''
obj_res_leave = self.pool.get('resource.calendar.leaves')
@ -182,6 +194,13 @@ class hr_holidays(osv.osv):
}
return result
def onchange_employee(self, cr, uid, ids, employee_id):
result = {'value': {'department_id': False}}
if employee_id:
employee = self.pool.get('hr.employee').browse(cr, uid, employee_id)
result['value'] = {'department_id': employee.department_id.id}
return result
# TODO: can be improved using resource calendar method
def _get_number_of_days(self, date_from, date_to):
"""Returns a float equals to the timedelta between two dates given as string."""
@ -196,22 +215,62 @@ class hr_holidays(osv.osv):
def unlink(self, cr, uid, ids, context=None):
for rec in self.browse(cr, uid, ids, context=context):
if rec.state not in ['draft', 'cancel', 'confirm']:
raise osv.except_osv(_('Warning!'),_('You cannot delete a leave which is in %s state!')%(rec.state))
raise osv.except_osv(_('Warning!'),_('You cannot delete a leave which is in %s state.')%(rec.state))
return super(hr_holidays, self).unlink(cr, uid, ids, context)
def onchange_date_from(self, cr, uid, ids, date_to, date_from):
result = {}
if date_to and date_from:
"""
If there are no date set for date_to, automatically set one 8 hours later than
the date_from.
Also update the number_of_days.
"""
# date_to has to be greater than date_from
if (date_from and date_to) and (date_from > date_to):
raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.'))
result = {'value': {}}
# No date_to set so far: automatically compute one 8 hours later
if date_from and not date_to:
date_to_with_delta = datetime.datetime.strptime(date_from, tools.DEFAULT_SERVER_DATETIME_FORMAT) + datetime.timedelta(hours=8)
result['value']['date_to'] = str(date_to_with_delta)
# Compute and update the number of days
if (date_to and date_from) and (date_from <= date_to):
diff_day = self._get_number_of_days(date_from, date_to)
result['value'] = {
'number_of_days_temp': round(math.floor(diff_day))+1
}
return result
result['value'] = {
'number_of_days_temp': 0,
}
result['value']['number_of_days_temp'] = round(math.floor(diff_day))+1
else:
result['value']['number_of_days_temp'] = 0
return result
def onchange_date_to(self, cr, uid, ids, date_to, date_from):
"""
Update the number_of_days.
"""
# date_to has to be greater than date_from
if (date_from and date_to) and (date_from > date_to):
raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.'))
result = {'value': {}}
# Compute and update the number of days
if (date_to and date_from) and (date_from <= date_to):
diff_day = self._get_number_of_days(date_from, date_to)
result['value']['number_of_days_temp'] = round(math.floor(diff_day))+1
else:
result['value']['number_of_days_temp'] = 0
return result
def write(self, cr, uid, ids, vals, context=None):
check_fnct = self.pool.get('hr.holidays.status').check_access_rights
for holiday in self.browse(cr, uid, ids, context=context):
if holiday.state in ('validate','validate1') and not check_fnct(cr, uid, 'write', raise_exception=False):
raise osv.except_osv(_('Warning!'),_('You cannot modify a leave request that has been approved. Contact a human resource manager.'))
return super(hr_holidays, self).write(cr, uid, ids, vals, context=context)
def set_to_draft(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {
'state': 'draft',
@ -430,10 +489,10 @@ class hr_employee(osv.osv):
def _get_remaining_days(self, cr, uid, ids, name, args, context=None):
cr.execute("""SELECT
sum(h.number_of_days) as days,
h.employee_id
h.employee_id
from
hr_holidays h
join hr_holidays_status s on (s.id=h.holiday_status_id)
join hr_holidays_status s on (s.id=h.holiday_status_id)
where
h.state='validate' and
s.limit=False and
@ -448,9 +507,9 @@ class hr_employee(osv.osv):
remaining[employee_id] = 0.0
return remaining
def _get_leave_status(self, cr, uid, ids, name, args, context=None):
def _get_leave_status(self, cr, uid, ids, name, args, context=None):
holidays_obj = self.pool.get('hr.holidays')
holidays_id = holidays_obj.search(cr, uid,
holidays_id = holidays_obj.search(cr, uid,
[('employee_id', 'in', ids), ('date_from','<=',time.strftime('%Y-%m-%d %H:%M:%S')),
('date_to','>=',time.strftime('%Y-%m-%d 23:59:59')),('type','=','remove'),('state','not in',('cancel','refuse'))],
context=context)
@ -476,7 +535,7 @@ class hr_employee(osv.osv):
('validate1', 'Waiting Second Approval'), ('validate', 'Approved'), ('cancel', 'Cancelled')]),
'current_leave_id': fields.function(_get_leave_status, multi="leave_status", string="Current Leave Type",type='many2one', relation='hr.holidays.status'),
'leave_date_from': fields.function(_get_leave_status, multi='leave_status', type='date', string='From Date'),
'leave_date_to': fields.function(_get_leave_status, multi='leave_status', type='date', string='To Date'),
'leave_date_to': fields.function(_get_leave_status, multi='leave_status', type='date', string='To Date'),
}
hr_employee()

View File

@ -34,8 +34,8 @@
<record model="hr.holidays" id="hr_holidays_employee1_vc">
<field name="name">Summer Vacation</field>
<field name="holiday_status_id" ref="holiday_status_unpaid"/>
<field eval="time.strftime('%Y-%m-20')" name="date_from"/>
<field eval="time.strftime('%Y-%m-22')" name="date_to"/>
<field eval="time.strftime('%Y-%m-23')" name="date_from"/>
<field eval="time.strftime('%Y-%m-25')" name="date_to"/>
<field name="type">add</field>
<field name="state">draft</field>
<field name="number_of_days_temp">7</field>
@ -45,8 +45,8 @@
<record model="hr.holidays" id="hr_holidays_employee1_int_tour">
<field name="name">International Tour</field>
<field name="holiday_status_id" ref="holiday_status_comp"/>
<field eval="time.strftime('%Y-%m-20')" name="date_from"/>
<field eval="time.strftime('%Y-%m-22')" name="date_to"/>
<field eval="time.strftime('%Y-%m-26')" name="date_from"/>
<field eval="time.strftime('%Y-%m-28')" name="date_to"/>
<field name="type">add</field>
<field name="number_of_days_temp">7</field>
<field name="employee_id" ref="hr.employee_fp"/>

View File

@ -13,9 +13,9 @@
<record id="action_holidays_unread" model="ir.values">
<field name="name">action_holidays_unread</field>
<field name="action_id" ref="actions_server_holidays_unread"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_holidays_unread'))" />
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_holidays_unread'))"/>
<field name="key">action</field>
<field name="model_id" ref="model_hr_holidays" />
<field name="model_id" ref="model_hr_holidays"/>
<field name="model">hr.holidays</field>
<field name="key2">client_action_multi</field>
</record>
@ -31,9 +31,9 @@
<record id="action_holidays_read" model="ir.values">
<field name="name">action_holidays_read</field>
<field name="action_id" ref="actions_server_holidays_read"/>
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_holidays_read'))" />
<field name="value" eval="'ir.actions.server,' + str(ref('actions_server_holidays_read'))"/>
<field name="key">action</field>
<field name="model_id" ref="model_hr_holidays" />
<field name="model_id" ref="model_hr_holidays"/>
<field name="model">hr.holidays</field>
<field name="key2">client_action_multi</field>
</record>
@ -83,7 +83,7 @@
</field>
</record>
<record model="ir.ui.view" id="edit_holiday_new">
<record id="edit_holiday_new" model="ir.ui.view">
<field name="name">Leave Request</field>
<field name="model">hr.holidays</field>
<field name="priority">1</field>
@ -93,7 +93,7 @@
<button string="Approve" name="validate" states="confirm" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
<button string="Validate" name="second_validate" states="validate1" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
<button string="Refuse" name="refuse" states="confirm,validate1,validate" type="workflow" groups="base.group_hr_user"/>
<button string="Reset to New" name="set_to_draft" states="refuse" type="object" groups="base.group_hr_user" />
<button string="Reset to New" name="set_to_draft" states="refuse" type="object" groups="base.group_hr_user"/>
<field name="state" widget="statusbar" statusbar_visible="draft,confirm,validate" statusbar_colors='{"confirm":"blue","validate1":"blue","refuse":"red"}'/>
</header>
<sheet string="Leave Request">
@ -101,11 +101,11 @@
<group>
<field name="name" attrs="{'readonly':[('state','!=','draft'),('state','!=','confirm')]}"/>
<field name="holiday_status_id" context="{'employee_id':employee_id}"/>
<label for="number_of_days_temp" string="Duration"/>
<label for="number_of_days_temp" string="Duration" help="The default duration interval between the start date and the end date is 8 hours. Feel free to adapt it to your needs."/>
<div>
<group col="3">
<field name="date_from" nolabel="1" on_change="onchange_date_from(date_to, date_from)" required="1" class="oe_inline"/><label string="-" class="oe_inline" />
<field name="date_to" nolabel="1" on_change="onchange_date_from(date_to, date_from)" required="1" class="oe_inline"/>
<field name="date_from" nolabel="1" on_change="onchange_date_from(date_to, date_from)" required="1" class="oe_inline"/><label string="-" class="oe_inline"/>
<field name="date_to" nolabel="1" on_change="onchange_date_to(date_to, date_from)" required="1" class="oe_inline"/>
</group>
<div>
<field name="number_of_days_temp" class="oe_inline"/> days
@ -115,7 +115,7 @@
</group>
<group>
<field name="holiday_type" on_change="onchange_type(holiday_type)" attrs="{'readonly':[('state','!=','draft')]}" width="130" string="Mode" groups="base.group_hr_user"/>
<field name="employee_id" attrs="{'required':[('holiday_type','=','employee')],'invisible':[('holiday_type','=','category')]}" groups="base.group_hr_user"/>
<field name="employee_id" attrs="{'required':[('holiday_type','=','employee')],'invisible':[('holiday_type','=','category')]}" on_change="onchange_employee(employee_id)" groups="base.group_hr_user"/>
<field name="department_id" attrs="{'readonly':[('holiday_type','=','category')]}" groups="base.group_hr_user"/>
</group>
</group>
@ -138,7 +138,7 @@
<button string="Approve" name="validate" states="confirm" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
<button string="Validate" name="second_validate" states="validate1" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
<button string="Refuse" name="refuse" states="confirm,validate,validate1" type="workflow" groups="base.group_hr_user"/>
<button string="Reset to New" name="set_to_draft" states="cancel,refuse" type="object" groups="base.group_hr_user" />
<button string="Reset to New" name="set_to_draft" states="cancel,refuse" type="object" groups="base.group_hr_user"/>
<field name="state" widget="statusbar" statusbar_visible="draft,confirm,validate" statusbar_colors='{"confirm":"blue","validate1":"blue","refuse":"red"}'/>
</header>
<sheet>
@ -233,7 +233,6 @@
</field>
</record>
<record model="ir.ui.view" id="view_holiday">
<field name="name">hr.holidays.tree</field>
<field name="model">hr.holidays</field>
@ -251,7 +250,6 @@
<field name="holiday_status_id" invisible="1"/>
<field name="manager_id" invisible="1"/>
<field name="user_id" invisible="1"/>
<!--field name="type"/-->
</tree>
</field>
</record>
@ -268,7 +266,7 @@
<field name="search_view_id" ref="view_hr_holidays_filter"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new leave request.
Click to create a new leave request.
</p><p>
Once you have recorded your leave request, it will be sent
to a manager for validation. Be sure to set the right leave
@ -298,7 +296,7 @@
<field name="view_id" ref="view_holiday_new_calendar"/>
<field name="act_window_id" ref="open_ask_holidays"/>
</record>
<menuitem name="My Leave Requests" parent="menu_open_ask_holidays" id="menu_open_ask_holidays_new" action="open_ask_holidays"/>
<record model="ir.actions.act_window" id="request_approve_holidays">
@ -392,7 +390,7 @@
<menuitem name="Leaves Summary" parent="menu_open_ask_holidays" id="menu_open_company_allocation" action="open_company_allocation" sequence="40"/>
<!-- holidays status -->
<!-- Holidays status -->
<record id="view_holidays_status_filter" model="ir.ui.view">
<field name="name">hr.holidays.status.filter</field>
<field name="model">hr.holidays.status</field>
@ -443,6 +441,7 @@
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_holiday_status_normal_tree">
<field name="name">hr.holidays.status.normal.tree</field>
<field name="model">hr.holidays.status</field>
@ -467,7 +466,7 @@
</record>
<record id="open_view_holiday_status" model="ir.actions.act_window">
<field name="name">Leave Type</field>
<field name="name">Leave Types</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">hr.holidays.status</field>
<field name="view_type">form</field>
@ -477,9 +476,9 @@
</record>
<menuitem sequence="3" id="hr.menu_open_view_attendance_reason_config" parent="hr.menu_hr_configuration" name="Leaves"/>
<menuitem name="Leave Type" action="open_view_holiday_status" id="menu_open_view_holiday_status" parent="hr.menu_hr_configuration" sequence="10" />
<menuitem name="Leave Type" action="open_view_holiday_status" id="menu_open_view_holiday_status" parent="hr.menu_hr_configuration" sequence="10"/>
<!-- holiday on resource leave -->
<!-- Holiday on resource leave -->
<record id="resource_calendar_leave_form_inherit" model="ir.ui.view">
<field name="name">resource.calendar.leaves.form.inherit</field>
<field name="model">resource.calendar.leaves</field>
@ -491,7 +490,7 @@
</field>
</record>
<!-- Shortcuts -->
<!-- Shortcuts -->
<record id="act_hr_employee_holiday_request" model="ir.actions.act_window">
<field name="name">Leaves</field>
<field name="type">ir.actions.act_window</field>
@ -504,8 +503,7 @@
<field name="view_id" eval="view_holiday"/>
</record>
<!-- Assing leave -->
<!-- Assing leave -->
<record id="hr_holidays_leaves_assign_tree_view" model="ir.ui.view">
<field name="name">hr.employee.leave.tree</field>
<field name="model">hr.employee</field>
@ -534,7 +532,6 @@
</record>
<!-- Hr employee inherit Legal Leaves -->
<record id="view_employee_form_leave_inherit" model="ir.ui.view">
<field name="name">hr.employee.leave.form.inherit</field>
<field name="model">hr.employee</field>

View File

@ -312,12 +312,7 @@ class hr_payslip(osv.osv):
company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
default.update({
'line_ids': [],
'move_ids': [],
'move_line_ids': [],
'company_id': company_id,
'period_id': False,
'basic_before_leaves': 0.0,
'basic_amount': 0.0,
'number': '',
'payslip_run_id': False,
'paid': False,

View File

@ -24,7 +24,7 @@
'name': 'Recruitment Process',
'version': '1.0',
'category': 'Human Resources',
'sequence': 24,
'sequence': 25,
'summary': 'Jobs, Recruitment, Applications, Job Interviews',
'description': """
Manage job positions and the recruitment process

View File

@ -258,6 +258,17 @@ class hr_applicant(base_stage, osv.Model):
stage_id = stage_ids and stage_ids[0] or False
return {'value': {'stage_id': stage_id}}
def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
data = {'partner_phone': False,
'partner_mobile': False,
'email_from': False}
if partner_id:
addr = self.pool.get('res.partner').browse(cr, uid, partner_id, context)
data.update({'partner_phone': addr.phone,
'partner_mobile': addr.mobile,
'email_from': addr.email})
return {'value': data}
def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
""" Override of the base.stage method
Parameter of the stage search taken from the lead:

View File

@ -135,7 +135,7 @@
<group>
<group>
<field name="partner_id"
on_change="onchange_partner_id(partner_id, email_from)"/>
on_change="onchange_partner_id(partner_id)"/>
<field name="email_from" widget="email"/>
<field name="partner_phone"/>
<field name="partner_mobile"/>

View File

@ -16,7 +16,7 @@ openerp.hr_recruitment = function(openerp) {
// Find their matching names
var dataset = new openerp.web.DataSetSearch(self, 'hr.applicant_category', self.session.context, [['id', 'in', _.uniq(categ_ids)]]);
dataset.read_slice(['id', 'name']).then(function(result) {
dataset.read_slice(['id', 'name']).done(function(result) {
_.each(result, function(v, k) {
// Set the proper value in the DOM and display the element
self.$el.find('span[data-categ_id=' + v.id + ']').text(v.name);

View File

@ -15,7 +15,7 @@
applicant_ids = self.search(cr, uid, [('email_from','=', 'Mr. Richard Anderson <Richard_Anderson@yahoo.com>')])
assert applicant_ids, "Applicant is not created after getting the mail"
applicant = self.browse(cr, uid, applicant_ids[0], context=context)
resume_ids = self.pool.get('ir.attachment').search(cr, uid, [('datas_fname','=','resume.doc'),('res_model','=',self._name),('res_id','=',applicant.id)])
resume_ids = self.pool.get('ir.attachment').search(cr, uid, [('datas_fname','=','resume.pdf'),('res_model','=',self._name),('res_id','=',applicant.id)])
assert applicant.name == "Application for the post of Jr.application Programmer.", "Applicant name does not match."
assert applicant.stage_id.id == ref('hr_recruitment.stage_job1'), "Stage should be 'Initial qualification' and is '%s'." % (applicant.stage_id.name)
assert applicant.state == "draft", "Applicant state should be 'draft'."

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
'name': 'Timesheets',
'version': '1.0',
'category': 'Human Resources',
'sequence': 23,
'description': """
This module implements a timesheet system.
==========================================

View File

@ -7,7 +7,7 @@
<field name="factor">50.0</field>
</record>
<record id="timesheet_invoice_factor3" model="hr_timesheet_invoice.factor">
<field name="name">Gratis</field>
<field name="name">Free of charge</field>
<field name="customer_name">Offered developments</field>
<field name="factor">100.0</field>
</record>

View File

@ -24,7 +24,7 @@
'name': 'Timesheets',
'version': '1.0',
'category': 'Human Resources',
'sequence': 16,
'sequence': 24,
'summary': 'Timesheets, Attendances, Activities',
'description': """
Record and validate timesheets and attendances easily

View File

@ -46,7 +46,7 @@ openerp.hr_timesheet_sheet = function(instance) {
var commands = this.field_manager.get_field_value("timesheet_ids");
this.res_o2m_drop.add(new instance.web.Model(this.view.model).call("resolve_2many_commands", ["timesheet_ids", commands, [],
new instance.web.CompoundContext()]))
.then(function(result) {
.done(function(result) {
self.querying = true;
self.set({sheets: result});
self.querying = false;
@ -57,7 +57,7 @@ openerp.hr_timesheet_sheet = function(instance) {
if (self.querying)
return;
self.updating = true;
self.field_manager.set_values({timesheet_ids: self.get("sheets")}).then(function() {
self.field_manager.set_values({timesheet_ids: self.get("sheets")}).done(function() {
self.updating = false;
});
},
@ -85,7 +85,7 @@ openerp.hr_timesheet_sheet = function(instance) {
var default_get;
return this.render_drop.add(new instance.web.Model("hr.analytic.timesheet").call("default_get", [
['account_id','general_account_id', 'journal_id','date','name','user_id','product_id','product_uom_id','to_invoice','amount','unit_amount'],
new instance.web.CompoundContext({'user_id': self.get('user_id')})]).pipe(function(result) {
new instance.web.CompoundContext({'user_id': self.get('user_id')})]).then(function(result) {
default_get = result;
// calculating dates
dates = [];
@ -108,9 +108,9 @@ openerp.hr_timesheet_sheet = function(instance) {
var account_ids = _.map(_.keys(accounts), function(el) { return el === "false" ? false : Number(el) });
return new instance.web.Model("hr.analytic.timesheet").call("multi_on_change_account_id", [[], account_ids,
new instance.web.CompoundContext({'user_id': self.get('user_id')})]).pipe(function(accounts_defaults) {
new instance.web.CompoundContext({'user_id': self.get('user_id')})]).then(function(accounts_defaults) {
accounts = _(accounts).chain().map(function(lines, account_id) {
account_defaults = _.extend({}, default_get, accounts_defaults[account_id]);
account_defaults = _.extend({}, default_get, (accounts_defaults[account_id] || {}).value || {});
// group by days
account_id = account_id === "false" ? false : Number(account_id);
var index = _.groupBy(lines, "date");
@ -136,7 +136,7 @@ openerp.hr_timesheet_sheet = function(instance) {
// we need the name_get of the analytic accounts
return new instance.web.Model("account.analytic.account").call("name_get", [_.pluck(accounts, "account"),
new instance.web.CompoundContext()]).pipe(function(result) {
new instance.web.CompoundContext()]).then(function(result) {
account_names = {};
_.each(result, function(el) {
account_names[el[0]] = el[1];
@ -146,7 +146,7 @@ openerp.hr_timesheet_sheet = function(instance) {
});
});;
});
})).pipe(function(result) {
})).then(function(result) {
// we put all the gathered data in self, then we render
self.dates = dates;
self.accounts = accounts;
@ -222,7 +222,7 @@ openerp.hr_timesheet_sheet = function(instance) {
return;
}
var ops = self.generate_o2m_value();
new instance.web.Model("hr.analytic.timesheet").call("on_change_account_id", [[], id]).pipe(function(res) {
new instance.web.Model("hr.analytic.timesheet").call("on_change_account_id", [[], id]).then(function(res) {
var def = _.extend({}, self.default_get, res.value, {
name: self.description_line,
unit_amount: 0,

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -0,0 +1,136 @@
# 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-08 16:01+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-09 04:39+0000\n"
"X-Generator: Launchpad (build 16250)\n"
#. module: l10n_fr_rib
#: constraint:res.partner.bank:0
msgid ""
"\n"
"Please define BIC/Swift code on bank for bank type IBAN Account to make "
"valid payments"
msgstr ""
"\n"
"Por favor defina el código BIC/Swift del banco para una cuenta de tipo IBAN "
"para realizar pagos válidos"
#. module: l10n_fr_rib
#: model:res.partner.bank.type,name:l10n_fr_rib.bank_rib
msgid "RIB and optional IBAN"
msgstr "CC e IBAN opcional"
#. module: l10n_fr_rib
#: field:res.partner.bank,rib_acc_number:0
msgid "RIB account number"
msgstr "Número de la cuenta"
#. module: l10n_fr_rib
#: field:res.partner.bank,bank_code:0
msgid "Bank Code"
msgstr "Código de banco"
#. module: l10n_fr_rib
#: code:addons/l10n_fr_rib/bank.py:54
#, python-format
msgid "The RIB key %s does not correspond to the other codes: %s %s %s."
msgstr "La clave de la CC %s no se corresponde con otros códigos: %s %s %s."
#. module: l10n_fr_rib
#: model:res.partner.bank.type.field,name:l10n_fr_rib.rib_office_field
msgid "office"
msgstr "oficina"
#. module: l10n_fr_rib
#: field:res.bank,rib_code:0
msgid "RIB Bank Code"
msgstr "Código CC"
#. module: l10n_fr_rib
#: code:addons/l10n_fr_rib/bank.py:58
#, python-format
msgid "The IBAN %s is not valid."
msgstr "El IBAN %s no es válido."
#. module: l10n_fr_rib
#: model:ir.model,name:l10n_fr_rib.model_res_partner_bank
msgid "Bank Accounts"
msgstr "Cuentas bancarias"
#. module: l10n_fr_rib
#: field:res.partner.bank,office:0
msgid "Office Code"
msgstr "Código de oficina"
#. module: l10n_fr_rib
#: model:res.partner.bank.type.field,name:l10n_fr_rib.rib_bic_field
msgid "bank_bic"
msgstr "Número BIC"
#. module: l10n_fr_rib
#: model:res.partner.bank.type.field,name:l10n_fr_rib.rib_bank_code_field
msgid "bank_code"
msgstr "código bancario"
#. module: l10n_fr_rib
#: model:res.partner.bank.type.field,name:l10n_fr_rib.rib_key_field
msgid "key"
msgstr "clave"
#. module: l10n_fr_rib
#: model:res.partner.bank.type.field,name:l10n_fr_rib.rib_rib_acc_number_field
msgid "rib_acc_number"
msgstr "Número CC"
#. module: l10n_fr_rib
#: help:res.partner.bank,key:0
msgid ""
"The key is a number allowing to check the correctness of the other codes."
msgstr ""
"La clave es un número que permite comprobar si el resto de códigos son "
"correctos."
#. module: l10n_fr_rib
#: field:res.partner.bank,key:0
msgid "Key"
msgstr "Clave"
#. module: l10n_fr_rib
#: code:addons/l10n_fr_rib/bank.py:53
#: code:addons/l10n_fr_rib/bank.py:58
#, python-format
msgid "Error"
msgstr "Error"
#. module: l10n_fr_rib
#: model:res.partner.bank.type,format_layout:l10n_fr_rib.bank_rib
msgid "%(bank_name)s: %(bank_code)s %(office)s %(rib_acc_number)s %(key)s"
msgstr "%(bank_name)s: %(bank_code)s %(office)s %(rib_acc_number)s %(key)s"
#. module: l10n_fr_rib
#: constraint:res.partner.bank:0
msgid "The RIB and/or IBAN is not valid"
msgstr "La CC y/o IBAN no es válida"
#. module: l10n_fr_rib
#: model:ir.model,name:l10n_fr_rib.model_res_bank
msgid "Bank"
msgstr "Banco"
#. module: l10n_fr_rib
#: model:res.partner.bank.type.field,name:l10n_fr_rib.rib_acc_number_field
msgid "acc_number"
msgstr "Número cuenta"

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -0,0 +1,177 @@
# 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 01:06+0000\n"
"PO-Revision-Date: 2012-11-08 14:29+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-09 04:39+0000\n"
"X-Generator: Launchpad (build 16250)\n"
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_fiscal_position_template
msgid "Template for Fiscal Position"
msgstr "Plantilla para posición fiscal"
#. module: l10n_multilang
#: sql_constraint:account.account:0
msgid "The code of the account must be unique per company !"
msgstr "¡El código de la cuenta debe ser único por compañía!"
#. module: l10n_multilang
#: constraint:account.account.template:0
msgid ""
"Configuration Error!\n"
"You can not define children to an account with internal type different of "
"\"View\"! "
msgstr ""
"Error de configuración!\n"
"¡No puede definir hijos para una cuenta con el tipo interno distinto de "
"\"Vista\"! "
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_analytic_journal
msgid "Analytic Journal"
msgstr "Diario analítico"
#. module: l10n_multilang
#: constraint:account.account.template:0
msgid "Error ! You can not create recursive account templates."
msgstr "¡Error! No puede crear plantillas de cuentas recursivas."
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_journal
msgid "Journal"
msgstr "Diario"
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_chart_template
msgid "Templates for Account Chart"
msgstr "Plantillas para el plan contable"
#. module: l10n_multilang
#: sql_constraint:account.tax:0
msgid "The description must be unique per company!"
msgstr "¡La descripción debe ser única por compañia!"
#. module: l10n_multilang
#: constraint:account.tax.code.template:0
msgid "Error ! You can not create recursive Tax Codes."
msgstr "¡Error! No puede crear códigos de impuestos recursivos."
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_tax_template
msgid "account.tax.template"
msgstr "Plantilla de impuestos"
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_tax
msgid "account.tax"
msgstr "Impuesto"
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_account
msgid "Account"
msgstr "Cuenta"
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_wizard_multi_charts_accounts
msgid "wizard.multi.charts.accounts"
msgstr "Asistente de plan de cuentas"
#. module: l10n_multilang
#: constraint:account.journal:0
msgid ""
"Configuration error! The currency chosen should be shared by the default "
"accounts too."
msgstr ""
"¡Error de configuración! La moneda elegida debería ser también la misma en "
"las cuentas por defecto"
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_account_template
msgid "Templates for Accounts"
msgstr "Plantillas para cuentas"
#. module: l10n_multilang
#: help:account.chart.template,spoken_languages:0
msgid ""
"State here the languages for which the translations of templates could be "
"loaded at the time of installation of this localization module and copied in "
"the final object when generating them from templates. You must provide the "
"language codes separated by ';'"
msgstr ""
"Indique aquí los idiomas para los que las traducciones de las plantillas "
"pueden ser cargadas en el momento de la instalación de este módulo de "
"localización y copiados en el objeto final cuando se generen desde las "
"plantillas. Debe proveer los códigos de idioma separados por ';'."
#. module: l10n_multilang
#: constraint:account.account:0
msgid "Error ! You can not create recursive accounts."
msgstr "¡Error! No se pueden crear cuentas recursivas."
#. module: l10n_multilang
#: constraint:account.account:0
msgid ""
"Configuration Error! \n"
"You can not select an account type with a deferral method different of "
"\"Unreconciled\" for accounts with internal type \"Payable/Receivable\"! "
msgstr ""
"¡Error de configuración! \n"
"¡No puede seleccionar un tipo de cuenta con un método de cierre diferente de "
"\"Reconciliado\" para las cuentas con tipo interno \"A pagar/A cobrar\"! "
#. module: l10n_multilang
#: sql_constraint:account.journal:0
msgid "The name of the journal must be unique per company !"
msgstr "¡El nombre del diaro debe ser único por compañía!"
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_analytic_account
msgid "Analytic Account"
msgstr "Cuenta analítica"
#. module: l10n_multilang
#: sql_constraint:account.journal:0
msgid "The code of the journal must be unique per company !"
msgstr "¡El código del diario debe ser único por compañía!"
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_fiscal_position
msgid "Fiscal Position"
msgstr "Posición fiscal"
#. module: l10n_multilang
#: constraint:account.account:0
msgid ""
"Configuration Error! \n"
"You can not define children to an account with internal type different of "
"\"View\"! "
msgstr ""
"¡Error de configuración! \n"
"¡No puede definir hijos en una cuenta con tipo interno distinto a \"Vista\"! "
#. module: l10n_multilang
#: constraint:account.analytic.account:0
msgid "Error! You can not create recursive analytic accounts."
msgstr "¡Error! No puede crear cuentas analíticas recursivas."
#. module: l10n_multilang
#: model:ir.model,name:l10n_multilang.model_account_tax_code_template
msgid "Tax Code Template"
msgstr "Plantilla códigos de impuestos"
#. module: l10n_multilang
#: field:account.chart.template,spoken_languages:0
msgid "Spoken Languages"
msgstr "Idiomas hablados"

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -641,11 +641,12 @@
<field name="account_paid_id" ref="a_wht_income"/>
<field name="type_tax_use">sale</field>
</record>
</data>
<!-- INSTALL ACTION -->
<data noupdate="1">
<!-- INSTALL ACTION -->
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>
</data>
</openerp><!-- vim: set fdm=marker : -->

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -1,5 +1,5 @@
<openerp>
<data>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

View File

@ -2,7 +2,7 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2004-2012 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
@ -20,7 +20,5 @@
##############################################################################
import lunch
import wizard
import report
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
import wizard

View File

@ -2,7 +2,7 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2004-2012 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
@ -22,31 +22,31 @@
{
'name': 'Lunch Orders',
'author': 'OpenERP SA',
'version': '0.1',
'depends': [],
'version': '0.2',
'depends': ['base'],
'category' : 'Tools',
'summary': 'Lunch Order, Meal, Food',
'description': """
The base module to manage lunch.
================================
keep track for the Lunch Order, Cash Moves, CashBox, Product. Apply Different
Category for the product.
""",
'data': [
'security/lunch_security.xml',
'security/ir.model.access.csv',
'wizard/lunch_order_cancel_view.xml',
'wizard/lunch_order_confirm_view.xml',
'wizard/lunch_cashbox_clean_view.xml',
'lunch_view.xml',
'lunch_report.xml',
'report/report_lunch_order_view.xml',
'lunch_installer_view.xml'
],
'demo': ['lunch_demo.xml'],
'test': ['test/test_lunch.yml', 'test/lunch_report.yml'],
'installable': True,
'images': ['images/cash_moves.jpeg','images/lunch_orders.jpeg','images/products.jpeg'],
}
Many companies order sandwiches, pizzas and other, from usual suppliers, for their employees to offer them more facilities.
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
However lunches management within the company requires proper administration especially when the number of employees or suppliers is important.
The Lunch Order module has been developed to make this management easier but also to offer employees more tools and usability.
In addition to a full meal and supplier management, this module offers the possibility to display warning and provides quick order selection based on employees preferences.
If you want to save your employees' time and avoid them to always have coins in their pockets, this module is essential.
""",
'data': ['security/lunch_security.xml','lunch_view.xml','wizard/lunch_order_view.xml','wizard/lunch_validation_view.xml','wizard/lunch_cancel_view.xml','lunch_report.xml',
'report/report_lunch_order_view.xml',
'security/ir.model.access.csv',],
'css':['static/src/css/lunch.css'],
'demo': ['lunch_demo.xml',],
'installable': True,
'application' : True,
'certificate' : '001292377792581874189',
'images': [],
}

View File

@ -19,234 +19,451 @@
#
##############################################################################
from xml.sax.saxutils import escape
import time
from osv import osv, fields
from datetime import datetime
from lxml import etree
import tools
from tools.translate import _
class lunch_category(osv.osv):
""" Lunch category """
_name = 'lunch.category'
_description = "Category"
_columns = {
'name': fields.char('Name', required=True, size=50),
}
_order = 'name'
lunch_category()
class lunch_product(osv.osv):
""" Lunch Product """
_name = 'lunch.product'
_description = "Lunch Product"
_columns = {
'name': fields.char('Name', size=50, required=True),
'category_id': fields.many2one('lunch.category', 'Category'),
'description': fields.text('Description', size=128, required=False),
'price': fields.float('Price', digits=(16,2)),
'active': fields.boolean('Active'),
}
_defaults = {
'active': lambda *a : True,
}
lunch_product()
class lunch_cashbox(osv.osv):
""" cashbox for Lunch """
_name = 'lunch.cashbox'
_description = "Cashbox for Lunch "
def amount_available(self, cr, uid, ids, field_name, arg, context=None):
""" count available amount
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of create menus IDs
@param context: A standard dictionary for contextual values """
cr.execute("SELECT box,sum(amount) from lunch_cashmove where active = 't' group by box")
amount = dict(cr.fetchall())
for i in ids:
amount.setdefault(i, 0)
return amount
_columns = {
'manager': fields.many2one('res.users', 'Manager'),
'name': fields.char('Name', size=30, required=True, unique = True),
'sum_remain': fields.function(amount_available, string='Total Remaining'),
}
lunch_cashbox()
class lunch_cashmove(osv.osv):
""" Move cash """
_name = 'lunch.cashmove'
_description = "Cash Move"
_columns = {
'name': fields.char('Description', size=128),
'user_cashmove': fields.many2one('res.users', 'User Name', required=True),
'amount': fields.float('Amount', digits=(16, 2)),
'box': fields.many2one('lunch.cashbox', 'Box Name', size=30, required=True),
'active': fields.boolean('Active'),
'create_date': fields.datetime('Creation Date', readonly=True),
}
_defaults = {
'active': lambda *a: True,
}
lunch_cashmove()
class lunch_order(osv.osv):
""" Apply lunch order """
class lunch_order(osv.Model):
"""
lunch order (contains one or more lunch order line(s))
"""
_name = 'lunch.order'
_description = "Lunch Order"
_rec_name = "user_id"
_description = 'Lunch Order'
def _price_get(self, cr, uid, ids, name, args, context=None):
def _price_get(self, cr, uid, ids, name, arg, context=None):
"""
get and sum the order lines' price
"""
result = dict.fromkeys(ids, 0)
for order in self.browse(cr, uid, ids, context=context):
result[order.id] = sum(order_line.product_id.price
for order_line in order.order_line_ids)
return result
""" Get Price of Product
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of Lunch orders IDs
@param context: A standard dictionary for contextual values """
def _fetch_orders_from_lines(self, cr, uid, ids, name, context=None):
"""
return the list of lunch orders to which belong the order lines `ids´
"""
result = set()
for order_line in self.browse(cr, uid, ids, context=context):
if order_line.order_id:
result.add(order_line.order_id.id)
return list(result)
res = {}
for price in self.browse(cr, uid, ids, context=context):
res[price.id] = price.product.price
def add_preference(self, cr, uid, ids, pref_id, context=None):
"""
create a new order line based on the preference selected (pref_id)
"""
assert len(ids) == 1
orderline_ref = self.pool.get('lunch.order.line')
prod_ref = self.pool.get('lunch.product')
order = self.browse(cr, uid, ids[0], context=context)
pref = orderline_ref.browse(cr, uid, pref_id, context=context)
new_order_line = {
'date': order.date,
'user_id': uid,
'product_id': pref.product_id.id,
'note': pref.note,
'order_id': order.id,
'price': pref.product_id.price,
'supplier': pref.product_id.supplier.id
}
return orderline_ref.create(cr, uid, new_order_line, context=context)
def _alerts_get(self, cr, uid, ids, name, arg, context=None):
"""
get the alerts to display on the order form
"""
result = {}
alert_msg = self._default_alerts_get(cr, uid, context=context)
for order in self.browse(cr, uid, ids, context=context):
if order.state == 'new':
result[order.id] = alert_msg
return result
def check_day(self, alert):
"""
This method is used by can_display_alert
to check if the alert day corresponds
to the current day
"""
today = datetime.now().isoweekday()
assert 1 <= today <= 7, "Should be between 1 and 7"
mapping = dict((idx, name) for idx, name in enumerate('monday tuestday wednesday thursday friday saturday sunday'.split()))
if today in mapping:
return mapping[today]
def can_display_alert(self, alert):
"""
This method check if the alert can be displayed today
"""
if alert.alter_type == 'specific':
#the alert is only activated on a specific day
return alert.specific_day == time.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
elif alert.alter_type == 'week':
#the alert is activated during some days of the week
return self.check_day(alert)
def _default_alerts_get(self, cr, uid, context=None):
"""
get the alerts to display on the order form
"""
alert_ref = self.pool.get('lunch.alert')
alert_ids = alert_ref.search(cr, uid, [], context=context)
alert_msg = []
for alert in alert_ref.browse(cr, uid, alert_ids, context=context):
#check if the address must be displayed today
if self.can_display_alert(alert):
#display the address only during its active time
mynow = fields.datetime.context_timestamp(cr, uid, datetime.now(), context=context)
hour_to = int(alert.active_to)
min_to = int((alert.active_to - hour_to) * 60)
to_alert = datetime.strptime(str(hour_to) + ":" + str(min_to), "%H:%M")
hour_from = int(alert.active_from)
min_from = int((alert.active_from - hour_from) * 60)
from_alert = datetime.strptime(str(hour_from) + ":" + str(min_from), "%H:%M")
if mynow.time() >= from_alert.time() and mynow.time() <= to_alert.time():
alert_msg.append(alert.message)
return '\n'.join(alert_msg)
def onchange_price(self, cr, uid, ids, order_line_ids, context=None):
"""
Onchange methode that refresh the total price of order
"""
res = {'value': {'total': 0.0}}
order_line_ids = self.resolve_o2m_commands_to_record_dicts(cr, uid, "order_line_ids", order_line_ids, ["price"], context=context)
if order_line_ids:
tot = 0.0
product_ref = self.pool.get("lunch.product")
for prod in order_line_ids:
if 'product_id' in prod:
tot += product_ref.browse(cr, uid, prod['product_id'], context=context).price
else:
tot += prod['price']
res = {'value': {'total': tot}}
return res
def __getattr__(self, attr):
"""
this method catch unexisting method call and if it starts with
add_preference_'n' we execute the add_preference method with
'n' as parameter
"""
if attr.startswith('add_preference_'):
pref_id = int(attr[15:])
def specific_function(cr, uid, ids, context=None):
return self.add_preference(cr, uid, ids, pref_id, context=context)
return specific_function
return super(lunch_order,self).__getattr__(self,attr)
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
"""
Add preferences in the form view of order.line
"""
res = super(lunch_order,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
line_ref = self.pool.get("lunch.order.line")
if view_type == 'form':
doc = etree.XML(res['arch'])
pref_ids = line_ref.search(cr, uid, [('user_id', '=', uid)], order='create_date desc', context=context)
xml_start = etree.Element("div")
#If there are no preference (it's the first time for the user)
if len(pref_ids)==0:
#create Elements
xml_no_pref_1 = etree.Element("div")
xml_no_pref_1.set('class','oe_inline oe_lunch_intro')
xml_no_pref_2 = etree.Element("h3")
xml_no_pref_2.text = _("This is the first time you order a meal")
xml_no_pref_3 = etree.Element("p")
xml_no_pref_3.set('class','oe_grey')
xml_no_pref_3.text = _("Select a product and put your order comments on the note.")
xml_no_pref_4 = etree.Element("p")
xml_no_pref_4.set('class','oe_grey')
xml_no_pref_4.text = _("Your favorite meals will be created based on your last orders.")
xml_no_pref_5 = etree.Element("p")
xml_no_pref_5.set('class','oe_grey')
xml_no_pref_5.text = _("Don't forget the alerts displayed in the reddish area")
#structure Elements
xml_start.append(xml_no_pref_1)
xml_no_pref_1.append(xml_no_pref_2)
xml_no_pref_1.append(xml_no_pref_3)
xml_no_pref_1.append(xml_no_pref_4)
xml_no_pref_1.append(xml_no_pref_5)
#Else: the user already have preferences so we display them
else:
preferences = line_ref.browse(cr, uid, pref_ids, context=context)
categories = {} #store the different categories of products in preference
count = 0
for pref in preferences:
#For each preference
categories.setdefault(pref.product_id.category_id.name, {})
#if this product has already been added to the categories dictionnary
if pref.product_id.id in categories[pref.product_id.category_id.name]:
#we check if for the same product the note has already been added
if pref.note not in categories[pref.product_id.category_id.name][pref.product_id.id]:
#if it's not the case then we add this to preferences
categories[pref.product_id.category_id.name][pref.product_id.id][pref.note] = pref
#if this product is not in the dictionnay, we add it
else:
categories[pref.product_id.category_id.name][pref.product_id.id] = {}
categories[pref.product_id.category_id.name][pref.product_id.id][pref.note] = pref
currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id
#For each preferences that we get, we will create the XML structure
for key,value in categories.items():
xml_pref_1 = etree.Element("div")
xml_pref_1.set('class','oe_lunch_30pc')
xml_pref_2 = etree.Element("h2")
xml_pref_2.text = key
xml_pref_1.append(xml_pref_2)
i = 0
value = value.values()
for val in value:
for pref in val.values():
#We only show 5 preferences per category (or it will be too long)
if i==5: break
i+=1
xml_pref_3 = etree.Element("div")
xml_pref_3.set('class','oe_lunch_vignette')
xml_pref_1.append(xml_pref_3)
xml_pref_4 = etree.Element("span")
xml_pref_4.set('class','oe_lunch_button')
xml_pref_3.append(xml_pref_4)
xml_pref_5 = etree.Element("button")
xml_pref_5.set('name',"add_preference_"+str(pref.id))
xml_pref_5.set('class','oe_link oe_i oe_button_plus')
xml_pref_5.set('type','object')
xml_pref_5.set('string','+')
xml_pref_4.append(xml_pref_5)
xml_pref_6 = etree.Element("button")
xml_pref_6.set('name',"add_preference_"+str(pref.id))
xml_pref_6.set('class','oe_link oe_button_add')
xml_pref_6.set('type','object')
xml_pref_6.set('string',_("Add"))
xml_pref_4.append(xml_pref_6)
xml_pref_7 = etree.Element("div")
xml_pref_7.set('class','oe_group_text_button')
xml_pref_3.append(xml_pref_7)
xml_pref_8 = etree.Element("div")
xml_pref_8.set('class','oe_lunch_text')
xml_pref_8.text = escape(pref.product_id.name)+str(" ")
xml_pref_7.append(xml_pref_8)
price = pref.product_id.price or 0.0
cur = currency.name or ''
xml_pref_9 = etree.Element("span")
xml_pref_9.set('class','oe_tag')
xml_pref_9.text = str(price)+str(" ")+cur
xml_pref_8.append(xml_pref_9)
xml_pref_10 = etree.Element("div")
xml_pref_10.set('class','oe_grey')
xml_pref_10.text = escape(pref.note or '')
xml_pref_3.append(xml_pref_10)
xml_start.append(xml_pref_1)
first_node = doc.xpath("//div[@name='preferences']")
if first_node and len(first_node)>0:
first_node[0].append(xml_start)
res['arch'] = etree.tostring(doc)
return res
_columns = {
'user_id': fields.many2one('res.users', 'User Name', required=True, \
readonly=True, states={'draft':[('readonly', False)]}),
'product': fields.many2one('lunch.product', 'Product', required=True, \
readonly=True, states={'draft':[('readonly', False)]}, change_default=True),
'date': fields.date('Date', readonly=True, states={'draft':[('readonly', False)]}),
'cashmove': fields.many2one('lunch.cashmove', 'Cash Move' , readonly=True),
'descript': fields.char('Comment', readonly=True, size=250, \
states = {'draft':[('readonly', False)]}),
'state': fields.selection([('draft', 'New'), ('confirmed', 'Confirmed'), ], \
'Status', readonly=True, select=True),
'price': fields.function(_price_get, string="Price"),
'category': fields.many2one('lunch.category','Category'),
'user_id': fields.many2one('res.users', 'User Name', required=True, readonly=True, states={'new':[('readonly', False)]}),
'date': fields.date('Date', required=True, readonly=True, states={'new':[('readonly', False)]}),
'order_line_ids': fields.one2many('lunch.order.line', 'order_id', 'Products', ondelete="cascade", readonly=True, states={'new':[('readonly', False)]}),
'total': fields.function(_price_get, string="Total", store={
'lunch.order.line': (_fetch_orders_from_lines, ['product_id','order_id'], 20),
}),
'state': fields.selection([('new', 'New'), \
('confirmed','Confirmed'), \
('cancelled','Cancelled'), \
('partially','Partially Confirmed')] \
,'Status', readonly=True, select=True),
'alerts': fields.function(_alerts_get, string="Alerts", type='text'),
}
_defaults = {
'user_id': lambda self, cr, uid, context: uid,
'date': fields.date.context_today,
'state': lambda self, cr, uid, context: 'draft',
'state': 'new',
'alerts': _default_alerts_get,
}
def confirm(self, cr, uid, ids, box, context=None):
""" confirm order
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of confirm orders IDs
@param context: A standard dictionary for contextual values """
class lunch_order_line(osv.Model):
"""
lunch order line: one lunch order can have many order lines
"""
_name = 'lunch.order.line'
_description = 'lunch order line'
def onchange_price(self, cr, uid, ids, product_id, context=None):
if product_id:
price = self.pool.get('lunch.product').browse(cr, uid, product_id, context=context).price
return {'value': {'price': price}}
return {'value': {'price': 0.0}}
def order(self, cr, uid, ids, context=None):
"""
The order_line is ordered to the supplier but isn't received yet
"""
for order_line in self.browse(cr, uid, ids, context=context):
order_line.write({'state': 'ordered'}, context=context)
return self._update_order_lines(cr, uid, ids, context=context)
def confirm(self, cr, uid, ids, context=None):
"""
confirm one or more order line, update order status and create new cashmove
"""
cashmove_ref = self.pool.get('lunch.cashmove')
for order in self.browse(cr, uid, ids, context=context):
if order.state == 'confirmed':
continue
new_id = cashmove_ref.create(cr, uid, {'name': order.product.name+' order',
'amount':-order.product.price,
'user_cashmove':order.user_id.id,
'box':box,
'active':True,
})
self.write(cr, uid, [order.id], {'cashmove': new_id, 'state': 'confirmed'})
for order_line in self.browse(cr, uid, ids, context=context):
if order_line.state != 'confirmed':
values = {
'user_id': order_line.user_id.id,
'amount': -order_line.price,
'description': order_line.product_id.name,
'order_id': order_line.id,
'state': 'order',
'date': order_line.date,
}
cashmove_ref.create(cr, uid, values, context=context)
order_line.write({'state': 'confirmed'}, context=context)
return self._update_order_lines(cr, uid, ids, context=context)
def _update_order_lines(self, cr, uid, ids, context=None):
"""
Update the state of lunch.order based on its orderlines
"""
orders_ref = self.pool.get('lunch.order')
orders = []
for order_line in self.browse(cr, uid, ids, context=context):
orders.append(order_line.order_id)
for order in set(orders):
isconfirmed = True
for orderline in order.order_line_ids:
if orderline.state == 'new':
isconfirmed = False
if orderline.state == 'cancelled':
isconfirmed = False
orders_ref.write(cr, uid, [order.id], {'state': 'partially'}, context=context)
if isconfirmed:
orders_ref.write(cr, uid, [order.id], {'state': 'confirmed'}, context=context)
return {}
def lunch_order_cancel(self, cr, uid, ids, context=None):
"""" cancel order
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of create menus IDs
@param context: A standard dictionary for contextual values """
orders = self.browse(cr, uid, ids, context=context)
for order in orders:
if not order.cashmove:
continue
if order.cashmove.id:
self.pool.get('lunch.cashmove').unlink(cr, uid, [order.cashmove.id])
self.write(cr, uid, ids, {'state':'draft'})
return {}
def onchange_product(self, cr, uid, ids, product):
""" Get price for Product
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of create menus IDs
@product: Product To Ordered """
if not product:
return {'value': {'price': 0.0}}
price = self.pool.get('lunch.product').read(cr, uid, product, ['price'])['price']
categ_id = self.pool.get('lunch.product').browse(cr, uid, product).category_id.id
return {'value': {'price': price,'category':categ_id}}
lunch_order()
class report_lunch_amount(osv.osv):
""" Lunch Amount Report """
_name = 'report.lunch.amount'
_description = "Amount available by user and box"
_auto = False
_rec_name = "user_id"
def cancel(self, cr, uid, ids, context=None):
"""
cancel one or more order.line, update order status and unlink existing cashmoves
"""
cashmove_ref = self.pool.get('lunch.cashmove')
for order_line in self.browse(cr, uid, ids, context=context):
order_line.write({'state':'cancelled'}, context=context)
cash_ids = [cash.id for cash in order_line.cashmove]
cashmove_ref.unlink(cr, uid, cash_ids, context=context)
return self._update_order_lines(cr, uid, ids, context=context)
_columns = {
'user_id': fields.many2one('res.users', 'User Name', readonly=True),
'amount': fields.float('Amount', readonly=True, digits=(16, 2)),
'box': fields.many2one('lunch.cashbox', 'Box Name', size=30, readonly=True),
'year': fields.char('Year', size=4, readonly=True),
'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'),
('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'),
('10','October'), ('11','November'), ('12','December')], 'Month',readonly=True),
'day': fields.char('Day', size=128, readonly=True),
'date': fields.date('Created Date', readonly=True),
'name': fields.related('product_id', 'name', readonly=True),
'order_id': fields.many2one('lunch.order', 'Order', ondelete='cascade'),
'product_id': fields.many2one('lunch.product', 'Product', required=True),
'date': fields.related('order_id', 'date', type='date', string="Date", readonly=True, store=True),
'supplier': fields.related('product_id', 'supplier', type='many2one', relation='res.partner', string="Supplier", readonly=True, store=True),
'user_id': fields.related('order_id', 'user_id', type='many2one', relation='res.users', string='User', readonly=True, store=True),
'note': fields.text('Note'),
'price': fields.float("Price"),
'state': fields.selection([('new', 'New'), \
('confirmed', 'Received'), \
('ordered', 'Ordered'), \
('cancelled', 'Cancelled')], \
'Status', readonly=True, select=True),
'cashmove': fields.one2many('lunch.cashmove', 'order_id', 'Cash Move', ondelete='cascade'),
}
_defaults = {
'state': 'new',
}
def init(self, cr):
""" @param cr: the current row, from the database cursor"""
class lunch_product(osv.Model):
"""
lunch product
"""
_name = 'lunch.product'
_description = 'lunch product'
_columns = {
'name': fields.char('Product', required=True, size=64),
'category_id': fields.many2one('lunch.product.category', 'Category', required=True),
'description': fields.text('Description', size=256),
'price': fields.float('Price', digits=(16,2)), #TODO: use decimal precision of 'Account', move it from product to decimal_precision
'supplier': fields.many2one('res.partner', 'Supplier'),
}
cr.execute("""
create or replace view report_lunch_amount as (
select
min(lc.id) as id,
to_date(to_char(lc.create_date, 'dd-MM-YYYY'),'dd-MM-YYYY') as date,
to_char(lc.create_date, 'YYYY') as year,
to_char(lc.create_date, 'MM') as month,
to_char(lc.create_date, 'YYYY-MM-DD') as day,
lc.user_cashmove as user_id,
sum(amount) as amount,
lc.box as box
from
lunch_cashmove lc
where
active = 't'
group by lc.user_cashmove, lc.box, lc.create_date
)""")
class lunch_product_category(osv.Model):
"""
lunch product category
"""
_name = 'lunch.product.category'
_description = 'lunch product category'
_columns = {
'name': fields.char('Category', required=True), #such as PIZZA, SANDWICH, PASTA, CHINESE, BURGER, ...
}
report_lunch_amount()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
class lunch_cashmove(osv.Model):
"""
lunch cashmove => order or payment
"""
_name = 'lunch.cashmove'
_description = 'lunch cashmove'
_columns = {
'user_id': fields.many2one('res.users', 'User Name', required=True),
'date': fields.date('Date', required=True),
'amount': fields.float('Amount', required=True), #depending on the kind of cashmove, the amount will be positive or negative
'description': fields.text('Description'), #the description can be an order or a payment
'order_id': fields.many2one('lunch.order.line', 'Order', ondelete='cascade'),
'state': fields.selection([('order','Order'), ('payment','Payment')], 'Is an order or a Payment'),
}
_defaults = {
'user_id': lambda self, cr, uid, context: uid,
'date': fields.date.context_today,
'state': 'payment',
}
class lunch_alert(osv.Model):
"""
lunch alert
"""
_name = 'lunch.alert'
_description = 'Lunch Alert'
_columns = {
'message': fields.text('Message', size=256, required=True),
'alter_type': fields.selection([('specific', 'Specific Day'), \
('week', 'Every Week'), \
('days', 'Every Day')], \
string='Recurrency', required=True, select=True),
'specific_day': fields.date('Day'),
'monday': fields.boolean('Monday'),
'tuesday': fields.boolean('Tuesday'),
'wednesday': fields.boolean('Wednesday'),
'thursday': fields.boolean('Thursday'),
'friday': fields.boolean('Friday'),
'saturday': fields.boolean('Saturday'),
'sunday': fields.boolean('Sunday'),
'active_from': fields.float('Between', required=True),
'active_to': fields.float('And', required=True),
}
_defaults = {
'alter_type': 'specific',
'specific_day': fields.date.context_today,
'active_from': 7,
'active_to': 23,
}

View File

@ -2,23 +2,180 @@
<openerp>
<data noupdate="1">
<record model="lunch.category" id="categ_sandwich">
<record id="base.user_root" model="res.users">
<field name="groups_id" eval="[(4,ref('lunch.group_lunch_manager'))]"/>
</record>
<record id="base.user_demo" model="res.users">
<field name="groups_id" eval="[(4,ref('lunch.group_lunch_user'))]"/>
</record>
<record model="lunch.product.category" id="categ_sandwich">
<field name="name">Sandwich</field>
</record>
<record model="lunch.product.category" id="categ_pizza">
<field name="name">Pizza</field>
</record>
<record model="lunch.product.category" id="categ_pasta">
<field name="name">Pasta</field>
</record>
<record model="lunch.product" id="product_club">
<field name="name">Club</field>
<record model="res.partner" id="partner_coin_gourmand">
<field name="name">Coin gourmand</field>
<field name="supplier_lunch">True</field>
</record>
<record model="res.partner" id="partner_pizza_inn">
<field name="name">Pizza Inn</field>
<field name="supplier_lunch">True</field>
</record>
<record model="lunch.product" id="product_cheese_ham">
<field name="name">Cheese And Ham</field>
<field name="category_id" eval="str(ref('categ_sandwich'))"/>
<field name="price">2.75</field>
<field name="price">3.30</field>
<field name="supplier" eval="str(ref('partner_coin_gourmand'))"/>
<field name="description">Cheese, Ham, Salad, Tomatoes, cucumbers, eggs</field>
</record>
<record model="lunch.cashbox" id="cashbox_cashbox">
<field name="name">Cashbox</field>
<field name="manager" ref="base.user_root"/>
<record model="lunch.product" id="product_country">
<field name="name">The Country</field>
<field name="category_id" eval="str(ref('categ_sandwich'))"/>
<field name="price">3.30</field>
<field name="supplier" eval="str(ref('partner_coin_gourmand'))"/>
<field name="description">Brie, Honey, Walnut Kernels</field>
</record>
<record id="base.user_demo" model="res.users">
<field name="groups_id" eval="[(4,ref('base.group_tool_user'))]"/>
<record model="lunch.product" id="product_tuna">
<field name="name">Tuna</field>
<field name="category_id" eval="str(ref('categ_sandwich'))"/>
<field name="price">2.50</field>
<field name="supplier" eval="str(ref('partner_coin_gourmand'))"/>
<field name="description">Tuna, Mayonnaise</field>
</record>
<record model="lunch.product" id="product_gouda">
<field name="name">Gouda Cheese</field>
<field name="category_id" eval="str(ref('categ_sandwich'))"/>
<field name="price">2.50</field>
<field name="supplier" eval="str(ref('partner_coin_gourmand'))"/>
<field name="description"></field>
</record>
<record model="lunch.product" id="product_chicken_curry">
<field name="name">Chicken Curry</field>
<field name="category_id" eval="str(ref('categ_sandwich'))"/>
<field name="price">2.60</field>
<field name="supplier" eval="str(ref('partner_coin_gourmand'))"/>
<field name="description"></field>
</record>
<record model="lunch.product" id="product_margherita">
<field name="name">Pizza Margherita</field>
<field name="category_id" eval="str(ref('categ_pizza'))"/>
<field name="price">6.90</field>
<field name="supplier" eval="str(ref('partner_pizza_inn'))"/>
<field name="description">Tomatoes, Mozzarella</field>
</record>
<record model="lunch.product" id="product_italiana">
<field name="name">Pizza Italiana</field>
<field name="category_id" eval="str(ref('categ_pizza'))"/>
<field name="price">7.40</field>
<field name="supplier" eval="str(ref('partner_pizza_inn'))"/>
<field name="description">Fresh Tomatoes, Basil, Mozzarella</field>
</record>
<record model="lunch.product" id="product_Bolognese">
<field name="name">Bolognese Pasta</field>
<field name="category_id" eval="str(ref('categ_pasta'))"/>
<field name="price">7.70</field>
<field name="supplier" eval="str(ref('partner_pizza_inn'))"/>
<field name="description"></field>
</record>
<record model="lunch.product" id="product_Napoli">
<field name="name">Napoli Pasta</field>
<field name="category_id" eval="str(ref('categ_pasta'))"/>
<field name="price">7.70</field>
<field name="supplier" eval="str(ref('partner_pizza_inn'))"/>
<field name="description">Tomatoes, Basil</field>
</record>
<record model="lunch.order" id="order_1">
<field name="user_id" ref="base.user_root"/>
<field name="date" eval="time.strftime('2012-10-23')"/>
<field name="order_line_ids" eval="[]"/>
<field name="state">new</field>
<field name='company_id'>1</field>
</record>
<record model="lunch.order" id="order_2">
<field name="user_id" ref="base.user_root"/>
<field name="date" eval="time.strftime('2012-10-22')"/>
<field name="order_line_ids" eval="[]"/>
<field name="state">confirmed</field>
<field name='company_id'>1</field>
</record>
<record model="lunch.order" id="order_3">
<field name="user_id" ref="base.user_root"/>
<field name="date" eval="time.strftime('2012-10-24')"/>
<field name="order_line_ids" eval="[]"/>
<field name="state">cancelled</field>
<field name='company_id'>1</field>
</record>
<record model="lunch.order.line" id="order_line_1">
<field name="user_id" ref="base.user_root"/>
<field name="product_id" ref="product_Bolognese"/>
<field name="date" eval="time.strftime('2012-10-23')"/>
<field name="state">new</field>
<field name="supplier" ref="partner_pizza_inn"/>
<field name="note">+Emmental</field>
<field name="order_id" ref="order_1"/>
</record>
<record model="lunch.order.line" id="order_line_2">
<field name="user_id" ref="base.user_root"/>
<field name="product_id" ref="product_italiana"/>
<field name="date" eval="time.strftime('2012-10-22')"/>
<field name="state">confirmed</field>
<field name="supplier" ref="partner_pizza_inn"/>
<field name="note">+Mushrooms</field>
<field name="order_id" ref="order_2"/>
</record>
<record model="lunch.order.line" id="order_line_3">
<field name="user_id" ref="base.user_root"/>
<field name="product_id" ref="product_gouda"/>
<field name="date" eval="time.strftime('2012-10-24')"/>
<field name="state">cancelled</field>
<field name="supplier" ref="partner_coin_gourmand"/>
<field name="note">+Salad +Tomatoes +Cucumbers</field>
<field name="order_id" ref="order_3"/>
</record>
<record model="lunch.cashmove" id="cashmove_1">
<field name="user_id" ref="base.user_root"/>
<field name="date" eval="time.strftime('2012-10-23')"/>
<field name="description">Pizza Italiana</field>
<field name="amount">-7.40</field>
<field name="order_id" ref="order_2"/>
<field name="state">order</field>
</record>
<record model="lunch.cashmove" id="cashmove_2">
<field name="user_id" ref="base.user_root"/>
<field name="date" eval="time.strftime('2012-10-24')"/>
<field name="description">Payment: 5 lunch tickets (6€)</field>
<field name="amount">30</field>
<field name="state">payment</field>
</record>
<record model="lunch.alert" id="alert_1">
<field name="message">Lunch must be ordered before 10h30 am</field>
<field name="day">days</field>
</record>
</data>

View File

@ -1,52 +0,0 @@
<openerp>
<data>
<record model="ir.actions.act_window" id="view_lunch_product_form_installer">
<field name="name">Define Your Lunch Products</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">lunch.product</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" eval="False"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a new product that can be ordered for the lunch.
</p><p>
We suggest you to put the real price so that the exact due
amount is deduced from each employee's cash boxes when they
order.
</p><p>
If you order lunch at several places, you can use the product
categories to split by supplier. It will be easier to filter
lunch orders.
</p>
</field>
</record>
<record id="view_lunch_product_form_todo" model="ir.actions.todo">
<field name="action_id" ref="view_lunch_product_form_installer"/>
<field name="sequence">50</field>
</record>
<record model="ir.actions.act_window" id="action_create_cashbox">
<field name="name">Create Lunch Cash Boxes</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">lunch.cashbox</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 add a new cash box.
</p><p>
You can create on cash box by employee if you want to keep
track of the amount due by employee according to what have been
ordered.
</p>
</field>
</record>
<record id="action_create_cashbox_todo" model="ir.actions.todo">
<field name="action_id" ref="action_create_cashbox" />
<field name="sequence">51</field>
</record>
</data>
</openerp>

View File

@ -4,8 +4,8 @@
<report
id="report_lunch_order"
string="Lunch Order"
model="lunch.order"
name="lunch.order"
model="lunch.order.line"
name="lunch.order.line"
rml="lunch/report/order.rml"
auto="False"
/>

View File

@ -1,393 +1,486 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- Top menu item -->
<menuitem name="Tools" id="base.menu_tools" sequence="160"/>
<!--Menu and Title-->
<menuitem id='menu_lunch' name='Lunch' sequence="300"/>
<menuitem name="Lunch" parent="menu_lunch" id="menu_lunch_title" sequence="50" />
<menuitem name="Administrate Orders" parent="menu_lunch" id="menu_lunch_admin" sequence="51" groups="group_lunch_manager"/>
<menuitem name="Administrate Cash Moves" parent="menu_lunch" id="menu_lunch_cash" sequence="52" groups="group_lunch_manager"/>
<menuitem name="Configuration" parent="menu_lunch" id="menu_lunch_config" sequence="53" groups="group_lunch_manager"/>
<!--View Search to group/filter by Supplier and time-->
<record model="ir.ui.view" id="lunch_order_line_search_view">
<field name="name">Search</field>
<field name="model">lunch.order.line</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search">
<field name="name" filter_domain="['|', ('name', 'ilike', self), ('note', 'ilike', self)]"/>
<filter name="not_confirmed" string="Not Received" domain="[('state','!=',('confirmed'))]"/>
<filter name="comfirmed" string="Received" domain="[('state','=','confirmed')]"/>
<filter name="cancelled" string="Cancelled" domain="[('state','=','cancelled')]"/>
<separator/>
<filter name="today" string="Today" domain="[('date','=',time.strftime('%%Y-%%m-%%d'))]"/>
<field name="user_id"/>
<group expand="0" string="Group By...">
<filter name="group_by_supplier" string="By Supplier" context="{'group_by':'supplier'}"/>
<filter name="group_by_date" string="By Date" context="{'group_by':'date'}"/>
</group>
</search>
</field>
</record>
<menuitem name="Lunch Order" parent="base.menu_tools"
id="menu_lunch" sequence="1" />
<!--View Search to group by employee and input/output (cashmoves)-->
<record id="view_lunch_employee_payment_filter" model="ir.ui.view">
<field name='name'>lunch employee payment</field>
<field name='model'>lunch.cashmove</field>
<field name='type'>search</field>
<field name='arch' type='xml'>
<search string="lunch employee payment">
<field name="description"/>
<field name="user_id"/>
<filter name='is_payment' string="Payment" domain="[('state','=','payment')]"/>
<separator/>
<filter name='is_mine' string="My Account" domain="[('user_id','=',uid)]"/>
</search>
</field>
</record>
<menuitem name="Reporting" parent="base.menu_tools"
id="base.menu_lunch_reporting" sequence="6" groups="base.group_tool_manager"/>
<record id="view_lunch_cashmove_filter" model="ir.ui.view">
<field name='name'>lunch cashmove</field>
<field name='model'>lunch.cashmove</field>
<field name='type'>search</field>
<field name='arch' type='xml'>
<search string="lunch cashmove">
<field name="description"/>
<field name="user_id"/>
<group expand="0" string="Group By...">
<filter name='group_by_user' string="By Employee" context="{'group_by':'user_id'}"/>
</group>
</search>
</field>
</record>
<menuitem name="Lunch"
parent="base.menu_reporting"
id="menu_lunch_reporting_order" sequence="55" />
<!--View search for order-->
<record id="view_search_my_order" model="ir.ui.view">
<field name='name'>lunch orders</field>
<field name='model'>lunch.order</field>
<field name='type'>search</field>
<field name='arch' type='xml'>
<search string="lunch orders">
<field name="date"/>
<field name="order_line_ids"/>
<filter name='is_mine' string="My Orders" domain="[('user_id','=',uid)]"/>
</search>
</field>
</record>
<menuitem name="Configuration" parent="base.menu_tools"
id="base.menu_lunch_survey_root" sequence="20" groups="base.group_tool_manager"/>
<menuitem name="Lunch" parent="base.menu_lunch_survey_root"
id="menu_lunch_category_root_configuration" sequence="1" />
<record model="ir.ui.view" id="alert_search_view">
<field name="name">Search</field>
<field name="model">lunch.alert</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search">
<field name="message"/>
</search>
</field>
</record>
<!-- Lunch order Form view -->
<!--Action for Your Orders-->
<record model="ir.actions.act_window" id="action_lunch_order_form">
<field name="name">New Order</field>
<field name="res_model">lunch.order</field>
<field name="view_mode">form</field>
</record>
<menuitem name="New Order" parent="menu_lunch_title" id="menu_lunch_order_form" action="action_lunch_order_form" sequence="1"/>
<record model="ir.ui.view" id="view_lunch_order_form">
<field name="name">Order</field>
<record model="ir.actions.act_window" id="action_lunch_order_tree">
<field name="name">Your Orders</field>
<field name="res_model">lunch.order</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_search_my_order"/>
<field name="context">{"search_default_is_mine":1}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a lunch order.
</p>
<p>
A lunch order is defined by its user, date and order lines.
Each order line corresponds to a product, an additional note and a price.
Before selecting your order lines, don't forget to read the warnings displayed in the reddish area.
</p>
</field>
</record>
<menuitem name="Previous Orders" parent="menu_lunch_title" id="menu_lunch_order_tree" action="action_lunch_order_tree" sequence="2"/>
<!--Action for Lunch cashmoves-->
<record model="ir.actions.act_window" id="action_lunch_cashmove_form">
<field name="name">Your Account</field>
<field name="res_model">lunch.cashmove</field>
<field name="view_mode">tree</field>
<field name="search_view_id" ref="view_lunch_employee_payment_filter"/>
<field name="context">{"search_default_is_mine":1}</field>
<field name="help" type="html">
<p>
Here you can see your cash moves.<br/>A cash moves can be either an expense or a payment.
An expense is automatically created when an order is received while a payment is a reimbursement to the company encoded by the manager.
</p>
</field>
</record>
<menuitem name="Your Lunch Account" parent="menu_lunch_title" id="menu_lunch_cashmove_form" action="action_lunch_cashmove_form" sequence="3"/>
<!--Action for Administrate Orders group by supplier-->
<record model="ir.actions.act_window" id="action_lunch_order_by_supplier_form">
<field name="name">Orders by Supplier</field>
<field name="res_model">lunch.order.line</field>
<field name="view_mode">tree</field>
<field name="search_view_id" ref="lunch_order_line_search_view"/>
<field name="context">{"search_default_group_by_supplier":1, "search_default_today":1}</field>
<field name="help" type="html">
<p>
Here you can see today's orders grouped by suppliers.
</p>
<p>
- Click on the <img src="../../../web/static/src/img/icons/terp-call-start.png"/> to announce that the order is ordered <br/>
- Click on the <img src="../../../web/static/src/img/icons/gtk-apply.png"/> to announce that the order is received <br/>
- Click on the <img src="../../../web/static/src/img/icons/gtk-cancel.png"/> to announce that the order isn't available
</p>
</field>
</record>
<menuitem name="Today's Orders by Supplier" parent="menu_lunch_admin" id="menu_lunch_order_by_supplier_form" action="action_lunch_order_by_supplier_form" />
<!--Action for control Supplier-->
<record model="ir.actions.act_window" id="action_lunch_control_suppliers">
<field name="name">Control Suppliers</field>
<field name="res_model">lunch.order.line</field>
<field name="view_mode">tree</field>
<field name="search_view_id" ref="lunch_order_line_search_view"/>
<field name="context">{"search_default_group_by_date":1, "search_default_group_by_supplier":1}</field>
<field name="help" type="html">
<p>
Here you can see every orders grouped by suppliers and by date.
</p>
<p>
- Click on the <img src="../../../web/static/src/img/icons/terp-call-start.png"/> to announce that the order is ordered <br/>
- Click on the <img src="../../../web/static/src/img/icons/gtk-apply.png"/> to announce that the order is received <br/>
- Click on the <img src="../../../web/static/src/img/icons/gtk-cancel.png"/> red X to announce that the order isn't available
</p>
</field>
</record>
<menuitem name="Orders by Supplier" parent="menu_lunch_admin" id="menu_lunch_control_suppliers" action="action_lunch_control_suppliers" />
<!--Action for Control Accounts-->
<record model="ir.actions.act_window" id="action_lunch_control_accounts">
<field name="name">Control Accounts</field>
<field name="res_model">lunch.cashmove</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_lunch_cashmove_filter"/>
<field name="context">{"search_default_group_by_user":1}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new payment.
</p>
<p>
A cashmove can either be an expense or a payment.<br/>
An expense is automatically created at the order receipt.<br/>
A payment represents the employee reimbursement to the company.
</p>
</field>
</record>
<menuitem name="Control Accounts" parent="menu_lunch_cash" id="menu_lunch_control_accounts" action="action_lunch_control_accounts" />
<!--Action for Payment cashmove-->
<record model="ir.actions.act_window" id="action_lunch_cashmove">
<field name="name">Register Cash Moves</field>
<field name="res_model">lunch.cashmove</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_lunch_employee_payment_filter"/>
<field name="context">{"search_default_is_payment":1}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a payment.
</p>
<p>
Here you can see the employees' payment. A payment is a cash move from the employee to the company.
</p>
</field>
</record>
<menuitem name="Employee's Payment" parent="menu_lunch_cash" id="menu_lunch_cashmove" action="action_lunch_cashmove" />
<!--Action for Products-->
<record model="ir.actions.act_window" id="action_lunch_products">
<field name="name">Products</field>
<field name="res_model">lunch.product</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a product for lunch.
</p>
<p>
A product is defined by its name, category, price and supplier.
</p>
</field>
</record>
<menuitem name="Products" parent="menu_lunch_config" id="menu_lunch_products" action="action_lunch_products" />
<!--Action for Product categories-->
<record model="ir.actions.act_window" id="action_lunch_product_categories">
<field name="name">Product Categories</field>
<field name="res_model">lunch.product.category</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a lunch category.
</p>
<p>
Here you can find every lunch categories for products.
</p>
</field>
</record>
<record model="ir.ui.view" id="product_category_form_view">
<field name="name">Product category Form</field>
<field name="model">lunch.product.category</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Products Form" version="7.0">
<sheet>
<group>
<field name='name' string="Product Category: "/>
</group>
</sheet>
</form>
</field>
</record>
<menuitem name="Product Categories" parent="menu_lunch_config" id="menu_lunch_product_categories" action="action_lunch_product_categories" />
<!--Action for Alert-->
<record model="ir.actions.act_window" id="action_lunch_alert">
<field name="name">Alerts</field>
<field name="res_model">lunch.alert</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="alert_search_view"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a lunch alert.
</p>
<p>
Alerts are used to warn employee from possible issues concerning the lunch orders.
To create a lunch alert you have to define its recurrency, the time interval during which the alert should be executed and the message to display.
</p>
<p>
Example: <br/>
- Recurency: Everyday<br/>
- Time interval: from 00h00 am to 11h59 pm<br/>
- Message: "You must order before 10h30 am"
</p>
</field>
</record>
<menuitem name="Alerts" parent="menu_lunch_config" id="menu_lunch_alert" action="action_lunch_alert" />
<!--View for Order lines-->
<record model="ir.ui.view" id="orders_order_lines_tree_view">
<field name="name">Order lines Tree</field>
<field name="model">lunch.order.line</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Order lines Tree">
<field name='date'/>
<field name='user_id'/>
<field name='supplier' invisible='1'/>
<field name='product_id'/>
<field name='note'/>
<field name='state'/>
<field name='price' sum="Total"/>
<button name="order" string="Order" type="object" icon="terp-call-start" attrs="{'invisible': ['|',('state','=','confirmed'),('state','=','ordered')]}"/>
<button name="confirm" string="Confirm" type="object" icon="gtk-apply" attrs="{'invisible': [('state','!=','ordered')]}"/>
<button name="cancel" string="Cancel" type="object" icon="gtk-cancel" attrs="{'invisible': [('state','=','cancelled')]}"/>
</tree>
</field>
</record>
<!--View for Your orders-->
<record model="ir.ui.view" id="orders_tree_view">
<field name="name">Orders Tree View</field>
<field name="model">lunch.order</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Orders Tree">
<field name="date"/>
<field name="order_line_ids"/>
<field name="state" />
<field name="total" sum="Total"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="orders_form_view">
<field name="name">Lunch Order</field>
<field name="model">lunch.order</field>
<field name="arch" type="xml">
<form string="Lunch Order" version="7.0">
<header>
<button name="%(action_lunch_order_confirm)d" string="Confirm Order" type="action" states="draft" class="oe_highlight"/>
<button name="%(action_lunch_order_cancel)d" string="Cancel Order" type="action" states="confirmed" />
<field name="state" widget="statusbar" statusbar_visible="draft,confirmed"/>
</header>
<sheet string="Order">
<group>
<form string='Orders Form' version='7.0' class="oe_lunch">
<header>
<field name='state' widget='statusbar' statusbar_visible='new,confirmed'/>
</header>
<sheet>
<group>
<field name="product" on_change="onchange_product(product)"/>
<field name="descript"/>
<field name="price"/>
<field name="category"/>
<group>
<field name='user_id'/>
</group>
<group>
<field name='date'/>
</group>
</group>
<field name='alerts' attrs="{'invisible': ['|',('state','!=','new'),('alerts','=','')]}" class="oe_inline oe_lunch_alert"/>
<div name="preferences">
</div>
<separator string='Select your order'/>
<field name='order_line_ids' nolabel='1' on_change='onchange_price(order_line_ids)'>
<tree string='List' editable='bottom'>
<field name='product_id' on_change='onchange_price(product_id)'/>
<field name='note' />
<field name='price' />
<field name='supplier' invisible="1"/>
<field name="state" invisible="1"/>
</tree>
</field>
<group class='oe_subtotal_footer oe_right'>
<field name='total'/>
</group>
<br/><br/>
</sheet>
</form>
</field>
</record>
<!--View for Products-->
<record model="ir.ui.view" id="products_tree_view">
<field name="name">Products Tree</field>
<field name="model">lunch.product</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Products Tree">
<field name="name"/>
<field name="category_id"/>
<field name="supplier"/>
<field name="description"/>
<field name="price"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="products_form_view">
<field name="name">Products Form</field>
<field name="model">lunch.product</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Products Form" version="7.0">
<header>
</header>
<sheet>
<group>
<field name='name'/>
<field name='category_id'/>
<field name='supplier'/>
<field name='price'/>
</group>
<label for='description'/>
<field name='description'/>
</sheet>
</form>
</field>
</record>
<!--view for cashmove-->
<record model="ir.ui.view" id="casmove_tree_view">
<field name="name">cashmove tree</field>
<field name="model">lunch.cashmove</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="cashmove tree">
<field name="date"/>
<field name="user_id"/>
<field name="description"/>
<field name="amount" sum="Total"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="casmove_form_view">
<field name="name">cashmove form</field>
<field name="model">lunch.cashmove</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="cashmove form" version="7.0">
<sheet>
<group>
<field name="user_id"/>
<field name="cashmove"/>
<field name="date"/>
<field name="amount"/>
</group>
</group>
<label for='description'/>
<field name="description"/>
</sheet>
</form>
</field>
</record>
<!--view for alerts-->
<record model="ir.ui.view" id="alert_tree_view">
<field name="name">alert tree</field>
<field name="model">lunch.alert</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="alert tree">
<field name="message"/>
<field name="alter_type"/>
<field name='active_from' widget='float_time'/>
<field name='active_to' widget='float_time'/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="alert_form_view">
<field name="name">alert form</field>
<field name="model">lunch.alert</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="alert tree" version="7.0">
<sheet>
<group string="Schedule Date">
<group>
<field name="alter_type"/>
<field name="specific_day" attrs="{'invisible': [('alter_type','!=','specific')], 'required':[('alter_type','=','specific')]}"/>
</group>
</group>
<group attrs="{'invisible': [('alter_type','!=','week')]}">
<group>
<field name="monday"/>
<field name="tuesday"/>
<field name="wednesday"/>
<field name="thursday"/>
</group>
<group>
<field name="friday"/>
<field name="saturday"/>
<field name="sunday"/>
</group>
</group>
<group string="Schedule Hour">
<field name='active_from' widget='float_time'/>
<field name='active_to' widget='float_time'/>
</group>
<group string='Message'>
<field name='message' nolabel='1' placeholder="Write the message you want to display during the defined period..."/>
</group>
</sheet>
</form>
</field>
</record>
<!-- Lunch order Tree view -->
<record model="ir.ui.view" id="view_lunch_order_tree">
<field name="name">Order</field>
<field name="model">lunch.order</field>
<field name="arch" type="xml">
<tree colors="blue:state == 'draft';black:state == 'confirmed'" string="Order">
<field name="date"/>
<field name="user_id"/>
<field name="product"/>
<field name="descript"/>
<field name="category"/>
<field name="price" sum="Total price"/>
<field name="state"/>
</tree>
</field>
</record>
<!-- Lunch order Search view -->
<record id="view_lunch_order_filter" model="ir.ui.view">
<field name="name">lunch.order.list.select</field>
<field name="model">lunch.order</field>
<field name="arch" type="xml">
<search string="Search Lunch Order">
<field name="date"/>
<filter icon="terp-check" string="To Confirm" domain="[('state','=','draft')]"/>
<filter icon="terp-camera_test" string="Confirmed" domain="[('state','=',('confirmed'))]"/>
<field name="user_id"/>
<group expand="0" string="Group By...">
<filter string="Category" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'category'}"/>
</group>
</search>
</field>
</record>
<!-- Lunch order Action -->
<record model="ir.actions.act_window" id="action_lunch_order_form">
<field name="name">Lunch Orders</field>
<field name="res_model">lunch.order</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_lunch_order_filter"/>
<field name="context">{"search_default_Today":1}</field>
</record>
<menuitem name="Lunch Orders" parent="menu_lunch"
id="menu_lunch_order_form" action="action_lunch_order_form" />
<!-- Cash Box Form view -->
<record model="ir.ui.view" id="view_lunch_cashbox_form">
<field name="name">Cashboxes</field>
<field name="model">lunch.cashbox</field>
<field name="arch" type="xml">
<form string="Cashboxes" version="7.0">
<group colspan="4">
<field name="name"/>
<field name="manager"/>
</group>
</form>
</field>
</record>
<!-- Cash Box Tree view -->
<record model="ir.ui.view" id="view_lunch_cashbox_tree">
<field name="name">Cashboxes</field>
<field name="model">lunch.cashbox</field>
<field name="arch" type="xml">
<tree string="Cashboxes" colors="red:sum_remain&lt;=0">
<field name="name"/>
<field name="manager"/>
<field name="sum_remain"/>
</tree>
</field>
</record>
<!-- Cash Box Action -->
<record model="ir.actions.act_window" id="action_lunch_cashbox_form">
<field name="name"> Cashboxes </field>
<field name="res_model">lunch.cashbox</field>
</record>
<menuitem name="Cashboxes"
parent="menu_lunch_category_root_configuration"
id="menu_lunch_cashbox_form"
action="action_lunch_cashbox_form" />
<!-- Cash Move Form view -->
<record model="ir.ui.view" id="view_lunch_cashmove_form">
<field name="name">CashMove</field>
<field name="model">lunch.cashmove</field>
<field name="arch" type="xml">
<form string="CashMove" version="7.0">
<sheet>
<group col="4">
<field name="name"/>
<field name="user_cashmove"/>
<field name="amount"/>
<field name="box"/>
<field name="create_date"/>
<field name="active"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- Cash Move Tree view -->
<record model="ir.ui.view" id="view_lunch_cashmove_tree">
<field name="name">CashMove</field>
<field name="model">lunch.cashmove</field>
<field name="arch" type="xml">
<tree string="CashMove" editable="top">
<field name="create_date"/>
<field name="box"/>
<field name="name" required="1"/>
<field name="user_cashmove"/>
<field name="amount" sum="Total amount"/>
</tree>
</field>
</record>
<!-- Cash Move Search View -->
<record id="view_lunch_cashmove_filter" model="ir.ui.view">
<field name="name">lunch.cashmove.list.select</field>
<field name="model">lunch.cashmove</field>
<field name="arch" type="xml">
<search string="Search CashMove">
<field name="create_date"/>
<field name="user_cashmove"/>
<group expand="0" string="Group By...">
<filter string="User" icon="terp-personal" domain="[]" context="{'group_by':'user_cashmove'}"/>
<filter string="Box" icon="terp-dolar" domain="[]" context="{'group_by':'box'}"/>
<filter string="Date" icon="terp-go-today" domain="[]" context="{'group_by':'create_date'}"/>
</group>
</search>
</field>
</record>
<!-- Cash Move Action -->
<record model="ir.actions.act_window" id="action_lunch_cashmove_form">
<field name="name">Cash Moves</field>
<field name="res_model">lunch.cashmove</field>
<field name="search_view_id" ref="view_lunch_cashmove_filter"/>
<field name="context">{"search_default_Today":1}</field>
</record>
<menuitem name="Cash Moves" parent="menu_lunch"
id="menu_lunch_cashmove_form"
action="action_lunch_cashmove_form" />
<!-- Lunch Category Form view -->
<record model="ir.ui.view" id="view_lunch_category_form">
<field name="name"> Category of product </field>
<field name="model">lunch.category</field>
<field name="arch" type="xml">
<form string="Category" version="7.0">
<group>
<field name="name"/>
</group>
</form>
</field>
</record>
<!-- Lunch Category Tree view -->
<record model="ir.ui.view" id="view_lunch_category_tree">
<field name="name">Category</field>
<field name="model">lunch.category</field>
<field name="arch" type="xml">
<tree string="Order">
<field name="name"/>
</tree>
</field>
</record>
<!-- Lunch Category Action -->
<record model="ir.actions.act_window" id="action_lunch_category_form">
<field name="name"> Product Categories </field>
<field name="res_model">lunch.category</field>
</record>
<!-- Lunch Product Form view -->
<record model="ir.ui.view" id="view_lunch_product_form">
<field name="name">Products</field>
<field name="model">lunch.product</field>
<field name="arch" type="xml">
<form string="Products" version="7.0">
<sheet>
<group>
<group>
<field name="name"/>
<field name="category_id"/>
<field name="price" />
</group>
<group>
<field name="active"/>
</group>
<field name="description" placeholder="Add a description" nolabel="1" colspan="4"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- Lunch Product Tree view -->
<record model="ir.ui.view" id="view_lunch_product_tree">
<field name="name">Products</field>
<field name="model">lunch.product</field>
<field name="arch" type="xml">
<tree string="Products">
<field name="name"/>
<field name="category_id"/>
<field name="price"/>
<field name="description"/>
</tree>
</field>
</record>
<!-- Lunch Product Search view -->
<record model="ir.ui.view" id="view_lunch_product_search">
<field name="name">Products</field>
<field name="model">lunch.product</field>
<field name="arch" type="xml">
<search string="Products">
<field name="name" string="Product"/>
<field name="price"/>
<field name="category_id"/>
</search>
</field>
</record>
<!-- Lunch Product Action -->
<record model="ir.actions.act_window" id="action_lunch_product_form">
<field name="name">Products</field>
<field name="res_model">lunch.product</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_lunch_product_tree"/>
<field name="search_view_id" ref="view_lunch_product_search"/>
</record>
<menuitem name="Products"
parent="menu_lunch_category_root_configuration"
id="menu_lunch_product_form" action="action_lunch_product_form"
sequence="2" />
<menuitem name="Product Categories"
parent="menu_lunch_category_root_configuration"
id="menu_lunch_category_form"
action="action_lunch_category_form" sequence="1" />
<!-- Lunch Amount Tree view -->
<record model="ir.ui.view" id="view_report_lunch_amount_tree">
<field name="name">Lunch amount</field>
<field name="model">report.lunch.amount</field>
<field name="arch" type="xml">
<tree string="Box Amount by User">
<field name="date" invisible="1"/>
<field name="year" invisible="1"/>
<field name="day" invisible="1"/>
<field name="month" invisible="1"/>
<field name="box"/>
<field name="user_id"/>
<field name="amount" sum="Total box" />
</tree>
</field>
</record>
<!-- Lunch Amount Form view -->
<record model="ir.ui.view" id="view_report_lunch_amount_form">
<field name="name">Lunch amount</field>
<field name="model">report.lunch.amount</field>
<field name="arch" type="xml">
<form string="Box Amount by User" version="7.0">
<sheet>
<group col="4">
<field name="user_id"/>
<field name="box"/>
<field name="amount"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- Lunch Amount Search view -->
<record model="ir.ui.view" id="view_report_lunch_amount_search">
<field name="name">Lunch amount</field>
<field name="model">report.lunch.amount</field>
<field name="arch" type="xml">
<search string="Box Amount by User">
<field name="date"/>
<field name="box"/>
<field name="amount"/>
<field name="user_id"/>
<group expand="0" string="Group By...">
<filter string="Box" icon="terp-dolar" context="{'group_by':'box'}"/>
</group>
</search>
</field>
</record>
<!-- Lunch Amount Action -->
<record model="ir.actions.act_window" id="action_report_lunch_amount_tree">
<field name="name">Cash Position by User</field>
<field name="res_model">report.lunch.amount</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_year': 1,"search_default_month":1}</field>
<field name="search_view_id" ref="view_report_lunch_amount_search"/>
</record>
<menuitem name="Cash Position by User"
parent="menu_lunch_reporting_order"
action="action_report_lunch_amount_tree"
id="menu_lunch_report_amount_tree" />
</data>
</openerp>

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