Commit Graph
128586 Commits
Author SHA1 Message Date
qmo-odoo f49d83f07d [IMP] utm, crm: add lead/opportunity stats on campaign
PURPOSE

This commit removes the mass_mailing.campaign model. Instead of having a fully
fledged model, we will simply inherit utm.campaign. We will also add relevant
statistics on utm campaign model in order to use it in various applications.

SPECIFICATIONS

This commit adds leads/generated statistics in the kanban and
the form view of the utm campaign.

Kanban and form views will now display the number of leads and
opportunities generated with the campaign

TaskID: 2002029
PR: #34452
2019-08-02 12:33:42 +00:00
qmo-odoo a661b00015 [REF] utm,mass_mailing: replace mass mailing campaign by utm campaign
PURPOSE

This commit removes the mass_mailing.campaign model. Instead of having a fully
fledged model, we will simply inherit utm.campaign. We will also add relevant
statistics on utm campaign model in order to use it in various applications.

SPECIFICATIONS

This commit removes the mass_mailing.campaign model. Instead of having a fully
fledged model, we will simply inherit utm.campaign. This change implies that
mass_mailing.tag and mass_mailing.stage have to move to the utm model along
their associated views/data.

These changes were made so that campaigns could be used in the future
by social, mass_mailing and mass_sms and available in the same view

This commit also removes the source_id and the medium_id
fields on the campaign.

This commit also moves the unique_ab_testing field from the mass_mailing_campaign
to the mass_mailing model

Task ID: 2002029
PR: #34015
2019-08-02 12:32:35 +00:00
wan 2d086f5d8f [IMP] account: credit note usability
Task 2038326

* Tick the credit note sequence by default on the customer invoices and vendor bills journals
* Write Customer Invoice/Vendor Bill/Credit Note/Customer refund at the top of the document
* The reference field should be printed on the credit note pdf (interesting because it gives source and reason)
* If the document is a credit note, there shouldn't be any payment information on the pdf (the customer doesn't have to pay you) (currently you see the "payment communication" the customer is supposed to use)
* Rename Credit Note to Refund on dashboard
* Add tooltip on payment widget

closes odoo/odoo#35231

Signed-off-by: Cedric Snauwaert (csn) <csn@openerp.com>
2019-07-31 14:39:22 +00:00
Josse Colpaert b66d84119c [IMP] l10n_ca: add PST number on partner for the invoice
If you have a PST number, certain taxes
don't need to be paid, but the number
should be indicated on the invoice however.

opw-1951352
Closes #31982

Signed-off-by: Cedric Snauwaert (csn) <csn@openerp.com>
2019-05-15 15:06:12 +00:00
jbm-odoo e967435b2d [IMP] mail: Change validation success message
If the connection test to mail server succeeds, we shouldn't see
"Oops something went wrong" and "User Error" either

Replace error generation to display success message by bus notify.

closes odoo/odoo#35292

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2019-08-02 11:47:35 +00:00
jbm-odoo 252609d375 [IMP] employee profile: Reload the view if language changed
When a user change his langage in employee profile, he doesn't see
the result before reloading manually the page.

With this commit, when a user change his language, the page is
reloaded on saving. And remove Create button on My Profile

closes odoo/odoo#34906

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2019-08-02 11:44:45 +00:00
Naglis Jonaitis 0fe2b4530f [IMP] *: remove digits attribute from Monetary fields
* account, hr_contract, hr_expense, point_of_sale, sale_margin,
website_sale_delivery, website_sale_wishlist

digits only works on Float fields, on Monetary fields it has no
effect:

- The column_type of a monetary field is always numeric
- It is not applied in `convert_to_column()` or `convert_to_cache()`
- It is not part of `description_attrs`, so it will not be included in
the output of `fields_get()`

closes odoo/odoo#35336

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-08-02 11:17:12 +00:00
Ravi Gohil 914a722f81 [IMP] l10n_th: replace VAT return report
- Added zero rated and exempted taxes
- Improved 7% tax label
- Removed unused tax group

opw-39083

closes odoo/odoo#35203

Signed-off-by: oco-odoo <oco-odoo@users.noreply.github.com>
2019-08-02 11:06:01 +00:00
Kevin Baptiste 6542f3c41f [IMP] website_livechat: improve general usability (back2basics)
Purpose
=======

Clean screens and improve onboarding

TaskID: 2029772

closes odoo/odoo#34543

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2019-08-02 11:33:22 +00:00
Martin Trigaux 66dea8bb7b [REF] web: remove raw_mode flag on export
The export is now always in raw_mode
Adapt the tests

Fixes odoo/odoo#18798

closes odoo/odoo#26724

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-08-02 08:53:24 +00:00
Robin Heinz 987951a8d4 [IMP] point_of_sale: Navigation as employee from frontend to backend.
We added a button for the front end closure to go back to the back end.
Before this, the only way to go back was to change the URL, now we can close the session with the frontend properly.

Also moved the css related to pos_hr in the good directory.
Task-id: 2032178

closes odoo/odoo#34948

Signed-off-by: pimodoo <pimodoo@users.noreply.github.com>
2019-08-02 09:33:05 +00:00
Pierre Masereel 2ef96ee8cc [FIX] stock_account: valuation layer access rights
When we try to validate a pos session without beinig administrator, we
don't have access rights on the valuation layer.

So we've extended this rev: 7ef11e3c96
2019-08-02 09:33:05 +00:00
Yannick Tivisse 690f457541 [IMP] hr_expense: Improve modifiers to allow inheritance
closes odoo/odoo#34553

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2019-08-02 07:47:32 +00:00
Swapnesh Shah 098a4ba67a [IMP] project: improve Warning message for task recursion
Use same as other _check_recursion error messages

closes odoo/odoo#33125

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-08-02 09:12:31 +00:00
Vincent Schippefilt 75aca37453 [IMP] web: listview remove extra style on click
Before this commit, when clicking on a cell in the listview, the cell
receives the focus, which makes it have an extra style (darker gray)
when waiting for the page to laod.

After this commit, the extra style will only be added when using the
keyboard to navigate between the cells and not on click.

task-id: 2041902

closes odoo/odoo#35303

Signed-off-by: Mathieu Duckerts-Antoine <Polymorphe57@users.noreply.github.com>
2019-07-30 14:21:46 +00:00
Naglis Jonaitis 0c413c26af [IMP] hr_attendance: drop redundant attribute
This appears to be leftover from a C/P from the line above, however
`type="html"` does not make much sense on `<p>` element.

closes odoo/odoo#35124

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-07-23 20:41:15 +00:00
Jinal Patel c8a30c2d81 [ADD] repair: add Responsible field on Repair Order
task- 1945878

closes odoo/odoo#35056

Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
2019-07-30 09:30:10 +00:00
Jinal Patel d9ac2e3485 [ADD] repair: add Graph view on Repair Order
- add Reporting > Repairs menu on Repair Order
 - also added pivot view

task- 1945878
2019-07-30 09:30:10 +00:00
Jinal Patel bc067ed388 [ADD] repair: add Tags field on Repair Order
- add Configuration > Repair Orders Tags menu
 - Configuration menu should only be available for Stock/Manager

task- 1945878
2019-07-30 09:30:10 +00:00
Jinal Patel 5006d48203 [ADD] repair: add Parts filter in Repair Order search view
task- 1945878
2019-07-30 06:33:06 +00:00
Martin Trigaux 294a857f4f [IMP] doc: add reference to _lt method
Was added at odoo/odoo#31211

closes odoo/odoo#35393

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-08-02 06:57:01 +00:00
Naglis Jonaitis f17f2e8336 [IMP] website_theme_install: typo in model class name
closes odoo/odoo#35389

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-08-01 20:27:30 +00:00
Naglis Jonaitis 7417d8fc13 [IMP] *: fix typos in field definitions
* account, crm, hr, im_livechat, l10n_ch, l10n_it_edi, mail,
mass_mailing, project, stock, base

- `String` -> `string`;
- `defaut` -> `default`;
- `defaults` -> `default`;
- `reandonly` -> `readonly`;
- removed redundant `placeholder` attribute for `Char` field;
- removed redundant `size` attribute for `Float` and `Integer` fields;
- changed to use `Selection` instead of `Char` for a field having a
defined `selection`.

closes odoo/odoo#35356

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-07-31 17:14:19 +00:00
Gert Pellin ef99ea2daa [IMP] product, sale, sale_management: move discount group on product
The group 'group_discount_per_so_line' is used on reports in
point_of_sale but is created in 'sale' module and point_of_sale doesn't
depends on sale. So we've move this group on product to be able to
properly use it in point_of_sale.

TASK-ID: 2008468

closes odoo/odoo#35041

Signed-off-by: pimodoo <pimodoo@users.noreply.github.com>
2019-08-02 07:19:47 +00:00
Pierre Masereel eba2d26e90 [FIX] point_of_sale: set back orders stat button
The stat button on the pos session that shows the different POS orders
linked to the session has been deleted by mistake in rev: 91532b7b13

So we've set it back.
2019-08-02 06:55:43 +00:00
Gert Pellin ccce07680f [IMP] point_of_sale: improve views of pos objects
We made here some small changes on the views of different object of POS
module, and set the field journal_ids required in the views, because
launching a POS without payment method won't magically assign one
anymore.

TASK-ID: 2008468
2019-08-02 06:55:39 +00:00
Pierre Masereel acbca1195a [IMP] point_of_sale: pos journal for each company
When the accounting localisation is installed after the POS config, the
values on the default POS config which is in data are not completed
because the POS config has been created before any journal exists.

So now, when a chart template is installed, we are completing the POS
config values, and creating the Sale POS journal. We also call the
creation of POS journal when the point_of_sale module is installed after
the template is installed on the database to be sure that we have a
default value for POS journal.

TASK-ID: 2008468
2019-08-02 06:55:37 +00:00
Gert Pellin a6b598e645 [IMP] point_of_sale: correcly set default values on pos config
When a pos config is created, default values set on it are not allways
correct, for the sale journal we are referencing a data, which mean
rthat it only worls in the first company. For the invoice journal, we
are referencing the wrong journal in the onchannge, etc

TASK-ID: 2008468
2019-08-02 06:55:30 +00:00
Pierre Masereel 56331c1a75 [FIX] account: unlink data when installing chart of account
When a chart of account is installed, it first remove all existing
existing data. If you don't have account_accountant module installed,
but you have create a bank or cash journal (through the POS for
example). Some accounts have been created and the installation of chart
template is trying to remove some models, but as the account_accountant
you don't have access write on model 'account.reconcile.model'.
2019-08-01 17:59:53 +00:00
Martin Trigaux f8ff7debdc [FIX] *: bad usage of _ method
No need for selection fields
If in global variable, the _lt should be used instead

closes odoo/odoo#31211

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-08-01 12:40:01 +00:00
Martin Trigaux f4319580e5 [ADD] tools: lazy translation method
Introduces the method _lt

The translation method is now evaluated lazily.
It allows to declare global variables with translatable content

e.g. this code will now work:

LABEL = _lt("User")

def _compute_label(self):
    context = {'lang': self.partner_id.lang}
    self.user_label = LABEL
2019-08-01 12:39:56 +00:00
Simon Lejeune 0fc9a97d20 [REF] stock_account: _compute_average_price unit price rounding
Since the introduction of the stock valuation layer, unit_cost is
rounded in the company currency (actually it is NOT because of an ORM
bug that will be fixed later). With the test introduced at [0], fixing
that ORM bug shows we have a rounding issue (27.02 instead of 27) due to
the company currency rounding on the unit_cost. Since the logic of the
anglo saxon will probably always give some rounding issue (we always
return a price unit that will be multiply by the invoiced quantity)
recomputing a not rounded price unit by using the not rounded value with
the not rounded quantity seems a good enough compromise.

[0] 13a535a091

closes odoo/odoo#35384

Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
2019-08-01 13:16:58 +00:00
Simon Lejeune 9197c0ad23 [ADD] purchase: test planned date
task-2032417

closes odoo/odoo#35148

Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
2019-08-01 08:11:59 +00:00
Ankita Raval a2a39ef41e [IMP] purchase: set schedule_date of po lines as per date_planned of PO
In this commit -
1. Previously, date_planned of PO was computed and set while the creation of PO.
   In this commit, removed the compute logic and now field will be empty until
   user fills it.
2. ‘Set date to all order lines’ button is removed.
3. Now if user have filled the date_planned of PO, it will be copied to all po
   lines.
4. Schedule date of PO line will be readonly if date_planned have any value
   else will be editable.
5. Update the test cases of computation of date_planned.

Task-2032417
2019-08-01 08:11:59 +00:00
jpr-odooandpga-odoo 8bf1486da5 [IMP] mrp: added support embedded google slide on work center
This commit adds new `embed_viewer` widget which will be used display URLs
via embedded iframes.  You can add any valid URL to display page via iframe,
although widget automatically converts raw google slide URL into embedded URL.

Task ID: 1909010

closes odoo/odoo#29404

Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>


Co-authored-by: pga-odoo <pga@odoo.com>
2019-08-01 13:34:58 +00:00
Prakash Prajapati 1a33056557 [IMP] various: Clean stat buttons across all modules.
Purpose
=======

Make them consistent.
Make sure context is correctly set.
Prevent creation when necessary.

Specification
=============

See https://www.odoo.com/web#id=2024467&action=333&active_id=1251&model=project.task&view_type=form&menu_id=4720
for the detailed list of all the requested improvements.

TaskID: 2024467

closes odoo/odoo#34561

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2019-08-01 11:39:51 +00:00
Yenthe666 0c808a082f [IMP] base: improve logging view and add hooks
closes odoo/odoo#32392

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-08-01 13:06:55 +00:00
mreficent 64773140b0 [IMP] doc: remove calls to @api.guess and @api.noguess
Those two decorators are removed/deprecated since recent commits but
some references remained in the documentation.

api.guess and api.noguess is deprecated and removed since c552fb7a61

closes odoo/odoo#35332

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-08-01 13:16:37 +00:00
Meghna Jaswani ee1f0ef1ac [IMP] l10n_lu: update of CoA 2020 PCN standard and tax report
- Update the CoA for 2020
- Add the most recent monthly tax report
instead of the old one with the new tax model
- Base language English (multilang translation in fr and de)

hsh and rgo co-authored

opw-1917932

closes odoo/odoo#35371

Signed-off-by: Josse Colpaert <jco@openerp.com>
2019-08-01 10:17:47 +00:00
Robot OdooandYannick Tivisse 8626257bc7 [MERGE] base: Remove customer/supplier fields on res.partner
1/ Improve res.partner search for customers/suppliers
=========================================

Purpose
-------

This commit allows to call `name_search` with context key
`res_partner_search_mode` that can take currently two values: "customer" or
"supplier".

When ordering search results, order partners by the number of SO they have when
the value is "customer" and by the number of PO if the value is "supplier".

Top suppliers/customers are displayed above in a PO/SO partner dropdown.

We have thought about different implementations before selecting this one:

- Keep the 2 boolean flags and automatically set them if a SO or PO is created
for a customer/supplier (helps a bit but doesn't work well for the first
SO/PO). As the onboarding is also a priority, we didn't implement it.

- Instead of filtering on the bool flags, sort the name_search() result according
to the number of orders they already have (e.g. if you search for "Foo" on a
PO, a supplier "SuperFoo" with 32 purchase orders will appear before supplier
"HorribleFoo" that has no PO). Problem is to do this in an efficient manner for
large databases - possibly we could store a "relevance index" based on the
number
of recent orders. Storing those values is an issue too, as it doesn't work well
for multi company database. Indeed, storing values that depend on the context
is certainly not a good idea.

- Same as previous alternative but with no stored columns, rather a JOIN in
name_search. This is the solution that have been kept. The only concern was
about the perfomances. We tested it on our production base, on a sales order,
as we have way much more customers than suppliers. After a deep analysis on
the querry and the bitmap generated by PostgreSQL, we can conclude that the
count(*) works rather efficiently and that the request is not significantly
heavier than without the context key.

Performance Analysis
--------------------

The following results have been obtained on our production database.

### Before this commit ###

The original query is the following one:

```
EXPLAIN ANALYSE
SELECT res_partner.id
FROM "res_partner"
WHERE ("res_partner"."customer" = True) AND ("res_partner"."active" = True) AND ((("res_partner"."type" != 'private') OR "res_partner"."type" IS NULL)  OR  "res_partner"."type" IS NULL ) AND  (res_partner.email ilike '%eezee-i%'
OR res_partner.display_name ilike '%eezee-i%'
OR res_partner.ref ilike '%eezee-i%'
OR res_partner.vat ilike '%eezeei%')
-- don't panic, trust postgres bitmap
ORDER BY res_partner.display_name ilike '%eezee-i%' desc,
res_partner.display_name
limit 8;
```

Here is the EXPLAIN ANALYSE returned by PostgreSQL:

```
Limit  (cost=1625.50..1625.52 rows=8 width=21) (actual time=13.397..13.404 rows=8 loops=1)
->  Sort  (cost=1625.50..1626.32 rows=326 width=21) (actual time=13.395..13.396 rows=8 loops=1)
Sort Key: (((display_name)::text ~~* '%eezee-i%'::text)) DESC, display_name
Sort Method: top-N heapsort  Memory: 26kB
->  Bitmap Heap Scan on res_partner  (cost=1282.79..1618.98 rows=326 width=21) (actual time=13.025..13.350 rows=56 loops=1)
Recheck Cond: (((email)::text ~~* '%eezee-i%'::text) OR ((display_name)::text ~~* '%eezee-i%'::text) OR ((ref)::text ~~* '%eezee-i%'::text) OR ((vat)::text ~~* '%eezeei%'::text))
Rows Removed by Index Recheck: 1
Filter: (customer AND active AND (((type)::text <> 'private'::text) OR (type IS NULL) OR (type IS NULL)))
Rows Removed by Filter: 1
Heap Blocks: exact=58
->  BitmapOr  (cost=1282.79..1282.79 rows=328 width=0) (actual time=12.983..12.983 rows=0 loops=1)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=5.022..5.022 rows=54 loops=1)
Index Cond: ((email)::text ~~* '%eezee-i%'::text)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=4.128..4.128 rows=56 loops=1)
Index Cond: ((display_name)::text ~~* '%eezee-i%'::text)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..321.00 rows=1 width=0) (actual time=2.240..2.240 rows=0 loops=1)
Index Cond: ((ref)::text ~~* '%eezee-i%'::text)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..317.03 rows=4 width=0) (actual time=1.585..1.585 rows=0 loops=1)
Index Cond: ((vat)::text ~~* '%eezeei%'::text)
Planning time: 0.766 ms
Execution time: 13.489 ms
```

### After this commit ###

Without the context key, the query looks like this:

```
SELECT res_partner.id
FROM "res_partner"
WHERE ("res_partner"."active" = True) AND ((("res_partner"."type" != 'private') OR "res_partner"."type" IS NULL)  OR  "res_partner"."type" IS NULL ) AND  (res_partner.email ilike '%eezee-i%'
OR res_partner.display_name ilike '%eezee-i%'
OR res_partner.ref ilike '%eezee-i%'
OR res_partner.vat ilike '%eezeei%')
-- don't panic, trust postgres bitmap
GROUP BY res_partner.id
ORDER BY COUNT(*) DESC, res_partner.display_name ilike '%eezee-i%' desc,
res_partner.display_name
limit 8;
```

And it quite clear when looking at the EXPLAIN ANALYSE that the request
is quite the same, except the aggregation that is made with a quicksort method.

```
Limit  (cost=1645.00..1645.02 rows=8 width=29) (actual time=13.200..13.206 rows=8 loops=1)
->  Sort  (cost=1645.00..1645.82 rows=328 width=29) (actual time=13.197..13.198 rows=8 loops=1)
Sort Key: (count(*)) DESC, (((display_name)::text ~~* '%eezee-i%'::text)) DESC, display_name
Sort Method: top-N heapsort  Memory: 26kB
->  GroupAggregate  (cost=1631.88..1638.44 rows=328 width=29) (actual time=13.090..13.160 rows=56 loops=1)
Group Key: id
->  Sort  (cost=1631.88..1632.70 rows=328 width=20) (actual time=13.080..13.084 rows=56 loops=1)
Sort Key: id
Sort Method: quicksort  Memory: 29kB
->  Bitmap Heap Scan on res_partner  (cost=1282.79..1618.17 rows=328 width=20) (actual time=12.793..13.055 rows=56 loops=1)
Recheck Cond: (((email)::text ~~* '%eezee-i%'::text) OR ((display_name)::text ~~* '%eezee-i%'::text) OR ((ref)::text ~~* '%eezee-i%'::text) OR ((vat)::text ~~* '%eezeei%'::text))
Rows Removed by Index Recheck: 1
Filter: (active AND (((type)::text <> 'private'::text) OR (type IS NULL) OR (type IS NULL)))
Rows Removed by Filter: 1
Heap Blocks: exact=58
->  BitmapOr  (cost=1282.79..1282.79 rows=328 width=0) (actual time=12.755..12.755 rows=0 loops=1)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=4.823..4.823 rows=54 loops=1)
Index Cond: ((email)::text ~~* '%eezee-i%'::text)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=3.941..3.941 rows=56 loops=1)
Index Cond: ((display_name)::text ~~* '%eezee-i%'::text)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..321.00 rows=1 width=0) (actual time=2.186..2.186 rows=0 loops=1)
Index Cond: ((ref)::text ~~* '%eezee-i%'::text)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..317.03 rows=4 width=0) (actual time=1.798..1.798 rows=0 loops=1)
Index Cond: ((vat)::text ~~* '%eezeei%'::text)
Planning time: 0.761 ms
Execution time: 13.317 ms
```

With the context key, the query looks like this:

```
EXPLAIN ANALYSE
SELECT res_partner.id
FROM "res_partner"
LEFT JOIN sale_order ON res_partner.id = sale_order.partner_id
WHERE ("res_partner"."active" = True) AND ((("res_partner"."type" != 'private') OR "res_partner"."type" IS NULL)  OR  "res_partner"."type" IS NULL ) AND  (res_partner.email ilike '%eezee-i%'
OR res_partner.display_name ilike '%eezee-i%'
OR res_partner.ref ilike '%eezee-i%'
OR res_partner.vat ilike '%eezeei%')
-- don't panic, trust postgres bitmap
GROUP BY res_partner.id
ORDER BY COUNT(*) DESC, res_partner.display_name ilike '%eezee-i%' desc,
res_partner.display_name
limit 8;
```

The only difference is that a nested loop is made for the left join, as postgreSQL has
correctly identified the dicriminating table. The correct result is obtained within
a similar duration.

```
Limit  (cost=2700.68..2700.70 rows=8 width=29) (actual time=12.561..12.568 rows=8 loops=1)
->  Sort  (cost=2700.68..2701.50 rows=328 width=29) (actual time=12.559..12.560 rows=8 loops=1)
Sort Key: (count(*)) DESC, (((res_partner.display_name)::text ~~* '%eezee-i%'::text)) DESC, res_partner.display_name
Sort Method: top-N heapsort  Memory: 26kB
->  GroupAggregate  (cost=2687.56..2694.12 rows=328 width=29) (actual time=12.449..12.527 rows=56 loops=1)
Group Key: res_partner.id
->  Sort  (cost=2687.56..2688.38 rows=328 width=20) (actual time=12.408..12.425 rows=305 loops=1)
Sort Key: res_partner.id
Sort Method: quicksort  Memory: 42kB
->  Nested Loop Left Join  (cost=1283.21..2673.86 rows=328 width=20) (actual time=11.629..12.340 rows=305 loops=1)
->  Bitmap Heap Scan on res_partner  (cost=1282.79..1618.17 rows=328 width=20) (actual time=11.596..11.862 rows=56 loops=1)
Recheck Cond: (((email)::text ~~* '%eezee-i%'::text) OR ((display_name)::text ~~* '%eezee-i%'::text) OR ((ref)::text ~~* '%eezee-i%'::text) OR ((vat)::text ~~* '%eezeei%'::text))
Rows Removed by Index Recheck: 1
Filter: (active AND (((type)::text <> 'private'::text) OR (type IS NULL) OR (type IS NULL)))
Rows Removed by Filter: 1
Heap Blocks: exact=58
->  BitmapOr  (cost=1282.79..1282.79 rows=328 width=0) (actual time=11.560..11.560 rows=0 loops=1)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=4.724..4.724 rows=54 loops=1)
Index Cond: ((email)::text ~~* '%eezee-i%'::text)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=3.825..3.825 rows=56 loops=1)
Index Cond: ((display_name)::text ~~* '%eezee-i%'::text)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..321.00 rows=1 width=0) (actual time=1.752..1.752 rows=0 loops=1)
Index Cond: ((ref)::text ~~* '%eezee-i%'::text)
->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..317.03 rows=4 width=0) (actual time=1.254..1.254 rows=0 loops=1)
Index Cond: ((vat)::text ~~* '%eezeei%'::text)
->  Index Only Scan using sale_order_partner_id_index on sale_order  (cost=0.42..2.74 rows=48 width=4) (actual time=0.006..0.007 rows=5 loops=56)
Index Cond: (partner_id = res_partner.id)
Heap Fetches: 12
Planning time: 1.056 ms
Execution time: 13.791 ms
```

2/ Remove customer and supplier fields from res.partner
===========================================

Purpose
-------

Fields `customer` and `supplier` on `res.partner`
are mostly used in domains of many2x fields.

Those domains can confuse end users because they don't
see the partner they are looking for; and it's not obvious why.

Some identified problems:

1. It can lead to duplicated partners: the user does not find
the partner, so he creates a new one.

2. The user imports supplier contacts in the Contacts app, so they
don't get the `supplier` flag. Then the user wants to make a purchase order,
and cannot find the new suppliers in the list

3. A user removes the customer flag on a prospect, because they don't think
it's a customer yet - except now they can't make a quote for that customer...

Specification
-------------

Remove the two mentioned fields.

Since fields `customer` and `supplier` have been removed, all partners
are now shown in many2one dropdowns.

But in some cases, not all partners are relevant or some are more likely
to be relevant than others. e.g. when creating a PO, top suppliers have a
higher priority than other partners.

So, adapt the places where those fields were used with the new mechanism to
display the searched the partners, according to the number purchase/sales
orders they made.

TaskID: 2031147

closes odoo/odoo#34524

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>

Co-authored-by: Yannick Tivisse <yti@odoo.com>
2019-08-01 14:08:08 +02:00
Lucas LefèvreandYannick Tivisse 3e97cff779 [IMP] base: Remove customer and supplier fields from res.partner
Purpose
=======

Fields `customer` and `supplier` on `res.partner`
are mostly used in domains of many2x fields.

Those domains can confuse end users because they don't
see the partner they are looking for; and it's not obvious why.

Some identified problems:

1. It can lead to duplicated partners: the user does not find
   the partner, so he creates a new one.

2. The user imports supplier contacts in the Contacts app, so they
   don't get the `supplier` flag. Then the user wants to make a purchase order,
   and cannot find the new suppliers in the list

3. A user removes the customer flag on a prospect, because they don't think
   it's a customer yet - except now they can't make a quote for that customer...

Specification
=============

Remove the two mentioned fields.

Since fields `customer` and `supplier` have been removed, all partners
are now shown in many2one dropdowns.

But in some cases, not all partners are relevant or some are more likely
to be relevant than others. e.g. when creating a PO, top suppliers have a
higher priority than other partners.

So, adapt the places where those fields were used with the new mechanism to
display the searched the partners, according to the number purchase/sales
orders they made.

TaskID: 2031147

Co-authored-by: Yannick Tivisse <yti@odoo.com>
2019-08-01 12:42:03 +02:00
Lucas LefèvreandYannick Tivisse 8766f388da [IMP] base: Allow to better search partners if they are customers/suppliers
This commit allows to call `name_search` with context key
`res_partner_search_mode` that can take currently two values: "customer" or
 "supplier".

When ordering search results, order partners by the number of SO they have when
the value is "customer" and by the number of PO if the value is "supplier".

Top suppliers/customers are displayed above in a PO/SO partner dropdown.

We have thought about different implementations before selecting this one:

- Keep the 2 boolean flags and automatically set them if a SO or PO is created
  for a customer/supplier (helps a bit but doesn't work well for the first
  SO/PO). As the onboarding is also a priority, we didn't implement it.

- Instead of filtering on the bool flags, sort the name_search() result according
  to the number of orders they already have (e.g. if you search for "Foo" on a
  PO, a supplier "SuperFoo" with 32 purchase orders will appear before supplier
  "HorribleFoo" that has no PO). Problem is to do this in an efficient manner for
  large databases - possibly we could store a "relevance index" based on the
  number
  of recent orders. Storing those values is an issue too, as it doesn't work well
  for multi company database. Indeed, storing values that depend on the context
  is certainly not a good idea.

- Same as previous alternative but with no stored columns, rather a JOIN in
  name_search. This is the solution that have been kept. The only concern was
  about the perfomances. We tested it on our production base, on a sales order,
  as we have way much more customers than suppliers. After a deep analysis on
  the querry and the bitmap generated by PostgreSQL, we can conclude that the
  count(*) works rather efficiently and that the request is not significantly
  heavier than without the context key.

Performance Analysis
====================

The following results have been obtained on our production database.

Before this commit
------------------

The original query is the following one:

```
EXPLAIN ANALYSE
SELECT res_partner.id
   FROM "res_partner"
 WHERE ("res_partner"."customer" = True) AND ("res_partner"."active" = True) AND ((("res_partner"."type" != 'private') OR "res_partner"."type" IS NULL)  OR  "res_partner"."type" IS NULL ) AND  (res_partner.email ilike '%eezee-i%'
     OR res_partner.display_name ilike '%eezee-i%'
     OR res_partner.ref ilike '%eezee-i%'
     OR res_partner.vat ilike '%eezeei%')
     -- don't panic, trust postgres bitmap
ORDER BY res_partner.display_name ilike '%eezee-i%' desc,
        res_partner.display_name
limit 8;
```

Here is the EXPLAIN ANALYSE returned by PostgreSQL:

```
 Limit  (cost=1625.50..1625.52 rows=8 width=21) (actual time=13.397..13.404 rows=8 loops=1)
   ->  Sort  (cost=1625.50..1626.32 rows=326 width=21) (actual time=13.395..13.396 rows=8 loops=1)
         Sort Key: (((display_name)::text ~~* '%eezee-i%'::text)) DESC, display_name
         Sort Method: top-N heapsort  Memory: 26kB
         ->  Bitmap Heap Scan on res_partner  (cost=1282.79..1618.98 rows=326 width=21) (actual time=13.025..13.350 rows=56 loops=1)
               Recheck Cond: (((email)::text ~~* '%eezee-i%'::text) OR ((display_name)::text ~~* '%eezee-i%'::text) OR ((ref)::text ~~* '%eezee-i%'::text) OR ((vat)::text ~~* '%eezeei%'::text))
               Rows Removed by Index Recheck: 1
               Filter: (customer AND active AND (((type)::text <> 'private'::text) OR (type IS NULL) OR (type IS NULL)))
               Rows Removed by Filter: 1
               Heap Blocks: exact=58
               ->  BitmapOr  (cost=1282.79..1282.79 rows=328 width=0) (actual time=12.983..12.983 rows=0 loops=1)
                     ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=5.022..5.022 rows=54 loops=1)
                           Index Cond: ((email)::text ~~* '%eezee-i%'::text)
                     ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=4.128..4.128 rows=56 loops=1)
                           Index Cond: ((display_name)::text ~~* '%eezee-i%'::text)
                     ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..321.00 rows=1 width=0) (actual time=2.240..2.240 rows=0 loops=1)
                           Index Cond: ((ref)::text ~~* '%eezee-i%'::text)
                     ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..317.03 rows=4 width=0) (actual time=1.585..1.585 rows=0 loops=1)
                           Index Cond: ((vat)::text ~~* '%eezeei%'::text)
 Planning time: 0.766 ms
 Execution time: 13.489 ms
```

After this commit
-----------------

Without the context key, the query looks like this:

```
SELECT res_partner.id
   FROM "res_partner"
 WHERE ("res_partner"."active" = True) AND ((("res_partner"."type" != 'private') OR "res_partner"."type" IS NULL)  OR  "res_partner"."type" IS NULL ) AND  (res_partner.email ilike '%eezee-i%'
     OR res_partner.display_name ilike '%eezee-i%'
     OR res_partner.ref ilike '%eezee-i%'
     OR res_partner.vat ilike '%eezeei%')
     -- don't panic, trust postgres bitmap
GROUP BY res_partner.id
ORDER BY COUNT(*) DESC, res_partner.display_name ilike '%eezee-i%' desc,
        res_partner.display_name
limit 8;

And it quite clear when looking at the EXPLAIN ANALYSE that the request
is quite the same, except the aggregation that is made with a quicksort method.

 Limit  (cost=1645.00..1645.02 rows=8 width=29) (actual time=13.200..13.206 rows=8 loops=1)
   ->  Sort  (cost=1645.00..1645.82 rows=328 width=29) (actual time=13.197..13.198 rows=8 loops=1)
         Sort Key: (count(*)) DESC, (((display_name)::text ~~* '%eezee-i%'::text)) DESC, display_name
         Sort Method: top-N heapsort  Memory: 26kB
         ->  GroupAggregate  (cost=1631.88..1638.44 rows=328 width=29) (actual time=13.090..13.160 rows=56 loops=1)
               Group Key: id
               ->  Sort  (cost=1631.88..1632.70 rows=328 width=20) (actual time=13.080..13.084 rows=56 loops=1)
                     Sort Key: id
                     Sort Method: quicksort  Memory: 29kB
                     ->  Bitmap Heap Scan on res_partner  (cost=1282.79..1618.17 rows=328 width=20) (actual time=12.793..13.055 rows=56 loops=1)
                           Recheck Cond: (((email)::text ~~* '%eezee-i%'::text) OR ((display_name)::text ~~* '%eezee-i%'::text) OR ((ref)::text ~~* '%eezee-i%'::text) OR ((vat)::text ~~* '%eezeei%'::text))
                           Rows Removed by Index Recheck: 1
                           Filter: (active AND (((type)::text <> 'private'::text) OR (type IS NULL) OR (type IS NULL)))
                           Rows Removed by Filter: 1
                           Heap Blocks: exact=58
                           ->  BitmapOr  (cost=1282.79..1282.79 rows=328 width=0) (actual time=12.755..12.755 rows=0 loops=1)
                                 ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=4.823..4.823 rows=54 loops=1)
                                       Index Cond: ((email)::text ~~* '%eezee-i%'::text)
                                 ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=3.941..3.941 rows=56 loops=1)
                                       Index Cond: ((display_name)::text ~~* '%eezee-i%'::text)
                                 ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..321.00 rows=1 width=0) (actual time=2.186..2.186 rows=0 loops=1)
                                       Index Cond: ((ref)::text ~~* '%eezee-i%'::text)
                                 ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..317.03 rows=4 width=0) (actual time=1.798..1.798 rows=0 loops=1)
                                       Index Cond: ((vat)::text ~~* '%eezeei%'::text)
 Planning time: 0.761 ms
 Execution time: 13.317 ms
```

With the context key, the query looks like this:

```
EXPLAIN ANALYSE
SELECT res_partner.id
   FROM "res_partner"
   LEFT JOIN sale_order ON res_partner.id = sale_order.partner_id
 WHERE ("res_partner"."active" = True) AND ((("res_partner"."type" != 'private') OR "res_partner"."type" IS NULL)  OR  "res_partner"."type" IS NULL ) AND  (res_partner.email ilike '%eezee-i%'
     OR res_partner.display_name ilike '%eezee-i%'
     OR res_partner.ref ilike '%eezee-i%'
     OR res_partner.vat ilike '%eezeei%')
     -- don't panic, trust postgres bitmap
GROUP BY res_partner.id
ORDER BY COUNT(*) DESC, res_partner.display_name ilike '%eezee-i%' desc,
        res_partner.display_name
limit 8;
```

The only difference is that a nested loop is made for the left join, as postgreSQL has
correctly identified the dicriminating table. The correct result is obtained within
a similar duration.

```
 Limit  (cost=2700.68..2700.70 rows=8 width=29) (actual time=12.561..12.568 rows=8 loops=1)
   ->  Sort  (cost=2700.68..2701.50 rows=328 width=29) (actual time=12.559..12.560 rows=8 loops=1)
         Sort Key: (count(*)) DESC, (((res_partner.display_name)::text ~~* '%eezee-i%'::text)) DESC, res_partner.display_name
         Sort Method: top-N heapsort  Memory: 26kB
         ->  GroupAggregate  (cost=2687.56..2694.12 rows=328 width=29) (actual time=12.449..12.527 rows=56 loops=1)
               Group Key: res_partner.id
               ->  Sort  (cost=2687.56..2688.38 rows=328 width=20) (actual time=12.408..12.425 rows=305 loops=1)
                     Sort Key: res_partner.id
                     Sort Method: quicksort  Memory: 42kB
                     ->  Nested Loop Left Join  (cost=1283.21..2673.86 rows=328 width=20) (actual time=11.629..12.340 rows=305 loops=1)
                           ->  Bitmap Heap Scan on res_partner  (cost=1282.79..1618.17 rows=328 width=20) (actual time=11.596..11.862 rows=56 loops=1)
                                 Recheck Cond: (((email)::text ~~* '%eezee-i%'::text) OR ((display_name)::text ~~* '%eezee-i%'::text) OR ((ref)::text ~~* '%eezee-i%'::text) OR ((vat)::text ~~* '%eezeei%'::text))
                                 Rows Removed by Index Recheck: 1
                                 Filter: (active AND (((type)::text <> 'private'::text) OR (type IS NULL) OR (type IS NULL)))
                                 Rows Removed by Filter: 1
                                 Heap Blocks: exact=58
                                 ->  BitmapOr  (cost=1282.79..1282.79 rows=328 width=0) (actual time=11.560..11.560 rows=0 loops=1)
                                       ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=4.724..4.724 rows=54 loops=1)
                                             Index Cond: ((email)::text ~~* '%eezee-i%'::text)
                                       ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..322.22 rows=162 width=0) (actual time=3.825..3.825 rows=56 loops=1)
                                             Index Cond: ((display_name)::text ~~* '%eezee-i%'::text)
                                       ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..321.00 rows=1 width=0) (actual time=1.752..1.752 rows=0 loops=1)
                                             Index Cond: ((ref)::text ~~* '%eezee-i%'::text)
                                       ->  Bitmap Index Scan on res_partner_name_tgm_idx_gin  (cost=0.00..317.03 rows=4 width=0) (actual time=1.254..1.254 rows=0 loops=1)
                                             Index Cond: ((vat)::text ~~* '%eezeei%'::text)
                           ->  Index Only Scan using sale_order_partner_id_index on sale_order  (cost=0.42..2.74 rows=48 width=4) (actual time=0.006..0.007 rows=5 loops=56)
                                 Index Cond: (partner_id = res_partner.id)
                                 Heap Fetches: 12
 Planning time: 1.056 ms
 Execution time: 13.791 ms
```

TaskID: 2031147

Co-authored-by: Yannick Tivisse <yti@odoo.com>
2019-08-01 12:42:03 +02:00
Robot Odoo ed7b53bb1d [MERGE] base: remove field source of ir.translation
Instead, make sure the field src is always up to date

Change a bit the behaviour of `_write` to always try to update potential
translations when in monolanguage (was only done in multi-language if different
than en_US) and always create translations when writing on a translatable field
when in multi-language (was skipped in en_US)

Add tests

Task-id: 2031752
Pad: https://pad.odoo.com/p/r.dbf835d0aae979d858f73446dcbfb1df

closes odoo/odoo#34598

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-08-01 12:02:44 +02:00
Martin Trigaux 18d9c2cab2 [FIX] base: single lang behaviour
If a db is in single lang (en_US or not) but still has translations, the
translation should be updated in addition to updating the referenced record
Add tests to formalise the expected behaviour:

If one language only (en_US or not), when writing on a translatable field:
- record field should updated
- value of potential existing en_US translation should be updated
- src of potential existing translations should be updated
- no new translation should be created

If en_US and fr_FR, when writing on a translatable field in en_US:
- record field should updated
- value of potential existing en_US translation should be updated
- src of potential existing translations should be updated
- new en_US translation should be created if was not present

If en_US and fr_FR, when writing on a translatable field in fr_FR:
- record field should not be updated
- value of potential existing fr_FR translation should be updated
- src of potential existing translations should not be updated
- new fr_FR translation should be created if was not present

Adapt test_new_api test
get_installed is ormcached, just putting active = True is not enough
2019-08-01 09:06:25 +00:00
Martin Trigaux 66ef641f33 [REF] base: remove field source of ir.translation
Instead, make sure the field src is always up to date
Add tests

Changes in _write:
- Replace _set_ids (to be deprecated) call by _upsert_translations as it works
  in batch
- Call _upsert_translations for any language, including en_US
  In case an English translation already existed for a record, only the master
  value (on the reference record) was updated but the user kept seeing the
  translation value (was revealed 73a7534bfc).
- Read src_trans without language
  Similar as above, if an English translation already existed, the translation
  was used for the result of the read and not the new value that has just been
  inserted into the database
- Add _set_source method
  When updating a master record of a translated field, the src field must be
  updated, including in different languages.
  Before it was ok that the src field was out of date as the source was computed

Changes in copy_translation:
- set src as the new value without lang
  update the comment to reflect reality since 489494e733
  src will contain the English version if no changes were made and it will
  contain the modified value if copy was overriden

Changes in upsert_translations:
- Do not force a module, comment, state
  Only src, res_id, name, value and lang must be given. Optional values will no
  longer be set to null if not given
2019-08-01 09:06:25 +00:00
Naglis Jonaitis 7aadcf1181 [REM] website: redundant context attribute on a link
Since this is a website template, the `context` does not make much
sense. Additionally, there is no search filter named `web_features`.
Lastly, the action opened via this link already has a default search
filter enabled [1].

[1]: https://github.com/odoo/odoo/blob/81f024b545c8ddeeed040fcde42db3f5f7e2a468/addons/website/views/website_views.xml#L17

closes odoo/odoo#35275

Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
2019-07-29 19:12:51 +00:00
Simon Lejeune 5c8342f9b5 [REF] stock: tests common
This class referenced demo data but even if they weren't installed, the
tests were passing. Remove the definition and usages.

closes odoo/odoo#35343

Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
2019-07-31 13:20:38 +00:00
wan 13a535a091 [FIX] point_of_sale: anglosaxon prices werent correctly calcuated
Reproduce:
1. I create a product with fifo and real_time valuation (make sure the invoicing policy is 'delivered' and make it available in pos).
2. set the cost of the product to be 5.0 and sale price to be 10.0.
3. I update its inventory and set 5 items. -> total valuation of 25.
4. I change the cost of the product to 1.0.
5. I update again the quantity to 10, making the valuation of the product to 30.0.
6. I configure point of sale to allow invoicing.
7. Open a pos session then sell 7 items of the product (invoice the order).
8. Since the product is fifo, this means that the cost of goods sold is 5 * 5.0 + 2 * 1.0 = 27.0.
9. The correct expense account line should have balance of 27.0.
10. The correct output account line should have balance of -27.0

However, instead of 27.0 as stock valuation amount, the value in the
pos.order invoice is currently 7 * 2.0 = 14 -- and this is wrong. It is
not taking into account the value of the previous stock

Solution:
Missing refactoring from https://github.com/odoo/odoo/commit/14812f41710282f9923078f6764323086500ae85

closes odoo/odoo#35335

Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
2019-07-31 14:04:15 +00:00
Xavier-Do 2293016272 [FIX] core: log error on addSubTest
Since #34996, in some case, the error detail was not logged keeping
only the final summary "x errors, x failures" when running TestSuite.

Making fail test test_cache_invalidation for instance won't show
a detailed message when breaking test_01_project_tour will.
This issue occurs when using subtest, like with assertQueryCount,
@users decorator, test_all_l10n, and test_youtube_urls.

Since Testresult addSubTest append directly to error and failures
instead of calling addError and addFailure, we need to ovewrite
addSubtest too.

closes odoo/odoo#35270

Signed-off-by: Denis Ledoux <beledouxdenis@users.noreply.github.com>
2019-07-30 09:15:30 +00:00
Nathan de Pryck 4f33ae1615 [IMP] iap: multi-company for iap account
The "company_id" fields for the iap account has
been changed by the "company_ids" fields to allow
the use of an iap account with multiple company.

closes odoo/odoo#35093

Signed-off-by: Rémi Rahir (rar) <rar@odoo.com>
2019-07-31 13:24:42 +00:00