Commit Graph
544 Commits
Author SHA1 Message Date
Christophe Simonis 5a273e74f0 [MERGE] forward port branch saas-12.4 up to fe59754c52
closes odoo/odoo#36721

Signed-off-by: Christophe Simonis <chs@odoo.com>
2019-09-13 13:32:51 +00:00
svs-odoo ee14dc0302 [FIX] purchase: units purchased product button
Before this commit, user got a traceback when he clicks on Units
Purchased button from product view form.
The issue was we asked to the purchase report to be based on a field who
doesn't exist anymore.
The fix only replaces `unit_quantity` for `qty_ordered`.

closes odoo/odoo#36342

Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
2019-09-02 14:13:11 +00:00
Christophe Simonis 51354fadb0 [MERGE] forward port branch saas-12.3 up to 50e571acf7
closes odoo/odoo#36491

Signed-off-by: Christophe Simonis <chs@odoo.com>
2019-09-11 09:39:33 +00:00
Christophe Simonis 9bf0b04adb [MERGE] forward port branch 12.0 up to 82a8cdd6f2 2019-09-06 17:52:48 +02:00
Nicolas Martinelli 6d8e5efa84 [FIX] purchase: default user_id on bill
On top of leading to AccessError in multi-company (if the PO was created
by OdooBot), it might also assign a user without Accounting rights to a
vendor bill.

This reverts commit 392f6f2b2b.

opw-2056061

closes odoo/odoo#36173

Signed-off-by: Nicolas Martinelli (nim) <nim@odoo.com>
2019-08-28 10:01:06 +00:00
Christophe Simonis f26de445e5 [MERGE] forward port branch saas-12.3 up to 6f55fd65da 2019-08-20 12:17:04 +02:00
Christophe Simonis 168e54d488 [MERGE] forward port branch 12.0 up to 32039b2ab4 2019-08-19 18:57:08 +02:00
Nicolas Martinelli 392f6f2b2b [FIX] purchase: default user_id on bill
- Create a PO, change the Purchase Representative (`user_id`)
- Create the corresponding vendor bill

The `user_id` of the PO is not transferred to the invoice.

There is no reason to not keep the value.

opw-2046963

closes odoo/odoo#35611

Signed-off-by: Nicolas Martinelli (nim) <nim@odoo.com>
2019-08-09 14:31:18 +00:00
Arnold Moyaux 20713735bf [REF] purchase: multi company
Adapt purchase to the multicompany changes.

task-1985992
2019-09-03 15:05:04 +00:00
Victor Feyens 7e45b447c3 [IMP] matrix : ui improvements 2019-08-22 15:27:59 +00:00
Lucas Lefèvre 46e48055ed [IMP] account: Store customer/supplier rank on partners
Purpose
=======

To correctly choose in which account a line should be posted,
we have to know if the partner is a customer or a supplier.

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

Keep track of the number of account moves "in" and "out"
a partner has. These counts should be based on the posted
account moves. A customer that has been created from the
'Customer' menuitem will have a rank=1. When a customer
invoice will be created for him, the generated account moves
will be taken into account to compute its rank. The most
invoices we have for a partner, the higher his rank is.

Note: To avoid any concurrent update failures on the partner,
if one transaction has already locked a partner row, the count
update will be skipped that time.

This means the values may be approximative in the database!
The exact values will eventually be correctly computed at
the next successfull try.

Known limitation of this approach: The computation ignores
the set of currently selected companies. Actually, storing
context dependent values in the database is a bad practice,
and is avoided in that case by taking all the companies into
account.

Use the stored fields `customer_rank` and `supplier_rank`
to order partners when searching by name. This allows to show
best customers or best suppliers on top.

To choose if best customer or supplier are shown on top,
the context key `res_partner_search_mode` is used.
The context key can take two values: 'customer' or 'supplier'.
This decision partially reverts/revamps 8766f38 to only use
account moves instead of PO and SO

On actions showing partners, set a default filters to menus to
only display customers (customer_rank > 0) if the string is
"Customers", and only suppliers if the string is "Vendors" or
"Suppliers".

TaskID: 2049131

closes odoo/odoo#35942

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2019-08-22 09:29:26 +00:00
Parth Choksi ebaa132d5d [IMP] various: Clean settings UX (back2basics)
TaskID: 2028958

closes odoo/odoo#35551

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2019-08-21 12:12:33 +00:00
Christophe Simonis 3faea8fbf8 [MERGE] forward port branch saas-12.4 up to f26de445e5 2019-08-21 10:10:11 +02:00
Raphael Collet 9920f20e4c [IMP] models: ORM speedup
This branch is the combination of several optimizations in the ORM:

* store field values once in the cache: the cache reflects more
faithfully the database, only fields that explicitly depend on the
context have an extra indirection in the cache;

* delay recomputations by default: use method `recompute` to explicitly
flush out pending recomputations;

* delay updates in method `write`: updates are stored in a data
structure that can be flushed efficiently to the database with method
`flush` (which also flush out recomputations);

* make method `modified` take advantage of inverse fields to inverse
dependencies;

* filter records by evaluating a domain on records in Python;

* a computed field with `readonly=False` behaves like a normal field
with an onchange method;

* computed fields are computed in superuser mode by default.

Work done by Toufik Ben Jaa, Raphael Collet, Denis Ledoux and Fabien
Pinckaers.

closes odoo/odoo#35659

Signed-off-by: Denis Ledoux <beledouxdenis@users.noreply.github.com>
2019-08-20 12:43:59 +00:00
Prakash Prajapati c058562d73 [IMP] various: Add multi company domains on views
When the many2xxx field relates to a model where company_id is required, set
this  domain [('company_id','=',company_id.id)]

When the company_id field of the related model is not required, set this domain
['|',('company_id','=',company_id.id),('company_id','=',False)]

When setting the domain on a field which is in the treeview of a xxx2many field
evaluate against the company_id of the 'parent'.

Some constraints have been added on sereval models. Take a look at the complete
specification for more details.

TaskID: 2024446
Closes: #35266

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2019-08-16 11:17:28 +00:00
Victor Feyens 699a4614ef [FIX] purchase(_product_matrix): no_variant attributes
Display no variant infos in the purchase order line description.

closes odoo/odoo#35717

Signed-off-by: Damien Bouvy (dbo) <dbo@odoo.com>
2019-08-14 10:23:38 +00:00
Victor Feyens e6c2975e76 [ADD] (sale/purchase)_product_matrix 2019-08-07 12:50:09 +00:00
Victor Feyens 3e41a1dbf2 [IMP] purchase: split onchange product_id for matrix triggering. 2019-08-07 12:50:09 +00:00
Christophe Simonis 886eca0131 [IMP] *: remove usage of oldname attribute
This attribute is misleading as it is insufficient to correctly upgrade
the database. It only renames the column in the database, but other
operations are needed, like updating the corresponding `ir.model.fields`
record (and its xmlid). The default values and the translations are also
lost during the upgrade.

Moreover, this feature was misused. It was:
 - left on fields during multiple versions.
 - used on reports (SQL views). This would be ok if the feature was
   complete, but, as is, it was useless.
 - kept unchanged after a second renaming of the field (which can happen
   versions later the first rename).
 - used, even when the meaning of the field changed. i.e. the field
   `archived` has been renamed to the classic `active`, but the value
   in the database should be switched.
2019-08-05 09:36:41 +00:00
Martin Trigaux 1f5a4649a6 [MERGE] Forward port of saas-12.3 to saas-12.4 up to 87fc1554d6
closes odoo/odoo#34820

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-07-12 13:59:35 +00:00
Martin Trigaux 00ef2653da [MERGE] Forward port of 12.0 to saas-12.2 up to 3b1d00acda
closes odoo/odoo#34732

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-07-10 10:14:06 +00:00
Martin Trigaux 3b1d00acda [MERGE] Forward port of saas-11.3 to 12.0 up to db5261b19e
closes odoo/odoo#34723

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-07-10 08:27:12 +00:00
Martin Trigaux db5261b19e [MERGE] Forwardport of 11.0 to saas-11.3 up to 198b5ecce2
closes odoo/odoo#34719

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-07-10 07:14:38 +00:00
Goffin Simon 88a12afdf4 [FIX] purchase: purchase VATs in a multi-company
Steps to reproduce the bug:

- Create two companies C1 and C2 where C2 is the child of C1
- Create two purchase taxes T1 and T2 where T1 is in C1 and C2 is in T2
- Create a prodcuct P with T1 and T2 as supplier taxes
- Be in C1 as current company
- Create a RFQ and add P

Bug:

T1 and T2 were set on the order line of P instead of T1

PS: This fix is insired from product_id_change in model sale.order.line

opw:2032113

closes odoo/odoo#34658

Signed-off-by: Simon Goffin (sig) <sig@openerp.com>
2019-07-08 12:09:51 +00:00
Christophe Simonis 1debaa89f1 [MERGE] forward port branch 11.0 up to 56ce29e71f 2019-07-04 17:35:07 +02:00
Goffin Simon 5c157c57b0 [FIX] purchase: Wrong RFQ Quantities loaded
Steps to reproduce the bug:
- Create two variants V1 and V2 for procuct template V
- Set supplierinfo on V
- For V1, assign "vendor X" with a minimum order quantity= 10 and price = $10
- For V2, assign "vendor X" with a minimum order quantity= 2 and price = $1
- Create a RFQ for vendor X
- Set V1 on a PO line

Bug:

The minimum quantity of V2 was automatically set (10) instead of the minimum quantity
of V1 (2)

opw:2028527

closes odoo/odoo#34523

Signed-off-by: Simon Goffin (sig) <sig@openerp.com>
2019-07-08 07:24:18 +00:00
Nicolas Martinelli baf1580be4 [FIX] purchase_stock: average cost
- Create 2 rates:
2019-05-01: 1.0
2019-06-01: 0.5
- Set-up a product A in AVCO
- Create a PO for A on 2019-05-15
- Receive the product after 2019-06-01

The AML are created with a rate of 0.5, but the product cost is updated
with the rate of 1.0.

This is because the stock move date is used when it is still assigned,
and not done yet. As described in:

https://github.com/odoo/odoo/blob/2f789b6863407e63f90b3a2d4cc3be09815f7002/addons/stock/models/stock_move.py#L36

The date is the scheduled date until the move is done, then it is the
date of the actual move processing.

We change the date to today's date, since it is the value used to update
the move date:

https://github.com/odoo/odoo/blob/2f789b6863407e63f90b3a2d4cc3be09815f7002/addons/stock/models/stock_move.py#L1143

opw-2006368

closes odoo/odoo#34446

Signed-off-by: Simon Goffin (sig) <sig@openerp.com>
2019-07-01 08:53:53 +00:00
Laurent Smet beaa30a3d1 [IMP/REF] accounting-pocalypse yeaaahh
This commit merges the following models
 * account.invoice and account.move
 * account.invoice.line and account.move.line
 * account.voucher and account.move
 * account.voucher.line and account.move.line

It was the opportunity for a big cleanup of the code, so it also restructures the whole account module, its different models/fields, the tests etc. for a better world and a better code readability.

==== Rationale ====
The rationale of this huge change is that we want journal entries / invoices to be easily edited, and changes reflected in the other model. It's a HUGE feature and very strategic for the fiduciary companies. For example, changing the account of a journal entry needs to be automatically reflected on the related invoice.

The same reasoning applies to sale/purchase vouchers.

==== Changes made in features =====
When creating an invoice, you are now creating a journal entry directly.
--> The object account.invoice no longer exists.
In the same fashion when creating an invoice line, you're now adding journal items directly in the journal entry representing the invoice. If this invoice line has some tax, it may create additional journal items as well.
--> The models account.invoice.line & account.invoice.tax no longer exist

Identically, when creating a sale/purchase receipt with its lines, you are now creating a journal entry directly and there's no more usability difference between encoding a receipt or an invoice.
--> The object account.voucher no longer exists.
--> The object account.voucher.line no longer exists.
--> The whole account_voucher module no longer exists.

Positive side-effects coming from these changes are
* draft invoices/bills/sale or purchase receipts now create a draft accounting entry. Validate these objects now simply post its journal entry. That means that draft invoices/bills/sale or purchase receipt can straightforwardly be included in reporting or budgets.
* opening a journal entry in form view will now always open the correct view: if it's a sale/purchase journal entry we will have a customer invoice/vendor bill view or a sale/purchase receipt view, whatever the menu we're coming from.
* code & business logic simplification. It is also condensed in a single place instead of being partially duplicated on invoices, vouchers and journal entries.

There should be no feature loss, except the one allowing to group multiple journal items together based on the same product during the invoice validation.

==== Changes made in models =====
* account.invoice: model removed. Instead, now use account.move with following mapping

field (account.invoice) 		field (account.move)
-----------------------			--------------------
name 					invoice_payment_ref
number 					name
reference 				ref
comment 				narration
user_id 				invoice_user_id
amount_					total_company_signed amount_total_signed
residual 				amount_residual
state 					state + invoice_payment_state 		/!\ selection changed
date_invoice 				invoice_date
date_due 				invoice_date_due
sent 					invoice_sent
origin 					invoice_origin
payment_term_id 			invoice_payment_term_id
partner_bank_id 			invoice_partner_bank_id
incoterm_id 				invoice_incoterm_id
vendor_bill_id 				invoice_vendor_bill_id
source_email 				invoice_source_email
vendor_display_name 			invoice_vendor_display_name
invoice_icon 				invoice_vendor_icon
cash_rounding_id 			invoice_cash_rounding_id
sequence_number_next 			invoice_sequence_number_next
sequence_number_next_prefix 		invoice_sequence_number_next_prefix

'invoices' subset of account.move can be accessed by using the selection field 'type' or one of the many helpers like is_invoice()

* account.move: now has a valid state 'cancel' that has to be excluded from all business logic
* account.move: field 'amount' renamed into 'amount_total'
* account.move: field 'reverse_entry_id' renamed into 'reversed_entry_id'
* account.move.line: now has a field 'display_type' that has to be excluded from all business logic, in order to support invoice layouting
* account.invoice.line: model removed. Instead, now use account.move.line with following mapping

field (account.invoice.line) 		field (account.move.line)
----------------------------		-------------------------
invoice_id 				move_id
uom_id 					product_uom_id
invoice_line_tax_ids 			tax_ids
account_analytic_id 			analytic_account_id

'invoice lines' subset of all account.move.line from a journal entry can be accessed by using the boolean field 'exclude_from_invoice_tab'

* account.invoice.tax: model removed. Instead, now use account.move.line with following mapping

field (account.invoice.tax) 		field (account.move.line)
---------------------------		-------------------------
invoice_id 				move_id
account_analytic_id 			analytic_account_id
amount 					price_unit
base 					tax_base_amount

'tax lines' subset of all account.move.line from a journal entry can be accessed by using the relational field 'tax_line_id'

* account.invoice.confirm: model removed. Instead, now use the 'post()' function of account.move
* account.invoice.refund: model removed. Instead, now use account.move.reversal to reverse the entries with the same options as we had for invoices
* account.voucher: model removed. Instead, now use account.move of type in ['out_receipt', 'in_receipt]
* account.voucher.line: model removed. Instead, now use account.move.line

==== Changes made in functions ====
* on account.move, method _run_post_draft_to_post() renamed into _autopost_draft_entries()
* on account.move, method action_account_invoice_payment() renamed into action_invoice_register_payment()
* on account.move, method action_invoice_reconcile_to_check() renamed into action_open_matching_suspense_moves()
* on account.move, method _get_domain_edition_mode_available() renamed into _get_domain_matching_supsense_moves()
* on account.move, method _get_intrastat_country_id() renamed into _get_invoice_intrastat_country_id()
* on account.move.line, method _get_domain_for_edition_mode() renamed into _get_suspense_moves_domain()
* in account.bank.statement, contextual key 'edition_mode' renamed into 'suspense_moves_mode'

Was task 1917430
2019-06-28 11:52:55 +00:00
Raphael Collet e0e9ae1edd [FIX] *: special cases for new records 2019-06-13 14:39:13 +00:00
Christophe Simonis 25e3f27062 [MERGE] forward port branch saas-12.3 up to 48a9f5a633 2019-06-17 13:20:35 +02:00
Christophe Simonis 8853e6b594 [MERGE] forward port branch 12.0 up to 7ef4ba03c4 2019-06-11 15:20:13 +02:00
Christophe Simonis a2582c4252 [MERGE] forward port branch 11.0 up to bdc62d8031 2019-06-07 13:00:07 +02:00
Christophe Simonis 71a50a2214 [MERGE] forward port branch saas-12.3 up to 409679866b 2019-06-06 11:54:35 +02:00
Nans Lefebvre ff4f3922a9 [FIX] purchase: fix reference update at onchange
Add two PO with references 'XY' and 'Z' to a vendor bill.
The reference is computed as 'XY, Z' (with ', ' as separator).
Add a PO with reference 'X', the reference becomes 'X' instead of 'XY, Z, X'.

There are two variables that may not be defined (vendor_ref and self.reference),
and specifically the case where a reference is the prefix of another one is not
correctly dealt with.

opw 2005825

closes odoo/odoo#33841

Signed-off-by: Nans Lefebvre (len) <len@odoo.com>
2019-06-03 13:30:42 +00:00
Christophe Simonis 9e9e9acef1 [MERGE] forward port branch saas-11.3 up to a2582c4252 2019-06-07 19:04:43 +02:00
Nicolas Martinelli dea93a683b [FIX] purchase: orderpoint on existing PO
- Create product A:
Reordering rule of 5 units
Set a vendor V
- Create a SO with 1 unit of A
- Create a PO with 1 unit of A for vendor V
- Run the scheduler => the PO contains 6 units
- Run the scheduler => the PO contains 12 units

The PO should not be updated the second time the scheduler is run.

It occurs because the `orderpoint_id` is not set on the PO line, while
the `_quantity_in_progress` method searches for PO lines with the
orderpoint set.

opw-2000962

closes odoo/odoo#33798

Signed-off-by: Nicolas Martinelli (nim) <nim@odoo.com>
2019-05-31 13:19:15 +00:00
Christophe Simonis cfe0523714 [MERGE] forward port branch 12.0 up to 8f21148e1a 2019-05-31 14:37:38 +02:00
Hetashree Chauhan b5cea7e2b6 [IMP] purchase: purchase report improvement
Modify purchase report in order to make it consistent with
sales report.
For the RFQ it will show the Order Date and for the Purchase order
menu it will display the Confirmation Date.

Also rewrite a bit the SQL view in order to compute every purchase
order in the company currency.

Technicaly rewrite the SQL alias in order to have a report more
readable in the future.

Task ID : 1857130.

closes odoo/odoo#28248

Signed-off-by: Arnold Moyaux <amoyaux@users.noreply.github.com>
2019-05-31 09:06:30 +00:00
Yannick Tivisse f5dfe4727c [IMP] api.py: Rename company_id/company_ids into company/companies
The goal is to be coherent with the user property.

Actually, company_id and company_ids on the environment are no fields.

Calling env.company_id returns a browse record, not an id.
2019-05-29 08:09:15 +00:00
Christophe Simonis cffd147cfd [MERGE] forward port branch 11.0 up to a20a31486c 2019-05-28 15:52:00 +02:00
Adrian Torres 73235ad6ae [FIX] purchase: truncate description for stock.move.line
Before this commit, when creating a PO line with a description that was long
enough (~2712 bytes long) and then confirming the PO, a traceback would
pop up with an error from postgres "index row size exceeds maximum".

This is because when confirming a PO, a stock.move is created with a
stock.move.line mirroring the purchase.order.line, however the "name"
field on stock.move.line is indexed (whereas the purchase.order.line is
not), thus triggering the aforementioned error.

This commit solves this issue by truncating the name field on the
stock.move.line to 2000 bytes (for simplicity's sake) upon creation.

Fixes #33549

closes odoo/odoo#33607

Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2019-05-23 11:34:07 +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
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
Hetashree Chauhan e532d4df0d [IMP] purchase: make products company consistence.
Purpose of the commit is to let user select only those
products which are being shared among companies or belongs to own company.

On purchase order user will only able to select those products
which are belongs to same company as purchase order or products
which are sharable by default.

task-2025168
closes: #34342

Signed-off-by: Damien Bouvy (dbo) <dbo@odoo.com>
2019-07-22 05:17:00 +00:00
Adrian Torres 4b38cc6590 [REM] *: calls to @api.multi
Multi is the default api for methods, it is not necessary to explicitly
decorate methods with it, adds clutter and most people use it because
they see that the rest of the code uses it.

Done with `find . -type f -name '*.py' | xargs sed -i '/@api.multi/d'`
2019-07-17 14:13:12 +02:00
Ravi Gadhia 561829849f [IMP] purchase: add section and note on order line 2019-07-16 08:18:55 +00:00
Martin Trigaux fd15ca1918 [MERGE] Forward port of saas-12.4 to master up to 1f5a4649a6
closes odoo/odoo#34850

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2019-07-15 08:12:26 +00:00
Mitali Patel 9d710df076 [REF] *: use the new decimal precision syntax
Since previous commit moved decimal_precision module's feature into base,
use the new syntax for fields declaration
Remove the imports to the removed module
Remove the module from dependency in manifest

sed -i "s|digits=dp.get_precision('\([A-Z a-z]*\)')|digits='\1'|" **.py
sed -i "/from odoo.tools import decimal_precision as dp/d" **py
2019-07-03 11:16:24 +00:00
Olivier Colson b1530265e4 [FIX] purchase: anglosaxon accounting: fix wrong computation of prod qty when multiple stock move
Have a PO with a product in automated valorization, and average as method of valorization
Validate and receive *partially* (create backorder)
invoice with a different price than the PO
Receive the backorder
Invoice the rest, also with a different price than the PO

Before this commit, wrong amounts were written in the account.move corresponding to the invoice.
In particular, the payable account's amount was erroneous because it is computed to balance the move
As a result, the bill showed an amount due different from its total, even though nothing was reconciled with it.

After this commit, the payable entry and hence the amount due on the invoice are correct

OPW 1967289

closes odoo/odoo#32920

Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
2019-04-24 13:17:22 +00:00
Laurent Smet bc131c0cfb [MERGE] manual forward port of accounting-pocalypse (beaa30a3d1)
This commit merges the following models
 * account.invoice and account.move
 * account.invoice.line and account.move.line
 * account.voucher and account.move
 * account.voucher.line and account.move.line

It was the opportunity for a big cleanup of the code, so it also restructures the whole account module, its different models/fields, the tests etc. for a better world and a better code readability.

==== Rationale ====
The rationale of this huge change is that we want journal entries / invoices to be easily edited, and changes reflected in the other model. It's a HUGE feature and very strategic for the fiduciary companies. For example, changing the account of a journal entry needs to be automatically reflected on the related invoice.

The same reasoning applies to sale/purchase vouchers.

==== Changes made in features =====
When creating an invoice, you are now creating a journal entry directly.
--> The object account.invoice no longer exists.
In the same fashion when creating an invoice line, you're now adding journal items directly in the journal entry representing the invoice. If this invoice line has some tax, it may create additional journal items as well.
--> The models account.invoice.line & account.invoice.tax no longer exist

Identically, when creating a sale/purchase receipt with its lines, you are now creating a journal entry directly and there's no more usability difference between encoding a receipt or an invoice.
--> The object account.voucher no longer exists.
--> The object account.voucher.line no longer exists.
--> The whole account_voucher module no longer exists.

Positive side-effects coming from these changes are
* draft invoices/bills/sale or purchase receipts now create a draft accounting entry. Validate these objects now simply post its journal entry. That means that draft invoices/bills/sale or purchase receipt can straightforwardly be included in reporting or budgets.
* opening a journal entry in form view will now always open the correct view: if it's a sale/purchase journal entry we will have a customer invoice/vendor bill view or a sale/purchase receipt view, whatever the menu we're coming from.
* code & business logic simplification. It is also condensed in a single place instead of being partially duplicated on invoices, vouchers and journal entries.

There should be no feature loss, except the one allowing to group multiple journal items together based on the same product during the invoice validation.

==== Changes made in models =====
* account.invoice: model removed. Instead, now use account.move with following mapping

field (account.invoice) 		field (account.move)
-----------------------			--------------------
name 					invoice_payment_ref
number 					name
reference 				ref
comment 				narration
user_id 				invoice_user_id
amount_					total_company_signed amount_total_signed
residual 				amount_residual
state 					state + invoice_payment_state 		/!\ selection changed
date_invoice 				invoice_date
date_due 				invoice_date_due
sent 					invoice_sent
origin 					invoice_origin
payment_term_id 			invoice_payment_term_id
partner_bank_id 			invoice_partner_bank_id
incoterm_id 				invoice_incoterm_id
vendor_bill_id 				invoice_vendor_bill_id
source_email 				invoice_source_email
vendor_display_name 			invoice_vendor_display_name
invoice_icon 				invoice_vendor_icon
cash_rounding_id 			invoice_cash_rounding_id
sequence_number_next 			invoice_sequence_number_next
sequence_number_next_prefix 		invoice_sequence_number_next_prefix

'invoices' subset of account.move can be accessed by using the selection field 'type' or one of the many helpers like is_invoice()

* account.move: now has a valid state 'cancel' that has to be excluded from all business logic
* account.move: field 'amount' renamed into 'amount_total'
* account.move: field 'reverse_entry_id' renamed into 'reversed_entry_id'
* account.move.line: now has a field 'display_type' that has to be excluded from all business logic, in order to support invoice layouting
* account.invoice.line: model removed. Instead, now use account.move.line with following mapping

field (account.invoice.line) 		field (account.move.line)
----------------------------		-------------------------
invoice_id 				move_id
uom_id 					product_uom_id
invoice_line_tax_ids 			tax_ids
account_analytic_id 			analytic_account_id

'invoice lines' subset of all account.move.line from a journal entry can be accessed by using the boolean field 'exclude_from_invoice_tab'

* account.invoice.tax: model removed. Instead, now use account.move.line with following mapping

field (account.invoice.tax) 		field (account.move.line)
---------------------------		-------------------------
invoice_id 				move_id
account_analytic_id 			analytic_account_id
amount 					price_unit
base 					tax_base_amount

'tax lines' subset of all account.move.line from a journal entry can be accessed by using the relational field 'tax_line_id'

* account.invoice.confirm: model removed. Instead, now use the 'post()' function of account.move
* account.invoice.refund: model removed. Instead, now use account.move.reversal to reverse the entries with the same options as we had for invoices
* account.voucher: model removed. Instead, now use account.move of type in ['out_receipt', 'in_receipt]
* account.voucher.line: model removed. Instead, now use account.move.line

==== Changes made in functions ====
* on account.move, method _run_post_draft_to_post() renamed into _autopost_draft_entries()
* on account.move, method action_account_invoice_payment() renamed into action_invoice_register_payment()
* on account.move, method action_invoice_reconcile_to_check() renamed into action_open_matching_suspense_moves()
* on account.move, method _get_domain_edition_mode_available() renamed into _get_domain_matching_supsense_moves()
* on account.move, method _get_intrastat_country_id() renamed into _get_invoice_intrastat_country_id()
* on account.move.line, method _get_domain_for_edition_mode() renamed into _get_suspense_moves_domain()
* in account.bank.statement, contextual key 'edition_mode' renamed into 'suspense_moves_mode'

Was task 1917430
2019-07-01 13:45:57 +02:00