Compare commits

..

79 Commits

Author SHA1 Message Date
Mourad Elhadj Mimoune
145ab11996 [FIX] regression on shortcut button on partner form view after PR #41 2017-10-10 17:35:32 +02:00
Alexis de Lattre
3888495071 Add field has_attachment on invoices 2017-09-29 14:36:57 +02:00
chafique delli
93acac8e19 Merge pull request #43 from akretion/8.0-mail-usability
add many2many_tags_email.js file for mail_usability that replaces addons-mail-fix.diff patch
2017-09-26 15:51:56 +02:00
Alexis de Lattre
44b32672e2 2 fixes in hr_holidays modules 2017-09-22 15:57:16 +02:00
Alexis de Lattre
1160cce1d8 Allow to duplicate an account move that belongs to a closed period => copy=False on period_id and date of account.move 2017-09-20 12:17:45 +02:00
chafique-delli
16664bcb7f add comment in many2many_tags_email.js file 2017-09-18 16:15:18 +02:00
chafique-delli
cfb92ec23a add many2many_tags_email.js file for mail_usability that replaces addons-mail-fix.diff patch 2017-09-18 15:44:58 +02:00
Sébastien BEAU
a3844004fb [FIX] fix showing all variant active or inactive 2017-09-16 12:28:22 +02:00
Alexis de Lattre
9319b120bf Add patch for odoo when using mail_usability 2017-09-14 17:46:05 +02:00
Alexis de Lattre
7fd5ab9cf1 Filter on period instead of dates for aged open invoices report 2017-09-12 10:35:39 +02:00
Alexis de Lattre
8f463db179 translation=False on 'name' of res.partner.category and crm.case.categ 2017-09-07 18:19:24 +02:00
Sébastien BEAU
f8720c7a36 [FIX] fix broken menu due to mistyping for context in reception menu 2017-08-17 10:27:30 +02:00
David Beal
e74e53c804 FIX make defaut module filter to installable 2017-08-16 12:43:41 +02:00
Sébastien BEAU
5388638941 [FIX] fix filtering partner on name and ref and not on email 2017-08-10 17:13:31 +02:00
mourad-ehm
d943ef262f Merge pull request #41 from akretion/fix_change_button_name_bug
[FIX] change button name bug
2017-08-04 14:49:13 +02:00
Sébastien BEAU
a787e092ed [IMP] add delivery usability 2017-08-03 20:30:44 +02:00
Sébastien BEAU
8e5f0b0afa [IMP] add type to be easier to customise button in custom module 2017-08-03 20:27:39 +02:00
Sébastien BEAU
cb21028a48 [IMP] add stock split menu 2017-08-03 14:32:53 +02:00
Sébastien BEAU
ffa6e74a19 [IMP] order invoice per date, solve issue with multi journal 2017-08-02 19:39:33 +02:00
Alexis de Lattre
1e062af883 Add wizard to mark all invoices as sent and add filter on invoices to send 2017-07-25 18:12:05 +02:00
Alexis de Lattre
31f191aecb Disable the constraint _check_account_type() on account.account, as agreed with Sebastien 2017-07-25 11:38:03 +02:00
Alexis de Lattre
51c982bf2f Fiscal value cols now have to right sign, to use with the updated version of l10n_fr_intrastat_product 2017-07-24 14:02:07 +02:00
Mourad Elhadj Mimoune
3d7241407e [FIX] Button name change bug 2017-07-11 15:32:07 +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
132 changed files with 3170 additions and 308 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': True,
}

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

@@ -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': True,
}

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

@@ -53,7 +53,10 @@ class AccountMoveLineFilterWizard(models.TransientModel):
self.ensure_one()
action = self.env['ir.actions.act_window'].for_xml_id(
'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:
action['context']['search_default_partner_id'] =\
[self.partner_id.id]

View File

@@ -21,9 +21,16 @@
##############################################################################
import xlwt
import logging
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):

View File

@@ -1,3 +1,4 @@
# -*- encoding: utf-8 -*-
from . import account
from . import wizard

View File

@@ -49,6 +49,9 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com',
'depends': ['account'],
'conflicts': ['account_invoice_overdue_filter'],
'data': ['account_view.xml'],
'data': [
'account_view.xml',
'wizard/account_invoice_mark_sent_view.xml',
],
'installable': True,
}

View File

@@ -23,10 +23,13 @@
from openerp import models, fields, api, _
from openerp.tools import float_compare
from openerp.exceptions import Warning as UserError
import logging
logger = logging.getLogger(__name__)
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
_order = "date_invoice desc, number desc, id desc"
origin = fields.Char(track_visibility='onchange')
supplier_invoice_number = fields.Char(track_visibility='onchange')
@@ -41,9 +44,41 @@ class AccountInvoice(models.Model):
journal_id = fields.Many2one(track_visibility='onchange')
partner_bank_id = fields.Many2one(track_visibility='onchange')
fiscal_position = fields.Many2one(track_visibility='onchange')
# has_attachment is useful for those who use attachment to archive
# supplier invoices. It allows them to find supplier invoices
# that don't have any attachment
has_attachment = fields.Boolean(
compute='_compute_has_attachment',
search='_search_has_attachment', readonly=True)
@api.multi
def onchange_payment_term_date_invoice(self, payment_term_id, date_invoice):
def _compute_has_attachment(self):
iao = self.env['ir.attachment']
for inv in self:
if iao.search([
('res_model', '=', 'account.invoice'),
('res_id', '=', inv.id),
('type', '=', 'binary'),
('company_id', '=', inv.company_id.id)], limit=1):
inv.has_attachment = True
else:
inv.has_attachment = False
def _search_has_attachment(self, operator, value):
att_inv_ids = {}
if operator == '=':
search_res = self.env['ir.attachment'].search_read([
('res_model', '=', 'account.invoice'),
('type', '=', 'binary'),
('res_id', '!=', False)], ['res_id'])
for att in search_res:
att_inv_ids[att['res_id']] = True
res = [('id', value and 'in' or 'not in', att_inv_ids.keys())]
return res
@api.multi
def onchange_payment_term_date_invoice(
self, payment_term_id, date_invoice):
res = super(AccountInvoice, self).onchange_payment_term_date_invoice(
payment_term_id, date_invoice)
if res and isinstance(res, dict) and 'value' in res:
@@ -54,8 +89,8 @@ class AccountInvoice(models.Model):
# 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
# write a rubbish '/' in it !
# 2) the 'name' field of the account.move.line is used in the overdue letter,
# and '/' is not meaningful for our customer !
# 2) the 'name' field of the account.move.line is used in the overdue
# letter and '/' is not meaningful for our customer !
@api.multi
def action_number(self):
res = super(AccountInvoice, self).action_number()
@@ -69,6 +104,28 @@ class AccountInvoice(models.Model):
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):
_inherit = 'account.fiscalyear'
@@ -105,10 +162,51 @@ class AccountAccount(models.Model):
else:
return super(AccountAccount, self).name_get()
def _check_account_type(self, cr, uid, ids, context=None):
'''Disable this native python constraint, because we want to be able
to configure payable/receivable accounts with an account type
with close_method == 'balance' in order to have opening entries with
fewer lines. It is not a problem because we always use
account_financial_report_webkit which doesn't take the detailed
opening entries into account.'''
return True
_constraints = [
# The method name must be exactly the same as the native
# method, in order to override it
(_check_account_type, 'No error message', ['user_type', 'type']),
]
@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):
_inherit = 'account.analytic.account'
invoice_line_ids = fields.One2many(
'account.invoice.line', 'account_analytic_id', 'Invoice Lines',
readonly=True)
@api.multi
def name_get(self):
if self._context.get('analytic_account_show_code_only'):
@@ -125,11 +223,55 @@ class AccountAnalyticAccount(models.Model):
class AccountMove(models.Model):
_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;
# Allow to duplicate an account.move that belongs to a closed period
period_id = fields.Many2one(copy=False)
date = fields.Date(copy=False)
@api.onchange('date')
def date_onchange(self):
if 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):
_inherit = 'account.move.line'
@@ -163,6 +305,28 @@ class AccountMoveLine(models.Model):
else:
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):
_inherit = 'account.bank.statement.line'
@@ -210,6 +374,7 @@ class AccountBankStatementLine(models.Model):
raise UserError(_(
'No journal entry linked to this bank statement line.'))
class ResPartner(models.Model):
_inherit = 'res.partner'

View File

@@ -38,6 +38,11 @@
<field name="period_id" position="attributes">
<attribute name="groups"></attribute>
</field>
<!-- move sent field and make it visible -->
<field name="sent" position="replace"/>
<field name="move_id" position="after">
<field name="sent"/>
</field>
</field>
</record>
@@ -61,6 +66,123 @@
<filter name="unpaid" position="after">
<filter name="overdue" string="Overdue"
domain="[('state', '=', 'open'), ('date_due', '&lt;', current_date)]"/>
<separator/>
<filter name="to_send" string="To Send" domain="[('sent', '=', False), ('state', 'in', ('open', 'paid'))]"/>
<filter name="sent" string="Sent" domain="[('sent', '=', True)]"/>
<separator/>
<filter name="no_attachment" string="Missing Attachment" domain="[('has_attachment', '=', False)]"/>
</filter>
</field>
</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>
@@ -68,10 +190,24 @@
<!-- model account.move.line / Journal Items -->
<record id="account.action_account_moves_all_a" model="ir.actions.act_window">
<field name="limit">200</field>
<!-- add graph -->
<field name="view_mode">tree_account_move_line_quickadd,form,graph</field>
<!-- Win space, because there are already many columns -->
<field name="context">{'journal_show_code_only': True}</field>
</record>
<record id="account_move_line_graph" model="ir.ui.view">
<field name="name">usability.account.move.line.graph</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.account_move_line_graph"/>
<field name="arch" type="xml">
<graph position="attributes">
<!-- pivot by default instead of bar -->
<attribute name="type">pivot</attribute>
</graph>
</field>
</record>
<!-- model account.move / Journal Entries -->
<record id="account.action_move_journal_line" model="ir.actions.act_window">
<field name="limit">200</field>
@@ -101,6 +237,7 @@
<field name="arch" type="xml">
<field name="partner_id" position="after">
<field name="reconcile_ref" />
<field name="debit" filter_domain="['|', ('debit', '=', self), ('credit', '=', self)]" string="Debit or Credit"/>
</field>
<filter name="unreconciled" position="before">
<filter name="reconciled" string="Fully Reconciled" domain="[('reconcile_id', '!=', False)]"/>
@@ -128,6 +265,7 @@
<field name="name">account_usability.account_move_line_tree</field>
<field name="model">account.move.line</field>
<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="analytic_account_id" position="attributes">
<attribute name="invisible"></attribute>
@@ -171,6 +309,12 @@
<field name="inherit_id" ref="account.partner_view_button_journal_item_count"/>
<field name="arch" type="xml">
<button name="%(account.action_account_moves_all_tree)d" position="after">
<button name="show_receivable_account" type="object"
attrs="{'invisible': [('customer', '=', False)]}"
icon="fa-list" class="oe_stat_button">
<field string="Journal Items" name="journal_item_count"
widget="statinfo"/>
</button>
<button name="show_payable_account" type="object"
attrs="{'invisible': [('supplier', '=', False)]}"
icon="fa-list" class="oe_stat_button">
@@ -179,9 +323,7 @@
</button>
</button>
<button name="%(account.action_account_moves_all_tree)d" position="attributes">
<attribute name="type">object</attribute>
<attribute name="name">show_receivable_account</attribute>
<attribute name="attrs">{'invisible': [('customer', '=', False)]}</attribute>
<attribute name="invisible">True</attribute>
</button>
<field name="journal_item_count" position="attributes">
<attribute name="string">Receivable Account</attribute>
@@ -189,6 +331,12 @@
</field>
</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">
<field name="name">usability.account.bank.statement.form</field>
<field name="model">account.bank.statement</field>
@@ -200,6 +348,65 @@
string="View Account Move" icon="gtk-redo"
attrs="{'invisible': [('journal_entry_id', '=', False)]}"/>
</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>
</record>

View File

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

View File

@@ -0,0 +1,23 @@
# -*- 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, api
import logging
logger = logging.getLogger(__name__)
class AccountInvoiceMarkSent(models.TransientModel):
_name = 'account.invoice.mark.sent'
_description = 'Mark invoices as sent'
@api.multi
def run(self):
assert self.env.context.get('active_model') == 'account.invoice',\
'Source model must be invoices'
assert self.env.context.get('active_ids'), 'No invoices selected'
invoices = self.env['account.invoice'].browse(
self.env.context.get('active_ids'))
invoices.write({'sent': True})
logger.info('Marking invoices with ID %s as sent', invoices.ids)
return

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
The licence is in the file __openerp__.py
-->
<openerp>
<data>
<record id="account_invoice_mark_sent_form" model="ir.ui.view">
<field name="name">account.invoice.mark.sent.form</field>
<field name="model">account.invoice.mark.sent</field>
<field name="arch" type="xml">
<form string="Mark invoices as sent">
<p>
This wizard will mark as sent all the selected invoices.
</p>
<footer>
<button type="object" name="run" string="Mark as Sent" class="oe_highlight"/>
<button special="cancel" string="Cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
<act_window id="account_invoice_mark_sent_action"
multi="True"
key2="client_action_multi"
name="Mark as Sent"
res_model="account.invoice.mark.sent"
src_model="account.invoice"
view_mode="form"
target="new" />
</data>
</openerp>

View File

@@ -12,6 +12,9 @@
<field name="model">ir.module.module</field>
<field name="inherit_id" ref="base.view_module_filter"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='extra']" position="after">
<filter name="installable" string="Installable" domain="[('state', '!=', 'uninstallable')]"/>
</xpath>
<xpath expr="//filter[@string='Category']" position="after">
<filter string="State" domain="[]" context="{'group_by':'state'}"/>
</xpath>
@@ -20,7 +23,7 @@
<record id="base.open_module_tree" model="ir.actions.act_window">
<field name="res_model">ir.module.module</field>
<field name="context">{}</field>
<field name="context">{'search_default_installable': 1}</field>
</record>
</data>

View File

@@ -60,3 +60,21 @@ class Partner(models.Model):
else:
name_title = ' '.join([title, name_title])
self.name_title = name_title
@api.model
def name_search(self, name, args=None, operator='ilike', limit=100):
if args is None:
args = []
if name:
# only filter on name and ref not in email
args += [
'|', ('display_name', 'ilike', name), ('ref', 'ilike', name)]
res = super(Partner, self).name_search(
name, args=args, operator=operator, limit=limit)
return [(pid, val.replace('\n', ' ')) for pid, val in res]
class ResPartnerCategory(models.Model):
_inherit = 'res.partner.category'
name = fields.Char(translate=False)

View File

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

View File

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

12
crm_usability/crm.py Normal file
View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (http://www.akretion.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
# @author Alexis de Lattre <alexis.delattre@akretion.com>
from openerp import models, fields
class CrmCaseCateg(models.Model):
_inherit = 'crm.case.categ'
name = fields.Char(translate=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

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

View File

@@ -0,0 +1,30 @@
# -*- 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": "Delivery usability",
"summary": "Delivery Usability",
"version": "8.0.1.0.0",
"category": "Warehouse",
"website": "www.akretion.com",
"author": " Akretion",
"license": "AGPL-3",
"application": False,
"installable": True,
"external_dependencies": {
"python": [],
"bin": [],
},
"depends": [
"delivery",
],
"data": [
"views/stock_picking_view.xml",
],
"demo": [
],
"qweb": [
]
}

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="view_picking_withcarrier_out_form" model="ir.ui.view">
<field name="model">stock.picking</field>
<field name="inherit_id" ref="delivery.view_picking_withcarrier_out_form"/>
<field name="priority" eval="100"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='carrier_id']/.." position="replace">
</xpath>
<field name="backorder_id" position="after">
<field name="carrier_id"/>
<field name="carrier_tracking_ref"/>
</field>
</field>
</record>
</data>
</openerp>

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': True,
}

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': True,
}

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,92 @@
# -*- 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
from openerp.tools import float_is_zero
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
# force_company to read standard_price properly
company = company.with_context(force_company=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 float_is_zero(
company.lunch_voucher_employer_price,
precision_digits=2):
raise UserError(_(
"Lunch Voucher Employer Price not set on company '%s'.")
% company.name)
if float_is_zero(
company.lunch_voucher_product_id.standard_price,
precision_digits=2):
raise UserError(_(
"Lunch Voucher Standard Price is not set on product '%s'.")
% company.lunch_voucher_product_id.display_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

@@ -241,6 +241,10 @@ class HrHolidays(models.Model):
string='Public Title',
help="Warning: this title is shown publicly in the "
"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.constrains(

View File

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

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<data noupdate="1">
<!--
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'))]"/>
</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>
</openerp>

View File

@@ -31,7 +31,9 @@ class HrHolidaysMassAllocation(models.TransientModel):
@api.model
def _default_employees(self):
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
def _get_default_holiday_status(self):

View File

@@ -56,6 +56,7 @@ class HrHolidaysPost(models.TransientModel):
('state', '=', 'validate'),
('posted_date', '=', False),
('vacation_date_to', '<=', self.before_date),
('company_id', '=', self.env.user.company_id.id),
])
self.write({
'state': 'done',
@@ -73,9 +74,11 @@ class HrHolidaysPost(models.TransientModel):
# because, after the write, it doesn't have a value any more !!!
holidays_to_post = self.holidays_to_post_ids
today = fields.Date.context_today(self)
if not self.holidays_to_post_ids:
raise Warning(
_('No leave request to post.'))
# Disable the raise below to make the module "hr_holidays_lunch_voucher"
# work even when nobody took holidays on the current month
# if not self.holidays_to_post_ids:
# raise Warning(
# _('No leave request to post.'))
self.holidays_to_post_ids.write({'posted_date': today})
view_id = self.env.ref('hr_holidays_usability.hr_holiday_graph').id
action = {

View File

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

View File

@@ -23,7 +23,7 @@
{
'name': 'Mail Usability',
'version': '0.1',
'version': '8.0.1.0.0',
'category': 'Base',
'license': 'AGPL-3',
'summary': 'Usability improvements on mails',
@@ -37,10 +37,11 @@ Small usability improvements on mails:
* 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',
'website': 'http://www.akretion.com',
'depends': ['mail'],
'data': [],
'data': ['views/mail.xml'],
'installable': True,
}

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):
@@ -47,6 +56,19 @@ class MailNotification(models.Model):
footer = super(MailNotification, self).get_signature_footer(
cr, uid, user_id, res_model=res_model, res_id=res_id,
context=context, user_signature=user_signature)
footer = footer[:footer.find('\n\n<br /><small>Sent by ')]
footer = footer[:footer.find(u'\n\n<br /><small>Envoyé par ')]
footer = footer[:footer.find('\n<br /><small>Sent by ')]
footer = footer[:footer.find(u'\n<br /><small>Envoyé par ')]
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

@@ -0,0 +1,92 @@
openerp_FieldMany2ManyTagsEmail = function(instance) {
var _t = instance.web._t;
/**
* Extend of FieldMany2ManyTags widget method.
* When the user add a partner and the partner don't have an email, open a popup to purpose to add an email.
* The user can choose to add an email or cancel and close the popup.
*/
instance.web.form.FieldMany2ManyTagsEmail = instance.web.form.FieldMany2ManyTags.extend({
start: function() {
this.mutex = new openerp.Mutex();
// This widget will indirectly trigger a change:value to it's parent widget
// when setting the value of valid partners. For this reason we have to keep an
// internal state of the last value in order to compute the effective value changes.
this.last_processed_value = [];
this.on("change:value", this, this.on_change_value_check);
// Restore pop-up when trying to send to a partner without email
this.on_change_value_check();
this._super.apply(this, arguments);
},
on_change_value_check : function () {
var self = this;
var values = this.get('value').slice(0); // Clone the array
// We only validate partners emails in case the value is not empty
// and is different from the last processed value
var effective_change = _.difference(values, self.last_processed_value).length;
if (values.length && effective_change) {
this.mutex.exec(function() {
return self._check_email_popup(values);
});
}
},
_check_email_popup: function (ids) {
var self = this;
var valid_partners;
new instance.web.Model('res.partner').call("search", [[
["id", "in", ids],
["email", "=", false],
["notify_email", "in", ['always', 'all_except_notification']]]],
{context: this.build_context()})
.then(function (record_ids) {
var popups_deferreds = [];
self.valid_partners = _.difference(ids, record_ids);
// Propose the user to correct invalid partners
_.each(record_ids, function (id) {
var popup_def = $.Deferred();
popups_deferreds.push(popup_def);
var pop = new instance.web.form.FormOpenPopup(self);
pop.show_element(
'res.partner',
id,
self.build_context(),
{
title: _t("Please complete partner's informations and Email"),
}
);
pop.on('write_completed', self, function () {
self.valid_partners.push(id);
});
pop.on('closed', self, function () {
popup_def.resolve();
});
});
return $.when.apply($, popups_deferreds).then(function() {
// All popups have been processed for the given ids
// It is now time to set the final value with valid partners ids.
var filtered_value = _.uniq(self.valid_partners);
self.last_processed_value = filtered_value;
self.set({'value': filtered_value});
});
});
},
});
/**
* Registry of form fields
*/
instance.web.form.widgets = instance.web.form.widgets.extend({
'many2many_tags_email' : 'instance.web.form.FieldMany2ManyTagsEmail',
});
};

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="assets_backend" name="mail usability assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/mail_usability/static/src/js/many2many_tags_email.js"></script>
</xpath>
</template>
</data>
</openerp>

View File

@@ -40,31 +40,27 @@ class ResPartner(models.Model):
def open_aged_open_invoices_report(self):
aoiwo = self.env['aged.open.invoices.webkit']
afo = self.env['account.fiscalyear']
# Force 'date_from' to the first day of the company's life
# in order to get the full picture of the partner's account
# (we could also do that via a filter by period, but, in this case,
# account_financial_report_webkit doesn't accept "until_date = today" ;
# until_date has to be the end date of the last period
# Filter by period (and not by date) to get
# the report à nouveau
fy_years = afo.search([], order='date_start')
date_from = fy_years[0].date_start
fy_id = aoiwo._get_fiscalyear()
filter_change = aoiwo.onchange_filter(
filter='filter_date', fiscalyear_id=fy_id)
filter='filter_period', fiscalyear_id=fy_id)
vals = {
'fiscalyear_id': fy_id,
'filter': 'filter_date',
'filter': 'filter_period',
'partner_ids': [(6, 0, [self.commercial_partner_id.id])],
'target_move': 'all',
}
vals.update(filter_change['value'])
vals['date_from'] = date_from
wizard = aoiwo.create(vals)
data = {'form': {
'chart_account_id': wizard.chart_account_id.id,
'filter': vals['filter'],
'date_from': vals['date_from'],
'date_to': vals['date_to'],
'period_to': False,
'period_from': vals['period_from'],
'period_to': vals['period_to'],
'date_to': False,
'fiscalyear_id': vals['fiscalyear_id'],
'partner_ids': vals['partner_ids'][0][2],
'target_move': vals['target_move'],

View File

@@ -14,10 +14,20 @@
<field name="phone" string="Phones"
filter_domain="['|', ('phone', 'like', self), ('mobile', 'like', self)]"/>
</field>
<!-- Display the real field names of the search -->
<!-- We split the search of name, ref / email in two
as searching in email can return a lot of unwanted result
for exemple when you sell on marketplace and search for a customer
amazon you will have all customer that have bought throught the marketplace -->
<field name="name" position="attributes">
<attribute name="string">Name, Ref, Email</attribute>
<attribute name="string">Name, Ref</attribute>
<attribute name="filter_domain">['|', ('display_name','ilike',self), ('ref','=',self)]</attribute>
</field>
<field name="name" position="after">
<field name="email"/>
</field>
</field>
</record>

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": True,
"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

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

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': 'Product Expiry Simple',
'version': '8.0.1.0.0',
'category': 'Product',
'license': 'AGPL-3',
'summary': 'Simpler and better alternative to the official product_expiry module',
'description': """
Product Expiry Simple
=====================
This module is similar to the official *product_expiry* modules, but much simpler and much better:
* Only one expiry date field instead of 4 !
* date field instead of datetime
* No automatic computing of expiry date based on a delay configured on product (not needed in most companies)
* colored production lot and stock quant tree views depending on expiry dates
* ability to show stats about expiry dates on quants pivot table (thanks to related stored field on stock.quant)
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['stock'],
'conflicts': ['product_expiry'],
'data': [
'stock_view.xml',
'product_removal_data.xml',
],
'installable': True,
}

View File

@@ -0,0 +1,53 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * product_expiry_simple
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-02-14 13:19+0000\n"
"PO-Revision-Date: 2017-02-14 13:19+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: product_expiry_simple
#: view:stock.production.lot:product_expiry_simple.search_product_lot_filter
#: view:stock.quant:product_expiry_simple.quant_search_view
msgid "Expired"
msgstr "Périmé"
#. module: product_expiry_simple
#: view:stock.production.lot:product_expiry_simple.search_product_lot_filter
#: field:stock.production.lot,expiry_date:0
#: view:stock.quant:product_expiry_simple.quant_search_view
#: field:stock.quant,expiry_date:0
msgid "Expiry Date"
msgstr "Date de péremption"
#. module: product_expiry_simple
#: model:ir.model,name:product_expiry_simple.model_stock_production_lot
msgid "Lot/Serial"
msgstr "Lot/N° série"
#. module: product_expiry_simple
#: view:stock.production.lot:product_expiry_simple.search_product_lot_filter
#: view:stock.quant:product_expiry_simple.quant_search_view
msgid "Not Expired"
msgstr "Non périmé"
#. module: product_expiry_simple
#: model:ir.model,name:product_expiry_simple.model_stock_quant
msgid "Quants"
msgstr "Quants"
#. module: product_expiry_simple
#: view:stock.production.lot:product_expiry_simple.view_production_lot_tree
#: view:stock.quant:product_expiry_simple.view_stock_quant_tree
msgid "red:expiry_date and expiry_date < current_date;green:expiry_date >= current_date"
msgstr "red:expiry_date and expiry_date < current_date;green:expiry_date >= current_date"

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" ?>
<openerp>
<data>
<record id="removal_fefo" model="product.removal">
<field name="name">First Expiry First Out (FEFO)</field>
<field name="method">fefo</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,43 @@
# -*- 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
class StockProductionLot(models.Model):
_inherit = 'stock.production.lot'
_rec_name = 'display_name'
expiry_date = fields.Date(string='Expiry Date')
display_name = fields.Char(
compute='compute_display_name_field',
string='Lot/Serial Number Display', store=True, readonly=True)
@api.multi
@api.depends('name', 'expiry_date')
def compute_display_name_field(self):
for lot in self:
dname = lot.name
if lot.expiry_date:
dname = '[%s] %s' % (lot.expiry_date, dname)
lot.display_name = dname
class StockQuant(models.Model):
_inherit = 'stock.quant'
expiry_date = fields.Date(
related='lot_id.expiry_date', store=True, readonly=True)
# method copy/pasted from the official product_expiry module
# © Odoo SA
@api.model
def apply_removal_strategy(
self, location, product, qty, domain, removal_strategy):
if removal_strategy == 'fefo':
order = 'expiry_date, location_id, package_id, lot_id, in_date, id'
return self._quants_get_order(
location, product, qty, domain, order)
return super(StockQuant, self).apply_removal_strategy(
location, product, qty, domain, removal_strategy)

View File

@@ -0,0 +1,94 @@
<?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>
<!-- LOTS -->
<record id="view_production_lot_form" model="ir.ui.view">
<field name="name">product_expiry_simple.stock.production.lot.form</field>
<field name="model">stock.production.lot</field>
<field name="inherit_id" ref="stock.view_production_lot_form"/>
<field name="arch" type="xml">
<field name="ref" position="after">
<field name="expiry_date"/>
</field>
</field>
</record>
<record id="view_production_lot_tree" model="ir.ui.view">
<field name="name">product_expiry_simple.stock.production.lot.tree</field>
<field name="model">stock.production.lot</field>
<field name="inherit_id" ref="stock.view_production_lot_tree"/>
<field name="arch" type="xml">
<field name="product_id" position="after">
<field name="expiry_date"/>
</field>
<xpath expr="/tree" position="attributes">
<attribute name="colors">red:expiry_date and expiry_date &lt; current_date;green:expiry_date &gt;= current_date</attribute>
</xpath>
</field>
</record>
<record id="search_product_lot_filter" model="ir.ui.view">
<field name="name">product_expiry_simple.stock.production.lot.search</field>
<field name="model">stock.production.lot</field>
<field name="inherit_id" ref="stock.search_product_lot_filter"/>
<field name="arch" type="xml">
<field name="product_id" position="after">
<filter string="Expired" name="expired"
domain="[('expiry_date', '&lt;', context_today().strftime('%Y-%m-%d'))]"/>
<filter string="Not Expired" name="no-expired"
domain="[('expiry_date', '&gt;=', context_today().strftime('%Y-%m-%d'))]"/>
</field>
<group expand="0" position="inside">
<filter name="expiry_date_groupby" string="Expiry Date"
context="{'group_by': 'expiry_date:month'}"/>
</group>
</field>
</record>
<!-- QUANTS -->
<!-- No need to inherit the form view, because the expiry date is shown in the lot_id via display_name field -->
<record id="view_stock_quant_tree" model="ir.ui.view">
<field name="name">product_expiry_simple.stock.quant.tree</field>
<field name="model">stock.quant</field>
<field name="inherit_id" ref="stock.view_stock_quant_tree"/>
<field name="arch" type="xml">
<field name="lot_id" position="after">
<field name="expiry_date"/>
</field>
<xpath expr="/tree" position="attributes">
<attribute name="colors">red:expiry_date and expiry_date &lt; current_date;green:expiry_date &gt;= current_date</attribute>
</xpath>
</field>
</record>
<record id="quant_search_view" model="ir.ui.view">
<field name="name">product_expiry_simple.stock.quant.search</field>
<field name="model">stock.quant</field>
<field name="inherit_id" ref="stock.quant_search_view"/>
<field name="arch" type="xml">
<filter name="internal_loc" position="after">
<separator/>
<filter string="Expired" name="expired"
domain="[('expiry_date', '&lt;', context_today().strftime('%Y-%m-%d'))]"
groups="stock.group_production_lot"/>
<filter string="Not Expired" name="no-expired"
domain="[('expiry_date', '&gt;=', context_today().strftime('%Y-%m-%d'))]"
groups="stock.group_production_lot"/>
</filter>
<filter context="{'group_by' : 'lot_id'}" position="after">
<filter name="expiry_date_groupby" string="Expiry Date"
context="{'group_by': 'expiry_date:month'}" groups="stock.group_production_lot"/>
</filter>
</field>
</record>
</data>
</openerp>

View File

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

View File

@@ -0,0 +1,31 @@
# -*- 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": "Product Simple Accounting",
"summary": "Simplify the accounting on product, remove accounting tab",
"version": "8.0.1.0.0",
"category": "Uncategorized",
"website": "www.akretion.com",
"author": " Akretion",
"license": "AGPL-3",
"application": False,
"installable": True,
"external_dependencies": {
"python": [],
"bin": [],
},
"depends": [
"product_profile",
"account_product_fiscal_classification",
],
"data": [
"views/product_view.xml",
],
"demo": [
],
"qweb": [
]
}

View File

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

View File

@@ -0,0 +1,24 @@
# -*- 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).
from openerp import fields, models
class ProductProfile(models.Model):
_inherit = 'product.profile'
def _get_types(self):
return [('product', 'Stockable Product'),
('consu', 'Consumable'),
('service', 'Service')]
property_account_income = fields.Many2one(
'account.account',
'Property Account Income',
company_dependent=True)
property_account_expense = fields.Many2one(
'account.account',
'Property Account Expense',
company_dependent=True)

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="product_template_view_form" model="ir.ui.view">
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="priority" eval="64"/>
<field name="arch" type="xml">
<page string="Accounting" position="replace"/>
<field name="profile_id" position="after">
<field name="categ_id"/>
<field name="fiscal_classification_id" widget="selection"/>
</field>
<field name="standard_price" position="after">
<field name="valuation" attrs="{'invisible':[('type', 'in', ('service', 'consu'))]}"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
# © 2017 Chafique DELLI @ Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# © 2017 Chafique DELLI @ Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
'name': 'Product Unit Manager Group',
'summary': 'Add a group Product Unit of Measure Manager',
'version': '8.0.1.0.0',
'category': 'Product',
'website': 'http://akretion.com',
'author': 'Akretion',
'license': 'AGPL-3',
'installable': True,
'depends': [
'sale',
'purchase',
'mrp',
],
'data': [
'security/product_security.xml',
'security/ir.model.access.csv',
'views/product_view.xml',
],
}

View File

@@ -0,0 +1,29 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * product_unit_manager_group
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-13 15:35+0000\n"
"PO-Revision-Date: 2017-03-13 15:35+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: product_unit_manager_group
#: model:res.groups,comment:product_unit_manager_group.group_uom_manager
#: model:res.groups,name:product_unit_manager_group.group_uom_manager
msgid "Manage Multiple Units of Measure"
msgstr "Gérer plusieurs unités de mesure"
#. module: product_unit_manager_group
#: model:res.groups,comment:product.group_uom
#: model:res.groups,name:product.group_uom
msgid "Use Multiple Units of Measure"
msgstr "Utiliser plusieurs unités de mesure"

View File

@@ -0,0 +1,13 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_product_uom_manager,product.uom.manager,product.model_product_uom,group_uom_manager,1,1,1,1
access_product_uom_categ_manager,product.uom.categ.manager,product.model_product_uom_categ,group_uom_manager,1,1,1,1
access_product_uom_user,product.uom.user,product.model_product_uom,product.group_uom,1,0,0,0
access_product_uom_categ_user,product.uom.categ.user,product.model_product_uom_categ,product.group_uom,1,0,0,0
sale.access_product_uom_sale_manager,product.uom salemanager,product.model_product_uom,base.group_sale_manager,1,0,0,0
sale.access_product_uom_categ_sale_manager,product.uom.categ salemanager,product.model_product_uom_categ,base.group_sale_manager,1,0,0,0
purchase.access_product_uom_purchase_manager,product.uom purchase_manager,product.model_product_uom,purchase.group_purchase_manager,1,0,0,0
purchase.access_product_uom_categ_purchase_manager,product.uom.categ purchase_manager,product.model_product_uom_categ,purchase.group_purchase_manager,1,0,0,0
mrp.access_product_uom_mrp_manager,product.uom mrp_manager,product.model_product_uom,mrp.group_mrp_manager,1,0,0,0
mrp.access_product_uom_categ_mrp_manager,product.uom.categ mrp_manager,product.model_product_uom_categ,mrp.group_mrp_manager,1,0,0,0
stock.access_product_uom_stock_manager,product.uom stock_manager,product.model_product_uom,stock.group_stock_manager,1,0,0,0
stock.access_product_uom_categ_stock_manager,product.uom.categ stock_manager,product.model_product_uom_categ,stock.group_stock_manager,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_product_uom_manager product.uom.manager product.model_product_uom group_uom_manager 1 1 1 1
3 access_product_uom_categ_manager product.uom.categ.manager product.model_product_uom_categ group_uom_manager 1 1 1 1
4 access_product_uom_user product.uom.user product.model_product_uom product.group_uom 1 0 0 0
5 access_product_uom_categ_user product.uom.categ.user product.model_product_uom_categ product.group_uom 1 0 0 0
6 sale.access_product_uom_sale_manager product.uom salemanager product.model_product_uom base.group_sale_manager 1 0 0 0
7 sale.access_product_uom_categ_sale_manager product.uom.categ salemanager product.model_product_uom_categ base.group_sale_manager 1 0 0 0
8 purchase.access_product_uom_purchase_manager product.uom purchase_manager product.model_product_uom purchase.group_purchase_manager 1 0 0 0
9 purchase.access_product_uom_categ_purchase_manager product.uom.categ purchase_manager product.model_product_uom_categ purchase.group_purchase_manager 1 0 0 0
10 mrp.access_product_uom_mrp_manager product.uom mrp_manager product.model_product_uom mrp.group_mrp_manager 1 0 0 0
11 mrp.access_product_uom_categ_mrp_manager product.uom.categ mrp_manager product.model_product_uom_categ mrp.group_mrp_manager 1 0 0 0
12 stock.access_product_uom_stock_manager product.uom stock_manager product.model_product_uom stock.group_stock_manager 1 0 0 0
13 stock.access_product_uom_categ_stock_manager product.uom.categ stock_manager product.model_product_uom_categ stock.group_stock_manager 1 0 0 0

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record id="product.group_uom" model="res.groups">
<field name="name">Use Multiple Units of Measure</field>
<field name="comment">Use multiple units of measure</field>
</record>
<record id="group_uom_manager" model="res.groups">
<field name="name">Manage Multiple Units of Measure</field>
<field name="comment">Manage Multiple Units of Measure</field>
<field name="category_id" ref="base.module_category_hidden"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="implied_ids" eval="[(6, 0, [ref('product.group_uom')])]"/>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="product.next_id_16" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('product_unit_manager_group.group_uom_manager')])]"/>
</record>
<record id="product.menu_product_uom_form_action" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('product_unit_manager_group.group_uom_manager')])]"/>
</record>
<record id="product.menu_product_uom_categ_form_action" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('product_unit_manager_group.group_uom_manager')])]"/>
</record>
<record id="stock.menu_stock_unit_measure_stock" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('product_unit_manager_group.group_uom_manager')])]"/>
</record>
<record id="stock.menu_stock_uom_categ_form_action" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('product_unit_manager_group.group_uom_manager')])]"/>
</record>
<record id="stock.menu_stock_uom_form_action" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('product_unit_manager_group.group_uom_manager')])]"/>
</record>
<record id="purchase.menu_purchase_unit_measure_purchase" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('product_unit_manager_group.group_uom_manager')])]"/>
</record>
<record id="purchase.menu_purchase_uom_categ_form_action" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('product_unit_manager_group.group_uom_manager')])]"/>
</record>
<record id="purchase.menu_purchase_uom_form_action" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('product_unit_manager_group.group_uom_manager')])]"/>
</record>
</data>
</openerp>

View File

@@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Product Usability module for Odoo
@@ -29,3 +29,20 @@ class ProductTemplate(models.Model):
price_history_ids = fields.One2many(
'product.price.history', 'product_template_id',
string='Product Price History')
name = fields.Char(track_visibility='onchange')
type = fields.Selection(track_visibility='onchange')
categ_id = fields.Many2one(track_visibility='onchange')
list_price = fields.Float(track_visibility='onchange')
sale_ok = fields.Boolean(track_visibility='onchange')
active = fields.Boolean(track_visibility='onchange')
state = fields.Selection(track_visibility='onchange')
weight = fields.Float(track_visibility='onchange')
weight_net = fields.Float(track_visibility='onchange')
class ProductProduct(models.Model):
_inherit = 'product.product'
default_code = fields.Char(track_visibility='onchange')
ean13 = fields.Char(track_visibility='onchange')
active = fields.Boolean(track_visibility='onchange')

View File

@@ -85,9 +85,6 @@
<field name="name" position="attributes">
<attribute name="class"></attribute>
</field>
<field name="description" position="attributes">
<attribute name="attrs">{'invisible': True}</attribute>
</field>
<!-- END for wider 'name' field -->
</field>
</record>
@@ -128,6 +125,78 @@
</field>
</record>
<record id="product_ul_form_view" model="ir.ui.view">
<field name="name">usability.product.ul.form</field>
<field name="model">product.ul</field>
<field name="inherit_id" ref="product.product_ul_form_view"/>
<field name="arch" type="xml">
<!-- Useusally, the size of packaging is written in cm,
so I propose to use that UoM for size of packaging.
Nothing is written in the native product module about this -->
<field name="height" position="replace">
<label for="height"/>
<div name="height">
<field name="height" class="oe_inline"/>
<label string=" cm" class="oe_inline"/>
</div>
</field>
<field name="width" position="replace">
<label for="width"/>
<div name="width">
<field name="width" class="oe_inline"/>
<label string=" cm" class="oe_inline"/>
</div>
</field>
<field name="length" position="replace">
<label for="length"/>
<div name="length">
<field name="length" class="oe_inline"/>
<label string=" cm" class="oe_inline"/>
</div>
</field>
<field name="weight" position="replace">
<label for="weight"/>
<div name="weight">
<field name="weight" class="oe_inline"/>
<label string=" kg" class="oe_inline"/>
</div>
</field>
</field>
</record>
<record id="product_ul_tree" model="ir.ui.view">
<field name="name">usability.product.ul.tree</field>
<field name="model">product.ul</field>
<field name="inherit_id" ref="product.product_ul_tree"/>
<field name="arch" type="xml">
<field name="type" position="after">
<!-- not so important, but we have room in the tree view, so let's use it -->
<field name="height"/>
<field name="width"/>
<field name="length"/>
<field name="weight"/>
</field>
</field>
</record>
<!-- Add missing search view on product.ul -->
<!-- It doesn't work: when you activate the group by type, it gives a JS error
TypeError: key.indexOf is not a function
-->
<!--
<record id="product_ul_search" model="ir.ui.view">
<field name="name">usability.product.ul.search</field>
<field name="model">product.ul</field>
<field name="arch" type="xml">
<search string="Search Logistic Units">
<field name="name"/>
<group string="Group By" name="groupby">
<filter name="type_groupby" string="Type" context="{'group_by': 'type'}"/>
</group>
</search>
</field>
</record>
-->
</data>
</openerp>

View File

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

View File

@@ -0,0 +1,31 @@
# -*- 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": "Product Variant Usability",
"summary": "Improve the product variant usability",
"version": "8.0.1.0.0",
"category": "Uncategorized",
"website": "www.akretion.com",
"author": " Akretion",
"license": "AGPL-3",
"application": False,
"installable": True,
"external_dependencies": {
"python": [],
"bin": [],
},
"depends": [
"product_variant_inactive",
],
"data": [
"views/product_view.xml",
"views/product_attribute_view.xml",
],
"demo": [
],
"qweb": [
]
}

View File

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

View File

@@ -0,0 +1,16 @@
# -*- 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).
from openerp import fields, models
class ProductTemplate(models.Model):
_inherit = 'product.template'
all_product_variant_ids = fields.One2many(
'product.product',
'product_tmpl_id',
'All Product Variant',
domain=['|', ('active', '=', False), ('active', '=', True)])

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="product_attribute_view_form" model="ir.ui.view">
<field name="model">product.attribute</field>
<field name="arch" type="xml">
<form string="Product Attribute">
<sheet>
<div class="oe_title" style="width: 390px;">
<label class="oe_edit_only" for="name" string="Product Name"/>
<h1><field name="name" class="oe_inline"/></h1>
</div>
<group>
<field name="code"/>
<field name="value_ids" colspan="4" nolabel="1">
<tree editable="bottom">
<field name="name"/>
<field name="code"/>
<field name="comment"/>
</tree>
</field>
</group>
</sheet>
</form>
</field>
</record>
<record id="attribute_tree_view" model="ir.ui.view">
<field name="model">product.attribute</field>
<field name="inherit_id" ref="product.attribute_tree_view"/>
<field name="arch" type="xml">
<xpath expr="//tree" position="attributes">
<attribute name="editable"></attribute>
</xpath>
</field>
</record>
<record id="product.attribute_action" model="ir.actions.act_window">
<field name="view_mode">tree,form</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="product_template_view_form" model="ir.ui.view">
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="priority" eval="64"/>
<field name="arch" type="xml">
<field name="attribute_line_ids" position="after">
<field name="all_product_variant_ids" nolabel="1" required="0">
<tree create="0">
<field name="default_code"/>
<field name="attribute_value_ids" widget="many2many_tags"/>
<field name="qty_available"/>
<field name="active" invisible="1"/>
<button type="object"
name="button_activate"
attrs="{'invisible': [('active','=',True)]}"
icon="gtk-stop"/>
<button type="object"
name="button_deactivate"
attrs="{'invisible': [('active','=',False)]}"
icon="gtk-apply"/>
</tree>
</field>
</field>
<xpath expr="//field[@name='product_variant_count']/../.." position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -277,12 +277,16 @@ class PurchaseSuggestPoCreate(models.TransientModel):
('warehouse_id.company_id', '=', company.id)]
pick_types = spto.search(
pick_type_dom + [(
'default_location_dest_id',
'child_of',
location.location_id.id)])
'default_location_dest_id', 'child_of', location.id)])
# I use location.parent_id.id to support 2 step-receptions
# where the stock.location .type is linked to Warehouse > Receipt
# but location is Warehouse > Stock
if not pick_types:
pick_types = spto.search(
pick_type_dom + [(
'default_location_dest_id',
'child_of',
location.location_id.id)])
if not pick_types:
pick_types = spto.search(pick_type_dom)
if not pick_types:

View File

@@ -26,6 +26,7 @@ for any help or question about this module.
'depends': ['purchase'],
'data': [
'purchase_view.xml',
'stock_view.xml',
'supplierinfo_view.xml',
],
'active': False,

View File

@@ -70,7 +70,7 @@ msgstr "Partenaire"
#. module: purchase_usability_extension
#: view:product.supplierinfo:purchase_usability_extension.product_supplierinfo_view_filter
msgid "Product"
msgstr "Article :"
msgstr "Article"
#. module: purchase_usability_extension
#: view:product.supplierinfo:purchase_usability_extension.product_supplierinfo_view_filter

View File

@@ -1,6 +1,6 @@
# coding: utf-8
# Copyright (C) 2015 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# -*- coding: utf-8 -*-
# © 2015-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.html).
from openerp import models, fields, api
@@ -30,6 +30,15 @@ class PurchaseOrder(models.Model):
partner_ref = fields.Char(track_visibility='onchange')
class StockPicking(models.Model):
_inherit = 'stock.picking'
# Field added to have a clickable link from picking to PO
purchase_id = fields.Many2one(
related='move_lines.purchase_line_id.order_id', readonly=True,
string='Purchase Order')
class ResPartner(models.Model):
_inherit = 'res.partner'
@@ -55,3 +64,9 @@ class ResPartner(models.Model):
compute='_purchase_stats', string='# of Purchase Order')
supplier_invoice_count = fields.Integer(
compute='_purchase_stats', string='# Supplier Invoices')
class ProductTemplate(models.Model):
_inherit = 'product.template'
purchase_ok = fields.Boolean(track_visibility='onchange')

View File

@@ -0,0 +1,25 @@
<?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="view_picking_form" model="ir.ui.view">
<field name="name">purchase_usability.stock.picking.form</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">
<field name="origin" position="after">
<field name="purchase_id" attrs="{'invisible': [('picking_type_code', '!=', 'incoming')]}"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@@ -1,4 +1,4 @@
# coding: utf-8
# -*- coding: utf-8 -*-
# © 2015 David BEAL @ Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
@@ -8,5 +8,8 @@ from openerp import models, fields
class ProductSupplierinfo(models.Model):
_inherit = 'product.supplierinfo'
supplier_is_company = fields.Boolean(
comodel_name='res.partner', related='name.is_company')
# Change product_tmpl_id to required=False
# because I added that field to form view and it blocks when you save
# the product form with a new supplier info
# This field is now required in the form view
product_tmpl_id = fields.Many2one(required=False)

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