Compare commits

..

59 Commits

Author SHA1 Message Date
Florian da Costa
da53473b60 migrate eradicate_quick_create to version 9.0 2017-10-04 10:43:32 +02:00
Florian da Costa
667775d466 Migrate product_search_supplier_code to v9 2017-07-21 14:47:39 +02:00
Florian da Costa
25de048402 Make modules uninstallable 2017-07-21 14:37:51 +02:00
Alexis de Lattre
817fadd167 Add groupby on commercial partner on invoice line search 2017-06-30 17:19:39 +02:00
Alexis de Lattre
25ea1991cf Add module account_invoice_update_wizard 2017-06-21 23:57:29 +02:00
Alexis de Lattre
c8c1f78e66 FIX my previous commit in mail_usability 2017-06-21 15:34:35 +02:00
Alexis de Lattre
0bc6cb32d9 Merge branch '8.0' of github.com:akretion/odoo-usability into 8.0 2017-06-21 14:53:13 +02:00
Alexis de Lattre
db736d95a3 Add "All Messages Except Notifications" for notify_email on res.partner 2017-06-21 14:52:47 +02:00
Alexis de Lattre
f83c948889 Add check methods for accounting and improve search view of account.invoice.report 2017-06-14 17:31:45 +02:00
Alexis de Lattre
d736663f3f Fix view 2017-05-19 09:47:10 +02:00
David Beal
f051537a92 FIX import report_xls in account_move_line_start_end_dates_xls 2017-05-15 12:01:49 +02:00
Alexis de Lattre
193e5e6ecc Add multi-company support hr_holidays_usability
Add modules hr_holidays_lunch_voucher and hr_holidays_lunch_voucher_natixis
2017-05-11 00:29:22 +02:00
Alexis de Lattre
00592100f7 Add module resource_usability 2017-05-09 17:09:34 +02:00
Alexis de Lattre
0d524f27d8 Merge branch '8.0' of github.com:akretion/odoo-usability into 8.0 2017-05-09 12:10:18 +02:00
Alexis de Lattre
4509b2631a Add multi-company record rule on leads
Small view improvement in crm_usability
2017-05-09 12:09:39 +02:00
Alexis de Lattre
2ff7943c62 Account_usability now compatible with account_analytic_plans 2017-05-04 17:13:48 +02:00
beau sebastien
d85e7270b3 Merge pull request #28 from akretion/sale-partner-shipping-filter-with-customer
[8.0] sale_partner_shipping_filter_with_customer module
2017-04-21 13:51:47 +02:00
beau sebastien
7b6916ce16 Merge pull request #29 from akretion/8.0-product-unit-manager-group
[8.0] product_unit_manager_group module
2017-04-21 11:27:26 +02:00
chafique-delli
a9c6f9ed69 replace partner_parent_id by commercial_partner_id 2017-04-13 21:50:12 +02:00
Alexis de Lattre
7a11966992 Better views for product.ul
Track partner_id on stock.picking
Improve stock.quant.package view
2017-04-13 20:05:15 +02:00
Alexis de Lattre
d4fcaa7d14 account.move.line: Add filter on both debit and credit 2017-03-23 14:38:15 +01:00
chafique-delli
77fb97f273 The units of measurement menus are visible only to the group_uom_manager group 2017-03-17 17:07:29 +01:00
Sébastien BEAU
9670eb7c10 [IMP] improve attribute view 2017-03-16 15:33:45 +01:00
chafique-delli
f8e955d5b7 remove dependency to point_of_sale to be more generic 2017-03-14 12:37:13 +01:00
chafique-delli
a803d1dcb9 add a dependency to the mrp and point_of_sale module 2017-03-14 12:14:44 +01:00
chafique-delli
a141f0506b add product_unit_manager_group module 2017-03-14 11:20:47 +01:00
chafique-delli
7c554aee33 fix after @bealdav's comment 2017-03-09 18:02:04 +01:00
chafique-delli
07c81e441d domain improvement 2017-03-09 15:14:05 +01:00
Alexis de Lattre
4c3c8e50db Remove show_account_move_form because of the fact that the context is kept from the account.move.line form view, so it triggers a crash when creating a line from the account.move form
Fix domain on analytic account on move lines
2017-03-08 00:31:23 +01:00
chafique-delli
60beb99580 fix domain 2017-03-07 19:13:30 +01:00
chafique-delli
709bde8fb7 add sale_partner_shipping_filter_with_customer module 2017-03-07 18:42:07 +01:00
Alexis de Lattre
281c0b7052 Cut ref field to 32 chars, to avoid trouble with PDF webkit accounting reports 2017-03-04 22:34:31 +01:00
Alexis de Lattre
8d55f9aaa5 Restore description field 2017-03-04 22:34:18 +01:00
Alexis de Lattre
964b1fca67 Better context from wizard 2017-03-03 09:36:44 +01:00
Alexis de Lattre
e20f88baf0 Add button for direct access to journal entry from journal items 2017-03-03 09:36:08 +01:00
Benoit
15d9c31f6f [FIX] change pattern for mail footer because it changes is there is user signature or not 2017-02-15 11:37:29 +01:00
Alexis de Lattre
e74864e54f Add FR translation 2017-02-14 14:25:41 +01:00
Alexis de Lattre
146c0e6b7d Add a link from incoming picking to PO 2017-02-10 17:27:27 +01:00
Alexis de Lattre
869c7176f7 Supplierinfo: remove field that is not usefull for everybody ; fix addition of supplier on products 2017-02-09 22:23:36 +01:00
Alexis de Lattre
4b26ab78be Better views on product.supplierinfo 2017-02-09 16:51:00 +01:00
Alexis de Lattre
662494db35 Better selection of picking type 2017-02-09 14:09:41 +01:00
Alexis de Lattre
aafc36dfdb Fix XMLID name 2017-02-07 17:37:01 +01:00
Alexis de Lattre
e94168ad27 Better procurement order search view 2017-02-07 16:48:24 +01:00
Sébastien BEAU
9b62198115 [FIX] fix missing dependency for partner_split_menu 2017-02-06 19:21:36 +01:00
Alexis de Lattre
309027198a Add module product_expiry_simple 2017-02-03 23:24:08 +01:00
Alexis de Lattre
c8f1517881 Add traking on some import product fields 2017-02-03 15:13:40 +01:00
Alexis de Lattre
6cb195a3eb Remove stored field product_supplier_code on stock.move because it takes a very very long time to compute on existing large DB and it is not needed by everybody. (#27) 2017-02-03 12:06:09 +01:00
Alexis de Lattre
b85f5184c2 Add track_visibility on important fields 2017-02-02 09:40:26 +01:00
Sébastien BEAU
2d392ce465 [FIX] fix product view with variant 2017-01-31 15:41:40 +01:00
Sébastien BEAU
e71ad5f952 [IMP] add module partner split menu to avoid the mix of contact and main partner 2017-01-26 14:40:47 +01:00
Alexis de Lattre
3905a826fa Small improvements on contracts view 2017-01-20 19:54:22 +01:00
Alexis de Lattre
18ea374d8c Add module account_analytic_analysis_usability 2017-01-20 19:27:55 +01:00
Alexis de Lattre
f8d3340e48 Better name 2017-01-20 18:43:12 +01:00
Alexis de Lattre
9761c7527b Improvement on invoice lines and analytic accounts 2017-01-20 18:22:37 +01:00
Alexis de Lattre
baf7359cc7 Show state column in all crm.phonecall tree view 2017-01-19 18:43:40 +01:00
Sébastien BEAU
33561ed930 [FIX] create variant manually is not allowed 2017-01-16 11:52:07 +01:00
Sébastien BEAU
aad2121f20 [IMP] add module product_variant_usability 2017-01-10 15:29:37 +01:00
Sébastien BEAU
880cf7c7a9 [ADD] add module product_simple_accounting to simplify the product form regarding accounting 2017-01-09 19:35:46 +01:00
Alexis de Lattre
d3eef1e5a5 Add start_date and end_date on bank statements 2016-12-21 21:13:40 +01:00
199 changed files with 2791 additions and 368 deletions

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import account_analytic_analysis

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Analytic Analysis Usability',
'version': '8.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Usability improvements on Account Analytic Analysis',
'description': """
Account Analytic Analysis Usability
===================================
Usability improvements include:
* add next invoice date in tree view of contrats (and add a group by)
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['account_analytic_analysis'],
'data': [
'analytic_view.xml',
],
'installable': False,
}

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields
class AccountAnalyticAccount(models.Model):
_inherit = "account.analytic.account"
recurring_next_date = fields.Date(track_visibility='onchange')
recurring_rule_type = fields.Selection(track_visibility='onchange')
recurring_interval = fields.Integer(track_visibility='onchange')
recurring_invoices = fields.Boolean(track_visibility='onchange')

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="view_account_analytic_account_tree_c2c_3" model="ir.ui.view">
<field name="name">usability.analytic_analysis.account.analytic.account.tree.contract</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="account_analytic_analysis.view_account_analytic_account_tree_c2c_3"/>
<field name="groups_id" eval="[(4, ref('account.group_account_invoice'))]"/>
<field name="arch" type="xml">
<field name="date" position="after">
<field name="recurring_rule_type"/>
<field name="recurring_next_date"/>
</field>
</field>
</record>
<record id="view_account_analytic_account_overdue_search" model="ir.ui.view">
<field name="name">usability.analytic_analysis.account.analytic.account.search</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="account_analytic_analysis.view_account_analytic_account_overdue_search"/>
<field name="arch" type="xml">
<filter context="{'group_by' : 'pricelist_id'}" position="after">
<filter name="recurring_rule_type_groupby" string="Invoicing Frequency" context="{'group_by': 'recurring_rule_type'}"/>
<filter name="recurring_next_date_groupby" string="Next Invoice Date" context="{'group_by': 'recurring_next_date'}"/>
</filter>
<filter name="cancelled" position="after">
<separator/>
<filter name="recurring_invoices" string="Recurring Invoicing" domain="[('recurring_invoices', '=', True)]"/>
</filter>
</field>
</record>
</data>
</openerp>

View File

@@ -45,5 +45,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account_bank_statement_import'], 'depends': ['account_bank_statement_import'],
'data': ['account_view.xml'], 'data': ['account_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -42,5 +42,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account_credit_control', 'partner_aged_open_invoices'], 'depends': ['account_credit_control', 'partner_aged_open_invoices'],
'data': ['account_credit_control_view.xml'], 'data': ['account_credit_control_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -20,5 +20,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account_cutoff_accrual_picking', 'report_aeroo'], 'depends': ['account_cutoff_accrual_picking', 'report_aeroo'],
'data': ['report.xml'], 'data': ['report.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -39,5 +39,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account_cutoff_prepaid', 'report_aeroo'], 'depends': ['account_cutoff_prepaid', 'report_aeroo'],
'data': ['report.xml'], 'data': ['report.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -43,5 +43,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account_banking_sepa_direct_debit', 'account_payment_partner'], 'depends': ['account_banking_sepa_direct_debit', 'account_payment_partner'],
'data': [], 'data': [],
'installable': True, 'installable': False,
} }

View File

@@ -22,5 +22,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'data': [ 'data': [
'account_fiscal_position_view.xml', 'account_fiscal_position_view.xml',
], ],
'installable': True, 'installable': False,
} }

View File

@@ -39,5 +39,5 @@ Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account'], 'depends': ['account'],
'data': [], 'data': [],
'installable': True, 'installable': False,
} }

View File

@@ -26,5 +26,5 @@ This module has been written by Alexis de Lattre from Akretion
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account', 'base_usability'], 'depends': ['account', 'base_usability'],
'data': ['account_view.xml'], 'data': ['account_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -40,5 +40,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'author': 'Akretion', 'author': 'Akretion',
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account'], 'depends': ['account'],
'installable': True, 'installable': False,
} }

View File

@@ -39,5 +39,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account'], 'depends': ['account'],
'data': ['account_invoice_view.xml'], 'data': ['account_invoice_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -39,5 +39,5 @@ This module has been written by Alexis de Lattre from Akretion
'data': [ 'data': [
'account_invoice_view.xml', 'account_invoice_view.xml',
], ],
'installable': True, 'installable': False,
} }

View File

@@ -37,5 +37,5 @@ This module has been written by Alexis de Lattre from Akretion
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account_invoice_margin', 'bi_invoice_company_currency'], 'depends': ['account_invoice_margin', 'bi_invoice_company_currency'],
'data': [], 'data': [],
'installable': True, 'installable': False,
} }

View File

@@ -39,5 +39,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account'], 'depends': ['account'],
'data': ['company_view.xml'], 'data': ['company_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -36,7 +36,7 @@ Adds a function field named *picking_ids_label* on invoices. This field contains
'website': 'http://www.akretion.com/', 'website': 'http://www.akretion.com/',
'depends': ['stock_account'], 'depends': ['stock_account'],
'data': [], 'data': [],
'installable': True, 'installable': False,
'active': False, 'active': False,
} }

View File

@@ -41,6 +41,6 @@ Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['sale'], 'depends': ['sale'],
'data': ['account_invoice_view.xml'], 'data': ['account_invoice_view.xml'],
'installable': True, 'installable': False,
'active': False, 'active': False,
} }

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import wizard

View File

@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Invoice Update Wizard',
'version': '8.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Wizard to update non-legal fields of an open/paid invoice',
'description': """
Account Invoice Update Wizard
=============================
This module adds a button *Update Invoice* on Customer and Supplier invoices in Open or Paid state. This button starts a wizard which allows the user to update non-legal fields of the invoice:
* Source Document
* Reference/Description
* Payment terms (update allowed only to a payment term with same number of terms of the same amount and on invoices without any payment)
* Bank Account
* Salesman
* Notes
* Description of invoice lines
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['account'],
'data': [
'wizard/account_invoice_update_view.xml',
'views/account_invoice.xml',
],
'installable': False,
}

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="invoice_supplier_form" model="ir.ui.view">
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form"/>
<field name="arch" type="xml">
<button name="invoice_cancel" position="before">
<button name="%(account_invoice_update_action)d" type="action" string="Update Invoice" states="open,paid" groups="account.group_account_invoice"/>
</button>
</field>
</record>
<record id="invoice_form" model="ir.ui.view">
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<button name="invoice_cancel" position="before">
<button name="%(account_invoice_update_action)d" type="action" string="Update Invoice" states="open,paid" groups="account.group_account_invoice"/>
</button>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import account_invoice_update

View File

@@ -0,0 +1,206 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp.exceptions import Warning as UserError
import openerp.addons.decimal_precision as dp
class AccountInvoiceUpdate(models.TransientModel):
_name = 'account.invoice.update'
_description = 'Wizard to update non-legal fields of invoice'
invoice_id = fields.Many2one(
'account.invoice', string='Invoice', required=True,
readonly=True)
type = fields.Selection(related='invoice_id.type', readonly=True)
company_id = fields.Many2one(
related='invoice_id.company_id', readonly=True)
commercial_partner_id = fields.Many2one(
related='invoice_id.commercial_partner_id', readonly=True)
user_id = fields.Many2one('res.users', string='Salesperson')
# I use the same field name as the original invoice field name
# even if it the name is "bad"
# Updating payment_term will not work if you use
# the OCA module account_constraints (you will just get an error)
payment_term = fields.Many2one(
'account.payment.term', string='Payment Terms')
reference = fields.Char(string='Invoice Reference')
name = fields.Char(string='Reference/Description')
origin = fields.Char(string='Source Document')
comment = fields.Text('Additional Information')
partner_bank_id = fields.Many2one(
'res.partner.bank', string='Bank Account')
line_ids = fields.One2many(
'account.invoice.line.update', 'parent_id', string='Invoice Lines')
@api.model
def _simple_fields2update(self):
'''List boolean, date, datetime, char, text fields'''
return ['reference', 'name', 'origin', 'comment']
@api.model
def _m2o_fields2update(self):
return ['payment_term', 'user_id', 'partner_bank_id']
@api.model
def _prepare_default_get(self, invoice):
res = {'invoice_id': invoice.id, 'line_ids': []}
for sfield in self._simple_fields2update():
res[sfield] = invoice[sfield]
for m2ofield in self._m2o_fields2update():
res[m2ofield] = invoice[m2ofield].id or False
for line in invoice.invoice_line:
res['line_ids'].append({
'invoice_line_id': line.id,
'name': line.name,
'quantity': line.quantity,
'price_subtotal': line.price_subtotal,
})
return res
@api.model
def default_get(self, fields_list):
res = super(AccountInvoiceUpdate, self).default_get(fields_list)
assert self._context.get('active_model') == 'account.invoice',\
'active_model should be account.invoice'
inv = self.env['account.invoice'].browse(self._context['active_id'])
res = self._prepare_default_get(inv)
return res
@api.onchange('type')
def type_on_change(self):
res = {'domain': {}}
if self.type in ('out_invoice', 'out_refund'):
res['domain']['partner_bank_id'] =\
"[('partner_id.ref_companies', 'in', [company_id])]"
else:
res['domain']['partner_bank_id'] =\
"[('partner_id', '=', commercial_partner_id)]"
return res
@api.multi
def _prepare_invoice(self):
vals = {}
inv = self.invoice_id
for sfield in self._simple_fields2update():
if self[sfield] != inv[sfield]:
vals[sfield] = self[sfield]
for m2ofield in self._m2o_fields2update():
if self[m2ofield] != inv[m2ofield]:
vals[m2ofield] = self[m2ofield].id or False
if 'payment_term' in vals:
pterm_list = self.payment_term.compute(
value=1, date_ref=inv.date_invoice)[0]
if pterm_list:
vals['date_due'] = max(line[0] for line in pterm_list)
return vals
@api.model
def _prepare_invoice_line(self, line):
vals = {}
if line.name != line.invoice_line_id.name:
vals['name'] = line.name
return vals
@api.multi
def _prepare_move(self):
mvals = {}
inv = self.invoice_id
ini_ref = inv.move_id.ref
ref = inv.reference or inv.name
if ini_ref != ref:
mvals['ref'] = ref
return mvals
@api.multi
def _update_payment_term_move(self):
self.ensure_one()
inv = self.invoice_id
if (
self.payment_term and
self.payment_term != inv.payment_term and
inv.move_id and
inv.move_id.period_id.state == 'draft'):
# I don't update pay term when the invoice is partially (or fully)
# paid because if you have a payment term with several lines
# of the same amount, you would also have to take into account
# the reconcile marks to put the new maturity date on the right
# lines
if inv.payment_ids:
raise UserError(_(
"This wizard doesn't support the update of payment "
"terms on an invoice which is partially or fully "
"paid."))
prec = self.env['decimal.precision'].precision_get('Account')
term_res = self.payment_term.compute(
inv.amount_total, inv.date_invoice)[0]
new_pterm = {} # key = int(amount * 100), value = [date1, date2]
for entry in term_res:
amount = int(entry[1] * 10 * prec)
if amount in new_pterm:
new_pterm[amount].append(entry[0])
else:
new_pterm[amount] = [entry[0]]
mlines = {} # key = int(amount * 100), value : [line1, line2]
for line in inv.move_id.line_id:
if line.account_id == inv.account_id:
amount = int(abs(line.credit - line.debit) * 10 * prec)
if amount in mlines:
mlines[amount].append(line)
else:
mlines[amount] = [line]
for iamount, lines in mlines.iteritems():
if len(lines) != len(new_pterm.get(iamount, [])):
raise UserError(_(
"The original payment term '%s' doesn't have the "
"same terms (number of terms and/or amount) as the "
"new payment term '%s'. You can only switch to a "
"payment term that has the same number of terms "
"with the same amount.") % (
inv.payment_term.name, self.payment_term.name))
for line in lines:
line.date_maturity = new_pterm[iamount].pop()
@api.multi
def run(self):
self.ensure_one()
inv = self.invoice_id
updated = False
# re-write date_maturity on move line
self._update_payment_term_move()
ivals = self._prepare_invoice()
if ivals:
updated = True
inv.write(ivals)
for line in self.line_ids:
ilvals = self._prepare_invoice_line(line)
if ilvals:
updated = True
line.invoice_line_id.write(ilvals)
if inv.move_id and inv.move_id.period_id.state == 'draft':
mvals = self._prepare_move()
if mvals:
inv.move_id.write(mvals)
if updated:
inv.message_post(_(
'Non-legal fields of invoice updated via the Invoice Update '
'wizard.'))
return True
class AccountInvoiceLineUpdate(models.TransientModel):
_name = 'account.invoice.line.update'
_description = 'Update non-legal fields of invoice lines'
parent_id = fields.Many2one(
'account.invoice.update', string='Wizard', ondelete='cascade')
invoice_line_id = fields.Many2one(
'account.invoice.line', string='Invoice Line', readonly=True)
name = fields.Text(string='Description', required=True)
quantity = fields.Float(
string='Quantity', digits=dp.get_precision('Product Unit of Measure'),
readonly=True)
price_subtotal = fields.Float(
string='Amount', readonly=True, digits=dp.get_precision('Account'))

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="account_invoice_update_form" model="ir.ui.view">
<field name="model">account.invoice.update</field>
<field name="arch" type="xml">
<form string="Update Invoice Wizard">
<group name="main">
<field name="invoice_id" invisible="1"/>
<field name="type" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="commercial_partner_id" invisible="1"/>
<field name="reference" attrs="{'invisible': [('type', 'not in', ('in_invoice', 'in_refund'))]}"/>
<field name="origin"/>
<field name="name"/>
<field name="payment_term" widget="selection"/>
<field name="partner_bank_id"/>
<field name="user_id"/>
<field name="comment"/>
</group>
<group name="lines">
<field name="line_ids" nolabel="1">
<tree editable="bottom">
<field name="invoice_line_id" invisible="1"/>
<field name="name"/>
<field name="quantity"/>
<field name="price_subtotal"/>
</tree>
</field>
</group>
<footer>
<button name="run" type="object" class="oe_highlight" string="Update"/>
or
<button special="cancel" string="Cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
<record id="account_invoice_update_action" model="ir.actions.act_window">
<field name="name">Invoice Update Wizard</field>
<field name="res_model">account.invoice.update</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@@ -39,5 +39,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account_usability'], 'depends': ['account_usability'],
'data': ['wizard/account_move_line_filter_view.xml'], 'data': ['wizard/account_move_line_filter_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -53,7 +53,10 @@ class AccountMoveLineFilterWizard(models.TransientModel):
self.ensure_one() self.ensure_one()
action = self.env['ir.actions.act_window'].for_xml_id( action = self.env['ir.actions.act_window'].for_xml_id(
'account', 'action_account_moves_all_a') 'account', 'action_account_moves_all_a')
action['context'] = {'search_default_account_id': [self.account_id.id]} action['context'] = {
'search_default_account_id': [self.account_id.id],
'journal_show_code_only': True,
}
if self.partner_id: if self.partner_id:
action['context']['search_default_partner_id'] =\ action['context']['search_default_partner_id'] =\
[self.partner_id.id] [self.partner_id.id]

View File

@@ -40,5 +40,5 @@ This module has been written by Alexis de Lattre from Akretion
'website': 'http://www.akretion.com/', 'website': 'http://www.akretion.com/',
'depends': ['account_cutoff_prepaid', 'account_move_line_report_xls'], 'depends': ['account_cutoff_prepaid', 'account_move_line_report_xls'],
'data': [], 'data': [],
'installable': True, 'installable': False,
} }

View File

@@ -21,9 +21,16 @@
############################################################################## ##############################################################################
import xlwt import xlwt
import logging
from openerp import models, api from openerp import models, api
from openerp.addons.report_xls.utils import _render
from openerp.addons.report_xls.report_xls import report_xls _logger = logging.getLogger(__name__)
try:
from openerp.addons.report_xls.utils import _render
from openerp.addons.report_xls.report_xls import report_xls
except (ImportError, IOError) as err:
_logger.debug(err)
class AccountMoveLine(models.Model): class AccountMoveLine(models.Model):

View File

@@ -37,4 +37,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'author': 'Akretion', 'author': 'Akretion',
'depends': ['account_payment'], 'depends': ['account_payment'],
'data': ['payment_view.xml'], 'data': ['payment_view.xml'],
'installable': False,
} }

View File

@@ -40,4 +40,5 @@ Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for
'payment_view.xml', 'payment_view.xml',
], ],
'active': False, 'active': False,
'installable': False,
} }

View File

@@ -42,4 +42,5 @@ Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for
'security/ir.model.access.csv', 'security/ir.model.access.csv',
], ],
'active': False, 'active': False,
'installable': False,
} }

View File

@@ -50,5 +50,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'depends': ['account'], 'depends': ['account'],
'conflicts': ['account_invoice_overdue_filter'], 'conflicts': ['account_invoice_overdue_filter'],
'data': ['account_view.xml'], 'data': ['account_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -23,6 +23,8 @@
from openerp import models, fields, api, _ from openerp import models, fields, api, _
from openerp.tools import float_compare from openerp.tools import float_compare
from openerp.exceptions import Warning as UserError from openerp.exceptions import Warning as UserError
import logging
logger = logging.getLogger(__name__)
class AccountInvoice(models.Model): class AccountInvoice(models.Model):
@@ -43,7 +45,8 @@ class AccountInvoice(models.Model):
fiscal_position = fields.Many2one(track_visibility='onchange') fiscal_position = fields.Many2one(track_visibility='onchange')
@api.multi @api.multi
def onchange_payment_term_date_invoice(self, payment_term_id, date_invoice): def onchange_payment_term_date_invoice(
self, payment_term_id, date_invoice):
res = super(AccountInvoice, self).onchange_payment_term_date_invoice( res = super(AccountInvoice, self).onchange_payment_term_date_invoice(
payment_term_id, date_invoice) payment_term_id, date_invoice)
if res and isinstance(res, dict) and 'value' in res: if res and isinstance(res, dict) and 'value' in res:
@@ -54,8 +57,8 @@ class AccountInvoice(models.Model):
# generated from customer invoices linked to the partners' account because: # generated from customer invoices linked to the partners' account because:
# 1) the label of an account move line is an important field, we can't # 1) the label of an account move line is an important field, we can't
# write a rubbish '/' in it ! # write a rubbish '/' in it !
# 2) the 'name' field of the account.move.line is used in the overdue letter, # 2) the 'name' field of the account.move.line is used in the overdue
# and '/' is not meaningful for our customer ! # letter and '/' is not meaningful for our customer !
@api.multi @api.multi
def action_number(self): def action_number(self):
res = super(AccountInvoice, self).action_number() res = super(AccountInvoice, self).action_number()
@@ -69,6 +72,28 @@ class AccountInvoice(models.Model):
return res return res
class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'
# In the 'account' module, we have related stored field for:
# company_id, partner_id
currency_id = fields.Many2one(
related='invoice_id.currency_id', readonly=True, store=True)
invoice_type = fields.Selection(
related='invoice_id.type', store=True, readonly=True)
date_invoice = fields.Date(
related='invoice_id.date_invoice', store=True, readonly=True)
commercial_partner_id = fields.Many2one(
related='invoice_id.partner_id.commercial_partner_id',
store=True, readonly=True)
state = fields.Selection(
related='invoice_id.state', store=True, readonly=True,
string='Invoice State')
invoice_number = fields.Char(
related='invoice_id.move_id.name', store=True, readonly=True,
string='Invoice Number')
class AccountFiscalYear(models.Model): class AccountFiscalYear(models.Model):
_inherit = 'account.fiscalyear' _inherit = 'account.fiscalyear'
@@ -105,10 +130,36 @@ class AccountAccount(models.Model):
else: else:
return super(AccountAccount, self).name_get() return super(AccountAccount, self).name_get()
@api.model
def check_account_hierarchy(self):
'''designed to be called by a script'''
accounts = self.env['account.account'].search([])
parent_accounts = self
for account in accounts:
if account.parent_id and account.parent_id not in parent_accounts:
parent_accounts += account.parent_id
err_msg = []
view_user_type = self.env.ref('account.data_account_type_view')
for pacc in parent_accounts:
if pacc.type != 'view':
err_msg.append(_(
'Parent account %s should have type=view '
'(current type=%s)') % (pacc.code, pacc.type))
if pacc.user_type != view_user_type:
err_msg.append(_(
'Parent account %s should have user_type=view (current '
'(user_type=%s)') % (pacc.code, pacc.user_type.name))
if err_msg:
raise UserError('\n'.join(err_msg))
class AccountAnalyticAccount(models.Model): class AccountAnalyticAccount(models.Model):
_inherit = 'account.analytic.account' _inherit = 'account.analytic.account'
invoice_line_ids = fields.One2many(
'account.invoice.line', 'account_analytic_id', 'Invoice Lines',
readonly=True)
@api.multi @api.multi
def name_get(self): def name_get(self):
if self._context.get('analytic_account_show_code_only'): if self._context.get('analytic_account_show_code_only'):
@@ -125,11 +176,51 @@ class AccountAnalyticAccount(models.Model):
class AccountMove(models.Model): class AccountMove(models.Model):
_inherit = 'account.move' _inherit = 'account.move'
# When ref is too long, the PDF general ledger report becomes
# unreadable
ref = fields.Char(size=32)
# If you want to migrate existing data :
# update account_move set ref=left(ref,32) where ref is not null;
# update account_move_line set ref=left(ref,32) where ref is not null;
@api.onchange('date') @api.onchange('date')
def date_onchange(self): def date_onchange(self):
if self.date: if self.date:
self.period_id = self.env['account.period'].find(self.date) self.period_id = self.env['account.period'].find(self.date)
@api.model
def delete_move_no_lines(self):
'''designed to be called by a script'''
moves_no_lines = self.search([('line_id', '=', False)])
inv_moves_sr = self.env['account.invoice'].search_read(
[('move_id', '!=', False)], ['move_id'])
move2inv = {} # key=move_id, value=invoice_id
invoice_move_no_line = {} # key=ID, value=number
deleted_move_ids = []
for inv_move_sr in inv_moves_sr:
move2inv[inv_move_sr['move_id'][0]] = inv_move_sr['id']
for move in moves_no_lines:
for l in move.line_id:
raise UserError(_('Move %d has a line !') % move.id)
if move.id not in move2inv:
if move.state == 'posted':
move.state = 'draft'
deleted_move_ids.append(move.id)
move.unlink()
else:
invoice_move_no_line[move2inv[move.id]] = move.name
if deleted_move_ids:
logger.info(
'Account move IDs %s have been deleted because they '
'had 0 lines', deleted_move_ids)
else:
logger.info('0 moves without lines found')
if invoice_move_no_line:
for inv_id, inv_number in invoice_move_no_line.iteritems():
logger.info(
'Invoice ID %d number %s has a move with 0 lines',
inv_id, inv_number)
class AccountMoveLine(models.Model): class AccountMoveLine(models.Model):
_inherit = 'account.move.line' _inherit = 'account.move.line'
@@ -163,6 +254,28 @@ class AccountMoveLine(models.Model):
else: else:
self.credit = amount_company_currency self.credit = amount_company_currency
analytic_account_id = fields.Many2one(
domain=[('type', 'not in', ('view', 'template'))])
class AccountBankStatement(models.Model):
_inherit = 'account.bank.statement'
start_date = fields.Date(
compute='_compute_dates', string='Start Date', readonly=True,
store=True)
end_date = fields.Date(
compute='_compute_dates', string='End Date', readonly=True,
store=True)
@api.multi
@api.depends('line_ids.date')
def _compute_dates(self):
for st in self:
dates = [line.date for line in st.line_ids]
st.start_date = dates and min(dates) or False
st.end_date = dates and max(dates) or False
class AccountBankStatementLine(models.Model): class AccountBankStatementLine(models.Model):
_inherit = 'account.bank.statement.line' _inherit = 'account.bank.statement.line'
@@ -210,6 +323,7 @@ class AccountBankStatementLine(models.Model):
raise UserError(_( raise UserError(_(
'No journal entry linked to this bank statement line.')) 'No journal entry linked to this bank statement line.'))
class ResPartner(models.Model): class ResPartner(models.Model):
_inherit = 'res.partner' _inherit = 'res.partner'

View File

@@ -65,6 +65,118 @@
</field> </field>
</record> </record>
<!-- Having a menu entry on invoice lines is often very usefull for odoo user:
they can search in their lines, etc...
So I enhance the generic views and add actions, but I don't add menu entries here ;
the creation of the corresponding menu entry should be done in the customer-specific
module -->
<record id="view_invoice_line_tree" model="ir.ui.view">
<field name="name">account_usability.invoice_line_tree</field>
<field name="model">account.invoice.line</field>
<field name="inherit_id" ref="account.view_invoice_line_tree"/>
<field name="arch" type="xml">
<field name="name" position="before">
<field name="partner_id" invisible="not context.get('show_invoice_fields')"/>
<field name="date_invoice" invisible="not context.get('show_invoice_fields')"/>
<field name="invoice_number" invisible="not context.get('show_invoice_fields')"/>
</field>
<field name="price_subtotal" position="after">
<field name="currency_id"/>
<field name="state" invisible="not context.get('show_invoice_fields')"/>
<field name="invoice_type" invisible="1"/>
</field>
<xpath expr="/tree" position="attributes">
<attribute name="edit">0</attribute>
<attribute name="create">0</attribute>
</xpath>
</field>
</record>
<record id="account_invoice_line_search" model="ir.ui.view">
<field name="name">account_usability.invoice_line_search</field>
<field name="model">account.invoice.line</field>
<field name="arch" type="xml">
<search string="Search Invoice Lines">
<field name="partner_id"/>
<field name="product_id"/>
<field name="account_id"/>
<field name="invoice_number"/>
<field name="name"/>
<filter name="out_invoice" string="Customer Invoices"
domain="[('invoice_type', '=', 'out_invoice')]"/>
<filter name="out_refund" string="Customer Refunds"
domain="[('invoice_type', '=', 'out_refund')]"/>
<filter name="in_invoice" string="Supplier Invoices"
domain="[('invoice_type', '=', 'in_invoice')]"/>
<filter name="in_refund" string="Supplier Refunds"
domain="[('invoice_type', '=', 'in_refund')]"/>
<separator/>
<filter name="draft" string="Draft" domain="[('state', '=', 'draft')]"/>
<filter name="unpaid" string="Not Paid" domain="[('state', '=', 'open')]"/>
<filter name="paid" string="Paid" domain="[('state', '=', 'paid')]"/>
<group string="Group By" name="groupby">
<filter name="partner_groupby" string="Partner"
context="{'group_by': 'partner_id'}"/>
<filter name="commercial_partner_group_by" string="Commercial Partner"
context="{'group_by': 'commercial_partner_id'}"/>
<filter name="date_groupby" string="Invoice Date"
context="{'group_by': 'date_invoice'}"/>
<filter name="product_groupby" string="Product"
context="{'group_by': 'product_id'}"/>
<filter name="account_groupby" string="Account"
context="{'group_by': 'account_id'}"/>
</group>
</search>
</field>
</record>
<record id="out_invoice_line_action" model="ir.actions.act_window">
<field name="name">Customer Invoice Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'out_invoice')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="out_refund_line_action" model="ir.actions.act_window">
<field name="name">Customer Refund Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'out_refund')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="in_invoice_line_action" model="ir.actions.act_window">
<field name="name">Supplier Invoice Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'in_invoice')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="in_refund_line_action" model="ir.actions.act_window">
<field name="name">Supplier Refund Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'in_refund')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="view_account_invoice_report_search" model="ir.ui.view">
<field name="name">usability.account.invoice.report.search</field>
<field name="model">account.invoice.report</field>
<field name="inherit_id" ref="account.view_account_invoice_report_search"/>
<field name="arch" type="xml">
<field name="categ_id" position="after">
<field name="product_id"/>
</field>
<filter name="category_product" position="after">
<filter string="Product" name="product_group_by" context="{'group_by': 'product_id'}"/>
</filter>
</field>
</record>
<!-- model account.move.line / Journal Items --> <!-- model account.move.line / Journal Items -->
<record id="account.action_account_moves_all_a" model="ir.actions.act_window"> <record id="account.action_account_moves_all_a" model="ir.actions.act_window">
<field name="limit">200</field> <field name="limit">200</field>
@@ -101,6 +213,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="partner_id" position="after"> <field name="partner_id" position="after">
<field name="reconcile_ref" /> <field name="reconcile_ref" />
<field name="debit" filter_domain="['|', ('debit', '=', self), ('credit', '=', self)]" string="Debit or Credit"/>
</field> </field>
<filter name="unreconciled" position="before"> <filter name="unreconciled" position="before">
<filter name="reconciled" string="Fully Reconciled" domain="[('reconcile_id', '!=', False)]"/> <filter name="reconciled" string="Fully Reconciled" domain="[('reconcile_id', '!=', False)]"/>
@@ -128,6 +241,7 @@
<field name="name">account_usability.account_move_line_tree</field> <field name="name">account_usability.account_move_line_tree</field>
<field name="model">account.move.line</field> <field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_tree"/> <field name="inherit_id" ref="account.view_move_line_tree"/>
<field name="priority">1</field> <!-- to be compatible with account_analytic_plans which removes the field analytic_account_id and has a priority of 2 -->
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="analytic_account_id" position="attributes"> <field name="analytic_account_id" position="attributes">
<attribute name="invisible"></attribute> <attribute name="invisible"></attribute>
@@ -189,6 +303,12 @@
</field> </field>
</record> </record>
<!-- When you click on the "Contract" button of partner form view,
the newly created analytic accounts should be of type contract ! -->
<record id="account.action_open_partner_analytic_accounts" model="ir.actions.act_window">
<field name="context">{'search_default_partner_id': [active_id], 'default_partner_id': active_id, 'default_type': 'contract'}</field>
</record>
<record id="view_bank_statement_form" model="ir.ui.view"> <record id="view_bank_statement_form" model="ir.ui.view">
<field name="name">usability.account.bank.statement.form</field> <field name="name">usability.account.bank.statement.form</field>
<field name="model">account.bank.statement</field> <field name="model">account.bank.statement</field>
@@ -200,6 +320,65 @@
string="View Account Move" icon="gtk-redo" string="View Account Move" icon="gtk-redo"
attrs="{'invisible': [('journal_entry_id', '=', False)]}"/> attrs="{'invisible': [('journal_entry_id', '=', False)]}"/>
</xpath> </xpath>
<field name="company_id" position="before">
<field name="start_date"/>
<field name="end_date"/>
</field>
</field>
</record>
<record id="view_bank_statement_tree" model="ir.ui.view">
<field name="name">usability.account.bank.statement.tree</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_tree"/>
<field name="arch" type="xml">
<field name="period_id" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="journal_id" position="after">
<field name="start_date"/>
<field name="end_date"/>
</field>
</field>
</record>
<record id="view_bank_statement_search" model="ir.ui.view">
<field name="name">usability.account.bank.statement.search</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_search"/>
<field name="arch" type="xml">
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<filter context="{'group_by': 'period_id'}" position="attributes">
<attribute name="invisible">1</attribute>
</filter>
<filter context="{'group_by': 'period_id'}" position="after">
<filter name="start_date_groupby" string="Start Date"
context="{'group_by': 'start_date'}"/>
<filter name="end_date_groupby" string="End Date"
context="{'group_by': 'end_date'}"/>
</filter>
<field name="date" position="after">
<field name="start_date"/>
<field name="end_date"/>
</field>
</field>
</record>
<record id="view_account_analytic_account_form" model="ir.ui.view">
<field name="name">analytic.analytic.account.form</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
<field name="arch" type="xml">
<notebook position="inside">
<page name="invoice_lines" string="Related Invoice Lines" attrs="{'invisible': [('type', 'not in', ('contract', 'normal'))]}">
<field name="invoice_line_ids" nolabel="1" context="{'show_invoice_fields': 1}"/>
</page>
</notebook>
</field> </field>
</record> </record>

View File

@@ -39,5 +39,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account_voucher'], 'depends': ['account_voucher'],
'data': [], 'data': [],
'installable': True, 'installable': False,
} }

View File

@@ -48,5 +48,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'report_aeroo', 'report_aeroo',
'base_other_report_engines', 'base_other_report_engines',
], ],
'installable': True, 'installable': False,
} }

View File

@@ -21,5 +21,5 @@ Contributors: David BEAL
'data': [ 'data': [
'view.xml', 'view.xml',
], ],
'installable': True, 'installable': False,
} }

View File

@@ -41,5 +41,5 @@ This module adds 2 fields on the Company :
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['base'], 'depends': ['base'],
'data': ['company_view.xml'], 'data': ['company_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -39,5 +39,5 @@ Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['base'], 'depends': ['base'],
'data': [], 'data': [],
'installable': True, 'installable': False,
} }

View File

@@ -37,6 +37,6 @@ By default, you can't enter several addresses for an individual in OpenERP becau
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['base'], 'depends': ['base'],
'data': ['partner_view.xml'], 'data': ['partner_view.xml'],
'installable': True, 'installable': False,
'active': False, 'active': False,
} }

View File

@@ -53,5 +53,5 @@ A group by 'State' is added to module search view.
'module_view.xml', 'module_view.xml',
'translation_view.xml', 'translation_view.xml',
], ],
'installable': True, 'installable': False,
} }

View File

@@ -5,7 +5,7 @@
{ {
'name': 'CRM Usability', 'name': 'CRM Usability',
'version': '8.0.1.0.0', 'version': '8.0.1.0.1',
'category': 'Customer Relationship Management', 'category': 'Customer Relationship Management',
'license': 'AGPL-3', 'license': 'AGPL-3',
'summary': 'CRM usability enhancements', 'summary': 'CRM usability enhancements',
@@ -13,10 +13,12 @@
CRM Usability CRM Usability
============= =============
Some enhancements in the *Merge Partners* wizard: The usability improvements include :
* take into account the unaccent option of the server config file * Adds multi-company record rules on crm.lead.
* add optional group by on 'customer' and 'supplier' (active by default) * Some enhancements in the *Merge Partners* wizard:
* take into account the unaccent option of the server config file
* add optional group by on 'customer' and 'supplier' (active by default)
This module has been written by Alexis de Lattre from Akretion This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>. <alexis.delattre@akretion.com>.
@@ -24,6 +26,10 @@ This module has been written by Alexis de Lattre from Akretion
'author': 'Akretion', 'author': 'Akretion',
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['crm'], 'depends': ['crm'],
'data': ['wizard/base_partner_merge_view.xml'], 'data': [
'installable': True, 'crm_view.xml',
'wizard/base_partner_merge_view.xml',
'security/rule.xml',
],
'installable': False,
} }

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="crm_case_form_view_oppor" model="ir.ui.view">
<field name="name">usability.crm.opportunity.form</field>
<field name="model">crm.lead</field>
<field name="inherit_id" ref="crm.crm_case_form_view_oppor"/>
<field name="arch" type="xml">
<field name="active" position="before">
<field name="company_id" groups="base.group_multi_company"
widget="selection"/>
</field>
</field>
</record>
<record id="crm_case_inbound_phone_tree_view" model="ir.ui.view">
<field name="name">crm_usability.crm.phonecall.tree.inbound</field>
<field name="model">crm.phonecall</field>
<field name="inherit_id" ref="crm.crm_case_inbound_phone_tree_view"/>
<field name="arch" type="xml">
<field name="state" position="attributes">
<attribute name="invisible">0</attribute>
</field>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="crm_lead_company_rule" model="ir.rule">
<field name="name">Lead/opportunity multi-company rule</field>
<field name="model_id" ref="crm.model_crm_lead"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record>
</data>
</openerp>

View File

@@ -39,5 +39,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['delivery'], 'depends': ['delivery'],
'data': [], 'data': [],
'installable': True, 'installable': False,
} }

View File

@@ -23,7 +23,7 @@
{ {
'name': 'Eradicate Quick Create', 'name': 'Eradicate Quick Create',
'version': '0.1', 'version': '9.0.1.0.0',
'category': 'Tools', 'category': 'Tools',
'license': 'AGPL-3', 'license': 'AGPL-3',
'summary': 'Disable quick create on all objects', 'summary': 'Disable quick create on all objects',
@@ -39,4 +39,5 @@ Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com> for
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['base_optional_quick_create'], 'depends': ['base_optional_quick_create'],
'data': [], 'data': [],
'installable': True,
} }

View File

@@ -34,5 +34,5 @@
'data': [ 'data': [
'security/expense_security.xml', 'security/expense_security.xml',
], ],
'installable': True, 'installable': False,
} }

View File

@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
from . import company
from . import hr_holidays
from . import hr_employee
from . import lunch_voucher_attribution
from . import wizard

View File

@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'HR Holidays Lunch Voucher',
'version': '10.0.1.0.0',
'category': 'Human Resources',
'license': 'AGPL-3',
'summary': 'Manage lunch vouchers in holidays requests',
'description': '',
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['hr_holidays_usability', 'purchase'],
'data': [
'security/ir.model.access.csv',
'security/lunch_voucher_security.xml',
'product_data.xml',
'company_view.xml',
'wizard/lunch_voucher_purchase_view.xml',
'lunch_voucher_attribution_view.xml',
'hr_employee_view.xml',
'hr_holidays_view.xml',
'wizard/hr_holidays_post_view.xml',
],
'installable': False,
}

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields
import openerp.addons.decimal_precision as dp
class ResCompany(models.Model):
_inherit = 'res.company'
lunch_voucher_product_id = fields.Many2one(
'product.product', string='Lunch Voucher Product',
ondelete='restrict')
lunch_voucher_employer_price = fields.Float(
'Lunch Voucher Employer Price', digits=dp.get_precision('Account'))
# Add constrain to check that lunch_voucher_employer_price is between
# 50% and 60% of the price of lunch_voucher_product_id for France

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion France (www.akretion.com)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="view_company_form" model="ir.ui.view">
<field name="name">lunch_voucher.company.form</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<group name="account_grp" position="after">
<group name="lunch_voucher" string="Lunch Vouchers">
<field name="lunch_voucher_product_id"/>
<!-- <field name="lunch_voucher_po_type"/> -->
<field name="lunch_voucher_employer_price"/>
</group>
</group>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields
class HrEmployee(models.Model):
_inherit = 'hr.employee'
lunch_voucher = fields.Boolean(string="Has Lunch Vouchers", default=True)

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion France (www.akretion.com)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="view_employee_form_leave_inherit" model="ir.ui.view">
<field name="name">lunch_voucher.hr.employee.form</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr_holidays_usability.view_employee_form_leave_inherit"/>
<field name="arch" type="xml">
<group name="holidays" position="inside">
<field name="lunch_voucher"/>
</group>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api
from dateutil.relativedelta import relativedelta
class HrHolidays(models.Model):
_inherit = 'hr.holidays'
lunch_voucher_id = fields.Many2one(
'lunch.voucher.attribution',
string="Related Lunch Voucher Attribution")
lunch_voucher_remove_qty = fields.Integer(
compute='_compute_lunch_voucher_remove_qty', readonly=True,
store=True, string='Lunch Vouchers to Deduct')
@api.depends('employee_id', 'vacation_date_from', 'vacation_date_to')
@api.multi
def _compute_lunch_voucher_remove_qty(self):
hhpo = self.env['hr.holidays.public']
for hol in self:
qty = 0
if (
hol.type == 'remove' and
hol.vacation_date_from and
hol.vacation_date_to):
start_date_dt = fields.Date.from_string(hol.vacation_date_from)
end_date_str = hol.vacation_date_to
date_dt = start_date_dt
# Remove 1 full LV when vacation_time_from == noon
# and also when vacation_time_to == noon
while True:
if (
date_dt.weekday() not in (5, 6) and
not hhpo.is_public_holiday(
date_dt, hol.employee_id.id)):
qty += 1
date_dt += relativedelta(days=1)
date_str = fields.Date.to_string(date_dt)
if date_str > end_date_str:
break
hol.lunch_voucher_remove_qty = qty

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="edit_holiday_new" model="ir.ui.view">
<field name="name">hr_holidays_lunch_voucher.leave_request_form</field>
<field name="model">hr.holidays</field>
<field name="inherit_id" ref="hr_holidays_usability.edit_holiday_new"/>
<field name="arch" type="xml">
<group name="counters" position="after">
<group name="lunch_vouchers" string="Lunch Vouchers" attrs="{'invisible': [('type', '!=', 'remove')]}">
<field name="lunch_voucher_remove_qty"/>
<field name="lunch_voucher_id"/>
</group>
</group>
</field>
</record>
<record id="view_holiday" model="ir.ui.view">
<field name="name">hr_holidays_lunch_voucher.leave_request_tree</field>
<field name="model">hr.holidays</field>
<field name="inherit_id" ref="hr_holidays_usability.view_holiday"/>
<field name="arch" type="xml">
<field name="number_of_days" position="after">
<field name="lunch_voucher_remove_qty" string="Lunch Vouchers -=" sum="Total"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api
class LunchVoucherAttribution(models.Model):
_name = 'lunch.voucher.attribution'
_description = 'Lunch Voucher Attribution'
_order = 'date desc'
employee_id = fields.Many2one(
'hr.employee', string='Employee', ondelete='restrict',
required=True, readonly=True)
company_id = fields.Many2one(
related='employee_id.resource_id.company_id', readonly=True,
store=True)
date = fields.Date('Attribution Date', readonly=True)
purchase_id = fields.Many2one(
'purchase.order', 'Purchase Order',
readonly=True)
month_work_days = fields.Integer(
'Month Work Days',
help="Number of work days of the month (without taking into "
"account the holidays)")
no_lunch_days = fields.Integer(
compute='_compute_qty', string='No Lunch Days',
readonly=True, store=True)
qty = fields.Integer(
compute='_compute_qty', readonly=True, store=True,
string='Lunch Voucher Quantity')
holiday_ids = fields.One2many(
'hr.holidays', 'lunch_voucher_id', readonly=True)
@api.depends('month_work_days', 'holiday_ids.lunch_voucher_remove_qty')
@api.multi
def _compute_qty(self):
for rec in self:
no_lunch_days = 0
for hol in rec.holiday_ids:
no_lunch_days += hol.lunch_voucher_remove_qty
rec.no_lunch_days = no_lunch_days
rec.qty = rec.month_work_days - no_lunch_days

View File

@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion France (www.akretion.com)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="lunch_voucher_attribution_form" model="ir.ui.view">
<field name="name">lunch.voucher.attribution.form</field>
<field name="model">lunch.voucher.attribution</field>
<field name="arch" type="xml">
<form string="Lunch Vouchers Attribution">
<group name="main">
<field name="employee_id"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="date"/>
<field name="month_work_days"/>
<field name="no_lunch_days"/>
<field name="qty"/>
<field name="purchase_id"/>
</group>
<group name="holidays" string="Related Holidays">
<field name="holiday_ids" nolabel="1" context="{'tree_view_ref': 'hr_holidays_lunch_voucher.view_holiday', 'form_view_ref': 'hr_holidays_lunch_voucher.edit_holiday_new'}"/>
</group>
</form>
</field>
</record>
<record id="lunch_voucher_attribution_tree" model="ir.ui.view">
<field name="name">lunch.voucher.attribution.tree</field>
<field name="model">lunch.voucher.attribution</field>
<field name="arch" type="xml">
<tree string="Lunch Vouchers Attribution">
<field name="date"/>
<field name="employee_id"/>
<field name="month_work_days"/>
<field name="no_lunch_days" sum="Total"/>
<field name="qty" sum="Total"/>
<field name="purchase_id"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<record id="lunch_voucher_attribution_search" model="ir.ui.view">
<field name="name">lunch.voucher.attribution.search</field>
<field name="model">lunch.voucher.attribution</field>
<field name="arch" type="xml">
<search string="Search Lunch Vouchers Attribution">
<field name="date"/>
<field name="employee_id"/>
<filter name="purchased" string="Purchased" domain="[('purchase_id', '!=', False)]"/>
<filter name="to_purchase" string="To Purchase" domain="[('purchase_id', '=', False)]"/>
<group string="Group By" name="groupby">
<filter name="employee_groupby" string="Employee" context="{'group_by': 'employee_id'}"/>
<filter name="purchase_order_groupby" string="Purchase Order" context="{'group_by': 'purchase_id'}"/>
</group>
</search>
</field>
</record>
<record id="lunch_voucher_attribution_graph" model="ir.ui.view">
<field name="name">lunch.voucher.attribution.graph</field>
<field name="model">lunch.voucher.attribution</field>
<field name="arch" type="xml">
<graph string="Lunch Vouchers Attribution" type="pivot">
<field name="date" type="row" interval="month"/>
<field name="qty" type="measure"/>
</graph>
</field>
</record>
<record id="lunch_voucher_attribution_action" model="ir.actions.act_window">
<field name="name">Lunch Voucher Attribution</field>
<field name="res_model">lunch.voucher.attribution</field>
<field name="view_mode">tree,form,graph</field>
</record>
<menuitem id="lunch_voucher_attribution_menu"
action="lunch_voucher_attribution_action"
parent="hr_holidays.menu_open_ask_holidays" sequence="200"/>
<act_window id="lunch_voucher_attribution_action_create_po"
multi="True"
key2="client_action_multi"
name="Create Purchase Order"
res_model="lunch.voucher.purchase"
src_model="lunch.voucher.attribution"
view_mode="form"
target="new" />
</data>
</openerp>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="lunch_voucher_product" model="product.product">
<field name="name">Lunch Vouchers</field>
<field name="categ_id" ref="product.product_category_all"/>
<field name="sale_ok" eval="False"/>
<field name="purchase_ok" eval="True"/>
<field name="list_price">0</field>
<field name="standard_price">8</field>
<field name="type">service</field> <!-- For those who want to manage stock of lunch vouchers, they can switch type to product manually -->
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="supplier_taxes_id" eval="False"/>
<field name="taxes_id" eval="False"/>
</record>
<record id="base.main_company" model="res.company">
<field name="lunch_voucher_product_id" ref="lunch_voucher_product"/>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_lunch_voucher_attribution_full,Full access on lunch_voucher_attribution,model_lunch_voucher_attribution,base.group_hr_manager,1,1,1,1
access_lunch_voucher_attribution_read,Read access on lunch_voucher_attribution,model_lunch_voucher_attribution,base.group_user,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_lunch_voucher_attribution_full Full access on lunch_voucher_attribution model_lunch_voucher_attribution base.group_hr_manager 1 1 1 1
3 access_lunch_voucher_attribution_read Read access on lunch_voucher_attribution model_lunch_voucher_attribution base.group_user 1 0 0 0

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="lunch_voucher_attribution_employee" model="ir.rule">
<field name="name">Personal Lunch Voucher Attributions</field>
<field name="model_id" ref="hr_holidays_lunch_voucher.model_lunch_voucher_attribution"/>
<field name="domain_force">[('employee_id.user_id', '=', user.id)]</field>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
</record>
<record id="lunch_voucher_attribution_officer" model="ir.rule">
<field name="name">HR Officer sees all Lunch Voucher Attributions</field>
<field name="model_id" ref="hr_holidays_lunch_voucher.model_lunch_voucher_attribution"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('base.group_hr_manager'))]"/>
</record>
<record id="lunch_voucher_attribution_multicompany_rule" model="ir.rule">
<field name="name">Lunch Voucher Attribution multi-company</field>
<field name="model_id" ref="hr_holidays_lunch_voucher.model_lunch_voucher_attribution"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,4 @@
# -*- encoding: utf-8 -*-
from . import hr_holidays_post
from . import lunch_voucher_purchase

View File

@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api
from dateutil.relativedelta import relativedelta
import logging
logger = logging.getLogger(__name__)
class HrHolidaysPost(models.TransientModel):
_inherit = 'hr.holidays.post'
lunch_voucher_po = fields.Boolean(
string='Generate Lunch Voucher Purchase Order')
work_days = fields.Integer(string='Work Days')
@api.model
def default_get(self, fields_list):
res = super(HrHolidaysPost, self).default_get(fields_list)
hhpo = self.env['hr.holidays.public']
company = self.env.user.company_id
if company.lunch_voucher_product_id:
res['lunch_voucher_po'] = True
today = fields.Date.context_today(self)
today_dt = fields.Date.from_string(today)
cur_month = today_dt.month
# last day of month
date_dt = today_dt + relativedelta(day=31)
work_days = date_dt.day
logger.info('Number of days in the month: %d', work_days)
# from last day of month to the first
while date_dt.month == cur_month:
if hhpo.is_public_holiday(date_dt):
work_days -= 1
logger.info(
"%s is a bank holiday, don't count", date_dt)
# if it's a saturday/sunday
elif date_dt.weekday() in (5, 6):
work_days -= 1
logger.info(
"%s is a saturday/sunday, don't count", date_dt)
date_dt += relativedelta(days=-1)
logger.info('Number of work days in the month: %d', work_days)
res['work_days'] = work_days
return res
@api.multi
def run(self):
self.ensure_one()
lvao = self.env['lunch.voucher.attribution']
today = fields.Date.context_today(self)
employees = self.env['hr.employee'].search([
('lunch_voucher', '=', True),
('company_id', '=', self.env.user.company_id.id),
])
lv_dict = {}
for employee in employees:
lv_dict[employee.id] = []
for hol in self.holidays_to_post_ids:
if not hol.lunch_voucher_id and hol.employee_id.id in lv_dict:
lv_dict[hol.employee_id.id].append(hol.id)
for employee_id, hol_ids in lv_dict.iteritems():
vals = {
'employee_id': employee_id,
'date': today,
'month_work_days': self.work_days,
}
if hol_ids:
vals['holiday_ids'] = [(6, 0, hol_ids)]
lvao.create(vals)
return super(HrHolidaysPost, self).run()

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="hr_holidays_post_form" model="ir.ui.view">
<field name="name">hr_holidays_post_form</field>
<field name="model">hr.holidays.post</field>
<field name="inherit_id" ref="hr_holidays_usability.hr_holidays_post_form"/>
<field name="arch" type="xml">
<field name="holidays_to_post_ids" position="before">
<field name="lunch_voucher_po" states="done"/>
<field name="work_days"
attrs="{'invisible': ['|', ('state', '!=', 'done'), ('lunch_voucher_po', '=', False)]}"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, api, _
from openerp.exceptions import Warning as UserError
class LunchVoucherPurchase(models.TransientModel):
_name = 'lunch.voucher.purchase'
_description = 'Purchase Lunch Vouchers Wizard'
@api.multi
def run(self):
self.ensure_one()
company = self.env.user.company_id
if not company.lunch_voucher_product_id:
raise UserError(_(
"Lunch Voucher Product not configured on company %s")
% company.name)
if not company.lunch_voucher_product_id.seller_id:
raise UserError(_(
"Missing supplier on Product '%s'.")
% company.lunch_voucher_product_id.name)
poo = self.env['purchase.order']
polo = self.env['purchase.order.line']
lvao = self.env['lunch.voucher.attribution']
assert self._context.get('active_model') ==\
'lunch.voucher.attribution', 'wrong source model'
assert self._context.get('active_ids'), 'missing active_ids in ctx'
lvouchers = lvao.browse(self._context['active_ids'])
total_qty = 0
for lvoucher in lvouchers:
if lvoucher.purchase_id:
raise UserError(_(
"One of the Lunch Voucher Attributions you selected "
"related to employee '%s' is already linked to a "
"purchase order.") % lvoucher.employee_id.name)
if lvoucher.qty < 0:
raise UserError(_(
"One of the Lunch Voucher Attributions you selected "
"related to employee '%s' has a negative quantity.")
% lvoucher.employee_id.name)
total_qty += lvoucher.qty
supplier = company.lunch_voucher_product_id.seller_id
pick_type_id = poo.default_get(['picking_type_id'])['picking_type_id']
onchange_ptype_vals = poo.browse(False).onchange_picking_type_id(
pick_type_id)
vals = onchange_ptype_vals['value']
onchange_vals = poo.browse(False).onchange_partner_id(supplier.id)
vals.update(onchange_vals['value'])
vals['partner_id'] = supplier.id
product = company.lunch_voucher_product_id
onchange_product_vals = polo.browse(False).onchange_product_id(
vals.get('pricelist_id'), product.id, total_qty, False,
supplier.id, fiscal_position_id=vals.get('fiscal_position_id'))
lvals = onchange_product_vals['value']
lvals['product_id'] = product.id
lvals['product_qty'] = total_qty
if lvals['taxes_id']:
lvals['taxes_id'] = [(6, 0, lvals['taxes_id'])]
vals['order_line'] = [(0, 0, lvals)]
po = poo.create(vals)
lvouchers.write({'purchase_id': po.id})
action = self.env['ir.actions.act_window'].for_xml_id(
'purchase', 'purchase_rfq')
action.update({
'res_id': po.id,
'view_mode': 'form,tree',
'views': False,
})
return action

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion (http://www.akretion.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="lunch_voucher_purchase_form" model="ir.ui.view">
<field name="name">lunch_voucher_purchase_form</field>
<field name="model">lunch.voucher.purchase</field>
<field name="arch" type="xml">
<form string="Create Purchase Order of Lunch Vouchers">
<group name="main">
<label string="Click on the button below to create the purchase order for the selected lunch vouchers attributions." colspan="2"/>
</group>
<footer>
<button name="run" type="object" string="Create"
class="oe_highlight"/>
<button special="cancel" string="Cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
<record id="lunch_voucher_purchase_action" model="ir.actions.act_window">
<field name="name">Create PO for Lunch Vouchers</field>
<field name="res_model">lunch.voucher.purchase</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import company
from . import wizard

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'HR Holidays Lunch Voucher Natixis',
'version': '10.0.1.0.0',
'category': 'Human Resources',
'license': 'AGPL-3',
'summary': 'Generate order file for Natixis lunch vouchers',
'description': '',
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['hr_holidays_lunch_voucher'],
'data': [
'company_view.xml',
],
'installable': False,
}

View File

@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields
class ResCompany(models.Model):
_inherit = 'res.company'
lunch_voucher_natixis_customer_code = fields.Char(
string='Natixis Customer Ref', size=7)
lunch_voucher_natixis_delivery_code = fields.Char(
string='Natixis Delivery Code', size=7)

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion France (www.akretion.com)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<record id="view_company_form" model="ir.ui.view">
<field name="name">natixis.lunch_voucher.company.form</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="hr_holidays_lunch_voucher.view_company_form"/>
<field name="arch" type="xml">
<group name="lunch_voucher" position="inside">
<field name="lunch_voucher_natixis_customer_code"/>
<field name="lunch_voucher_natixis_delivery_code"/>
</group>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,3 @@
# -*- encoding: utf-8 -*-
from . import lunch_voucher_purchase

View File

@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp.exceptions import Warning as UserError
class LunchVoucherPurchase(models.TransientModel):
_inherit = 'lunch.voucher.purchase'
@api.multi
def run(self):
self.ensure_one()
action = super(LunchVoucherPurchase, self).run()
company = self.env.user.company_id
lvao = self.env['lunch.voucher.attribution']
assert self._context.get('active_model')\
== 'lunch.voucher.attribution', 'wrong source model'
assert self._context.get('active_ids'), 'missing active_ids in ctx'
if not company.lunch_voucher_natixis_customer_code:
raise UserError(_(
"Missing Natixis Customer Ref on company '%s'.")
% company.name)
if not company.lunch_voucher_natixis_delivery_code:
raise UserError(_(
"Missing Natixis Delivery Code on company '%s'.")
% company.name)
if len(company.lunch_voucher_natixis_customer_code) != 7:
raise UserError(_(
"Natixis Customer Ref '%s' on company '%s' should "
"have 7 characters/digits.")
% (company.lunch_voucher_natixis_customer_code, company.name))
if len(company.lunch_voucher_natixis_delivery_code) != 7:
raise UserError(_(
"Natixis Delivery Code on company '%s' should "
"have 7 characters/digits.")
% (company.lunch_voucher_natixis_delivery_code, company.name))
if not company.lunch_voucher_employer_price:
raise UserError(_(
"Lunch Voucher Employer Price not set on company '%s'.")
% company.name)
lvouchers = lvao.browse(self._context['active_ids'])
of = u''
tmp = {}
for lvoucher in lvouchers:
if lvoucher.qty > 0:
if lvoucher.qty not in tmp:
tmp[lvoucher.qty] = 1
else:
tmp[lvoucher.qty] += 1
for vouchers_per_pack, pack_qty in tmp.iteritems():
if vouchers_per_pack > 99:
raise UserError(_(
"Cannot order more than 99 vouchers per pack"))
line = u'%s%s%s%s%s%s%s%s\n' % (
company.lunch_voucher_natixis_delivery_code,
company.lunch_voucher_natixis_customer_code,
unicode(pack_qty).zfill(3),
unicode(vouchers_per_pack).zfill(2),
unicode(pack_qty * vouchers_per_pack).zfill(5),
'{:05.2f}'.format(
company.lunch_voucher_product_id.standard_price),
'{:05.2f}'.format(company.lunch_voucher_employer_price),
' ' * 64)
of += line
today_dt = fields.Date.from_string(
fields.Date.context_today(self))
filename = 'E%s_%s.txt' % (
company.lunch_voucher_natixis_customer_code,
today_dt.strftime('%d%m%Y'))
self.env['ir.attachment'].create({
'name': filename,
'res_id': action['res_id'],
'res_model': 'purchase.order',
'datas': of.encode('base64'),
'datas_fname': filename,
'type': 'binary',
})
return action

View File

@@ -42,5 +42,5 @@
'security/holiday_security.xml', 'security/holiday_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
], ],
'installable': True, 'installable': False,
} }

View File

@@ -241,6 +241,10 @@ class HrHolidays(models.Model):
string='Public Title', string='Public Title',
help="Warning: this title is shown publicly in the " help="Warning: this title is shown publicly in the "
"calendar. Don't write private/personnal information in this field.") "calendar. Don't write private/personnal information in this field.")
# by default, there is no company_id field on hr.holidays !
company_id = fields.Many2one(
related='employee_id.resource_id.company_id', store=True,
readonly=True)
@api.one @api.one
@api.constrains( @api.constrains(

View File

@@ -61,6 +61,7 @@ hr_holidays.edit_holiday_new is used for both leaves and allocation -->
</group> </group>
</field> </field>
<field name="department_id" position="after"> <field name="department_id" position="after">
<field name="company_id" groups="base.group_multi_company"/>
<field name="posted_date" groups="base.group_hr_manager"/> <field name="posted_date" groups="base.group_hr_manager"/>
</field> </field>
</field> </field>
@@ -90,6 +91,7 @@ hr_holidays.edit_holiday_new is used for both leaves and allocation -->
</field> </field>
<field name="holiday_status_id" position="after"> <field name="holiday_status_id" position="after">
<field name="posted_date" groups="base.group_hr_manager"/> <field name="posted_date" groups="base.group_hr_manager"/>
<field name="company_id" groups="base.group_multi_company"/>
</field> </field>
</field> </field>
</record> </record>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data noupdate="0"> <data noupdate="1">
<!-- <!--
Employee : only see his holidays Employee : only see his holidays
@@ -41,5 +41,12 @@ Manager = person that administrates the holidays process : can see everything, d
<field name="groups" eval="[(4, ref('base.group_hr_manager'))]"/> <field name="groups" eval="[(4, ref('base.group_hr_manager'))]"/>
</record> </record>
<record id="hr_holidays_multicompany_rule" model="ir.rule">
<field name="name">Holidays multi-company</field>
<field name="model_id" ref="hr_holidays.model_hr_holidays"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@@ -31,7 +31,9 @@ class HrHolidaysMassAllocation(models.TransientModel):
@api.model @api.model
def _default_employees(self): def _default_employees(self):
return self.env['hr.employee'].search([ return self.env['hr.employee'].search([
('holiday_exclude_mass_allocation', '=', False)]) ('holiday_exclude_mass_allocation', '=', False),
('company_id', '=', self.env.user.company_id.id),
])
@api.model @api.model
def _get_default_holiday_status(self): def _get_default_holiday_status(self):

View File

@@ -56,6 +56,7 @@ class HrHolidaysPost(models.TransientModel):
('state', '=', 'validate'), ('state', '=', 'validate'),
('posted_date', '=', False), ('posted_date', '=', False),
('vacation_date_to', '<=', self.before_date), ('vacation_date_to', '<=', self.before_date),
('company_id', '=', self.env.user.company_id.id),
]) ])
self.write({ self.write({
'state': 'done', 'state': 'done',

View File

@@ -12,13 +12,13 @@
<field name="name">hr_holidays_post_form</field> <field name="name">hr_holidays_post_form</field>
<field name="model">hr.holidays.post</field> <field name="model">hr.holidays.post</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Post Leaves" version="7.0"> <form string="Post Leaves">
<group name="main" string="Leave Requests to Post"> <group name="main" string="Leave Requests to Post">
<field name="state" invisible="1"/> <field name="state" invisible="1"/>
<field name="before_date" states="draft"/> <field name="before_date" states="draft"/>
<field name="holidays_to_post_ids" nolabel="1" <field name="holidays_to_post_ids" nolabel="1"
context="{'tree_view_ref': 'hr_holidays.view_holiday'}" context="{'tree_view_ref': 'hr_holidays.view_holiday'}"
states="done"/> states="done" colspan="2"/>
</group> </group>
<footer> <footer>
<button name="select_date" type="object" string="Get Holiday Requests" <button name="select_date" type="object" string="Get Holiday Requests"

View File

@@ -41,5 +41,5 @@ This module has been developped by Alexis de Lattre <alexis.delattre@akretion.co
'data': [ 'data': [
'hr_view.xml', 'hr_view.xml',
], ],
'installable': True, 'installable': False,
} }

View File

@@ -42,5 +42,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'depends': ['intrastat_product', 'l10n_fr_intrastat_service'], 'depends': ['intrastat_product', 'l10n_fr_intrastat_service'],
'data': ['product_view.xml'], 'data': ['product_view.xml'],
'post_init_hook': 'set_intrastat_type_on_products', 'post_init_hook': 'set_intrastat_type_on_products',
'installable': True, 'installable': False,
} }

View File

@@ -46,5 +46,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'author': "Akretion", 'author': "Akretion",
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['base'], 'depends': ['base'],
'installable': True, 'installable': False,
} }

View File

@@ -39,5 +39,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['l10n_fr_intrastat_product', 'report_aeroo'], 'depends': ['l10n_fr_intrastat_product', 'report_aeroo'],
'data': ['report.xml'], 'data': ['report.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -40,5 +40,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['l10n_fr'], 'depends': ['l10n_fr'],
'data': [], 'data': [],
'installable': True, 'installable': False,
} }

View File

@@ -23,7 +23,7 @@
{ {
'name': 'Mail Usability', 'name': 'Mail Usability',
'version': '0.1', 'version': '8.0.1.0.0',
'category': 'Base', 'category': 'Base',
'license': 'AGPL-3', 'license': 'AGPL-3',
'summary': 'Usability improvements on mails', 'summary': 'Usability improvements on mails',
@@ -37,10 +37,11 @@ Small usability improvements on mails:
* remove 'sent by' in notification footer * remove 'sent by' in notification footer
* add a new entry *All Messages Except Notifications* to the field *Receive Inbox Notifications by Email* of partners (becomes the default value)
""", """,
'author': 'Akretion', 'author': 'Akretion',
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['mail'], 'depends': ['mail'],
'data': [], 'data': [],
'installable': True, 'installable': False,
} }

View File

@@ -20,7 +20,16 @@
# #
############################################################################## ##############################################################################
from openerp import models, api from openerp import models, fields, api
class ResPartner(models.Model):
_inherit = 'res.partner'
notify_email = fields.Selection(
selection_add=[
('all_except_notification', 'All Messages Except Notifications')],
default='all_except_notification')
class MailMail(models.Model): class MailMail(models.Model):
@@ -47,6 +56,19 @@ class MailNotification(models.Model):
footer = super(MailNotification, self).get_signature_footer( footer = super(MailNotification, self).get_signature_footer(
cr, uid, user_id, res_model=res_model, res_id=res_id, cr, uid, user_id, res_model=res_model, res_id=res_id,
context=context, user_signature=user_signature) context=context, user_signature=user_signature)
footer = footer[:footer.find('\n\n<br /><small>Sent by ')] footer = footer[:footer.find('\n<br /><small>Sent by ')]
footer = footer[:footer.find(u'\n\n<br /><small>Envoyé par ')] footer = footer[:footer.find(u'\n<br /><small>Envoyé par ')]
return footer return footer
@api.multi
def get_partners_to_email(self, message):
notify_pids = super(MailNotification, self).get_partners_to_email(
message)
for notif in self:
if (
notif.partner_id.id in notify_pids and
message.type == 'notification' and
notif.partner_id.notify_email ==
'all_except_notification'):
notify_pids.remove(notif.partner_id.id)
return notify_pids

View File

@@ -25,5 +25,5 @@ Contributors: David BEAL
'data': [ 'data': [
'view.xml', 'view.xml',
], ],
'installable': True, 'installable': False,
} }

View File

@@ -47,6 +47,6 @@ with https://github.com/akretion/csv2xml4odoo
'misc_data.xml', 'misc_data.xml',
'ir_exports_line_data.xml', 'ir_exports_line_data.xml',
], ],
'installable': True, 'installable': False,
'license': 'AGPL-3', 'license': 'AGPL-3',
} }

View File

@@ -43,5 +43,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['mrp'], 'depends': ['mrp'],
'data': ['mrp_view.xml'], 'data': ['mrp_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -41,4 +41,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['account_financial_report_webkit'], 'depends': ['account_financial_report_webkit'],
'data': ['partner_view.xml'], 'data': ['partner_view.xml'],
'installable': False,
} }

View File

@@ -43,5 +43,5 @@ This module has been written by Alexis de Lattre from Akretion
'depends': ['product'], 'depends': ['product'],
'conflicts': ['partner_products_shortcut'], 'conflicts': ['partner_products_shortcut'],
'data': ['partner_view.xml'], 'data': ['partner_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -43,5 +43,5 @@ This module has been written by Alexis de Lattre from Akretion
'depends': ['product'], 'depends': ['product'],
'conflicts': ['partner_product_variants_shortcut'], 'conflicts': ['partner_product_variants_shortcut'],
'data': ['partner_view.xml'], 'data': ['partner_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -18,5 +18,5 @@ Search view improved: filter on postal code, city, mail, phone, etc...
'data': [ 'data': [
'partner_view.xml', 'partner_view.xml',
], ],
'installable': True, 'installable': False,
} }

View File

@@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Akretion (http://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Partner Menu Split",
"summary": "Split the customer menu in two",
"version": "8.0.0.0",
"category": "Uncategorized",
"website": "www.akretion.com",
"author": " Akretion",
"license": "AGPL-3",
"application": False,
"installable": False,
"external_dependencies": {
"python": [],
"bin": [],
},
"depends": [
"base",
"purchase",
],
"data": [
"views/res_partner_view.xml",
],
"demo": [
],
"qweb": [
]
}

View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="base.action_partner_customer_form" model="ir.actions.act_window">
<field name="domain">[('parent_id', '=', False)]</field>
<field name="view_mode">tree,form,kanban</field>
</record>
<record id="base.action_partner_form" model="ir.actions.act_window">
<field name="domain">[('parent_id', '=', False)]</field>
<field name="view_mode">tree,form,kanban</field>
</record>
<record id="base.action_partner_form_view1" model="ir.actions.act_window.view">
<field eval="3" name="sequence"/>
</record>
<record id="action_partner_customer_contact_form" model="ir.actions.act_window">
<field name="name">Contact</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,kanban</field>
<field name="domain">[('parent_id', '!=', False)]</field>
<field name="context">{'default_customer':1, 'search_default_customer':1}</field>
<field name="filter" eval="True"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a contact in your address book.
</p><p>
Odoo helps you easily track all activities related to
a customer: discussions, history of business opportunities,
documents, etc.
</p>
</field>
</record>
<menuitem
id="menu_partner_form"
parent="base.menu_sales"
action="action_partner_customer_contact_form"
sequence="2"/>
<record id="base.action_partner_supplier_form" model="ir.actions.act_window">
<field name="domain">[('parent_id', '=', False)]</field>
<field name="view_mode">tree,form,kanban</field>
</record>
<record id="action_partner_supplier_contact_form" model="ir.actions.act_window">
<field name="name">Contact</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,kanban</field>
<field name="domain">[('parent_id', '!=', False)]</field>
<field name="context">{'default_supplier':1, 'search_default_supplier':1}</field>
<field name="filter" eval="True"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a contact in your address book.
</p><p>
Odoo helps you easily track all activities related to
a supplier: discussions, history of business opportunities,
documents, etc.
</p>
</field>
</record>
<menuitem
id="menu_partner_supplier_form"
parent="purchase.menu_procurement_management"
action="action_partner_supplier_contact_form"
sequence="20"/>
</data>
</openerp>

View File

@@ -37,5 +37,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['asterisk_click2dial', 'report_aeroo'], 'depends': ['asterisk_click2dial', 'report_aeroo'],
'data': ['report.xml'], 'data': ['report.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -42,5 +42,5 @@ This module has been written by Alexis de Lattre
'website': 'http://www.akretion.com', 'website': 'http://www.akretion.com',
'depends': ['point_of_sale'], 'depends': ['point_of_sale'],
'data': ['pos_journal_sequence_view.xml'], 'data': ['pos_journal_sequence_view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -40,5 +40,5 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'depends': ['point_of_sale', 'pos_usability'], 'depends': ['point_of_sale', 'pos_usability'],
# pos_usability is required to have the filter available_in_pos # pos_usability is required to have the filter available_in_pos
'data': ['view.xml'], 'data': ['view.xml'],
'installable': True, 'installable': False,
} }

View File

@@ -42,5 +42,5 @@ This module has been written by Alexis de Lattre
'product_view.xml', 'product_view.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
], ],
'installable': True, 'installable': False,
} }

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