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`.
closesodoo/odoo#36342
Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
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
closesodoo/odoo#36173
Signed-off-by: Nicolas Martinelli (nim) <nim@odoo.com>
- 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
closesodoo/odoo#35611
Signed-off-by: Nicolas Martinelli (nim) <nim@odoo.com>
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
closesodoo/odoo#35942
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
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.
closesodoo/odoo#35659
Signed-off-by: Denis Ledoux <beledouxdenis@users.noreply.github.com>
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>
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.
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
closesodoo/odoo#34658
Signed-off-by: Simon Goffin (sig) <sig@openerp.com>
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
closesodoo/odoo#34523
Signed-off-by: Simon Goffin (sig) <sig@openerp.com>
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
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
closesodoo/odoo#33841
Signed-off-by: Nans Lefebvre (len) <len@odoo.com>
- 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
closesodoo/odoo#33798
Signed-off-by: Nicolas Martinelli (nim) <nim@odoo.com>
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.
closesodoo/odoo#28248
Signed-off-by: Arnold Moyaux <amoyaux@users.noreply.github.com>
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.
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#33549closesodoo/odoo#33607
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
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
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>
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>
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'`
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
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
closesodoo/odoo#32920
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
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