Odoo create stock.move.line to reserve stock - odoo

product_id = 465
location_id =8
product_qty =1
lot_id = 118
env['stock.move.line'].create( {
'company_id':1,
'picking_id':record.id,
'lot_id':lot_id,
'date':record.date,
'location_dest_id':5,
'location_id':location_id ,
'product_uom_qty':product_qty,
'product_uom_id':32,
'product_id':product_id
})
I am trying to create stock move line to programmtically create stock.move.line. However, after using this code, stock move line is created but it is not working normally. The Transfer can't be processed even after pressing validating without any error popping. When cancel is pressed, it say It is not possible to unreserve more products of xxxxx than you have in stock. After some researching, i am not sure if I should update stock.quant to reserve the products. Then I added these two lines of code at the bottom of the code above. However, it leads to error that said 'int' object has no attribute 'categ_id'" while evaluating........ Is my code for reservation of stock wrong or is there other way that can make this works. Thanks
if env['stock.quant']._get_available_quantity(product_id,location_id, lot_id,strict=True)>=1:
env['stock.quant']._update_available_quantity(product_id,location_id, -product_qty, lot_id,package_id=False, owner_id=False)

The _get_available_quantity function will call _gather function which will call the _get_removal_strategy function and if you provide the product_id as an integer, it will fail to get the removal_strategy_id from the product categ_id
You may notice that the _get_available_quantity function expects a recordset because of the way Odoo defines the variable rounding.

Related

Global / Line Discount for Sale/Purchase/Account

[Odoo 14 Community Edition]
I need to customize Global and Line Discounts (amount & percentage) into Sale / Purchase / Account.
I have done the Sale and Purchase parts. It is just adding fields and a few logics here and there and send the data to Account (account.move) by prepare_invoice methods.
Now here's the issue I am facing -- The Account. I am having a tremendous confusion of where I should modify. After I tried to understand and tracked the flow of the standard invoicing/billing, I am at lost. There are too many functions/variables for me, who do not understand accounting, to try to get the whole idea out of it.
I did add the discount fields that I need. However, the standard calculation of price / taxes / credit / debit are messed up when I try to inherit some methods that I think I should modify. I ended up having incorrect taxes, unbalanced credit/debit, and incorrect total amount.
I tried editing here and there (by inheriting of course. I can still rollback everything I did).
The point is that I need precise suggestions and/or directions of what functions/methods I should inherit just enough to make discount possible. I have 2 Line Discount fields (amount and percent) and 2 Global Discount (also amount and percent). The calculation between them is not the point of interest here. The only problem at this point is to integrate these fields (from SO, PO, and manually created) into the calculation of everything in Invoicing/Billing.
Here are the fields:
account.move
global_discount_amount = fields.Float(string='Global Discount Amount', compute=compute_global_discount_amount, store=True)
global_discount_percent = fields.Float(string='Global Discount Percent', compute=compute_global_discount_percent, store=True)
account.move.line
discount_line_amount = fields.Float(string='Disc. Line Amount', compute=compute_discount_line_amount, store=True)
discount_line_percent = fields.Float(string='Disc. Line %', compute=compute_discount_line_percent, store=True)
Right now, I am messing with some methods such as: (a few examples)
account.move
_recompute_tax_lines
account.move.line
create
_get_fields_onchange_balance_model
_get_price_total_and_subtotal_model
_onchange_price_subtotal
Most of the modifications are written by copying the whole method from standard into my new model (inherit that standard model) and edit some codes here -- Override the standard code from my understanding.
Function computation/execution either depends on other fields value change or compute every time form/listview load.
Check in your case what is depends on the function compute_global_discount_amount and compute_global_discount_percentage
For better developing/troubleshooting, remove any #depends() fields declaration on the functions. Additionally, remove the store=True attribute temporarily. It will help you to narrow down the issue. And make sure you get the correct numbers.
Once you get it, add back fields depending.
Here is a sample example of a method (Odoo 14 CE) override which will be executed during compute amount.
#api.depends(
'line_ids.matched_debit_ids.debit_move_id.move_id.payment_id.is_matched',
'line_ids.matched_debit_ids.debit_move_id.move_id.line_ids.amount_residual',
'line_ids.matched_debit_ids.debit_move_id.move_id.line_ids.amount_residual_currency',
'line_ids.matched_credit_ids.credit_move_id.move_id.payment_id.is_matched',
'line_ids.matched_credit_ids.credit_move_id.move_id.line_ids.amount_residual',
'line_ids.matched_credit_ids.credit_move_id.move_id.line_ids.amount_residual_currency',
'line_ids.debit',
'line_ids.credit',
'line_ids.currency_id',
'line_ids.amount_currency',
'line_ids.amount_residual',
'line_ids.amount_residual_currency',
'line_ids.payment_id.state',
'line_ids.full_reconcile_id')
def _compute_amount(self):
super()._compute_amount()
for record in self:
record.compute_global_discount_amount()
record.compute_global_discount_percent()
def compute_global_discount_amount(self):
for record in self:
# Execute your logic for compute global_discount_amount
record.global_discount_amount = $$$$
have a look at apply_discount function in an inherited class of sale.order
def apply_discount(self, cr, uid, ids, discount_rate):
cur_obj = self.pool.get('res.currency')
res = {}
line_obj = self.pool.get('sale.order.line')
for order in self.browse(cr, uid, ids, context=None):
for line in order.order_line:
line_obj.write(cr, uid, [line.id], {'discount': discount_rate}, context=None)
return res
A new column was added to the new inherited subclass of sale order
'discount_rate' : fields.float('Discount rate'),
Then in the sale order view (an inherited one) placed the new field discount on the sale.order.view and fired an event on the on_change of the value passing the self value of the field to the on_change event
In this way you can apply discount sequentially to the rows of the order without altering the normal process.
Firstful, please pardon my English. Then let's get into the core, I guess that this is exactly the task that I was assigned. Luckily that I was not alone, I was guided by my so-called senior which showed me the way in order to achieve the Global Discount for Invoice and Bill.
By looking at your methods listing, you were already on the right path!
So now, let me help you further...as much as I can
As in my case, I didn't put any new field regarding the Global Discount in Account Move Line model, even though in Sale Order Line and Purchase Order Line Global Discount fields do exist.
All and all, here are the methods that need to be customized:
_onchange_invoice_line_ids
_compute_amount
_recompute_payment_terms_lines
_recompute_tax_lines
I heavily modified the 3rd and 4th methods. However, I think that I still have some bugs, don't hesitate to tell me.

Cannot create unbalanced journal entry. Ids: Differences debit - credit Error when trying to create an invoice line

I'm trying to create an invoice line using the Web APIs and XML-RPC (python). I receive this error while creating it.
xmlrpc.client.Fault: <Fault 2: 'Cannot create unbalanced journal entry. Ids: [12083]\nDifferences debit - credit: [-2629.33]'>
I'm creating the invoice line as follows:
inv_line_id = models.execute_kw(
db, uid, password,
'account.move.line',
'create'[
{'move_id':invoice_id,
'product_id':product_id[0]['id'],
'price_unit':product_id[0]['list_price'],
'quantity':sale_line_id[0]['product_uom_qty'],
'account_id':account_id[0]['property_account_income_categ_id'][0]
}
]
)
If i dont add the 'price_unit' the invoice line is being created normally but without a price.
Anyone knows how to fix this ? Thanks in advance
If you are in the same version of me (V13) or if the code is the same in your version. You could pass a value in the context to don't check the balanced.
'check_move_validity' = False
Find in the file account/models/account_move.py . Line 1721 in method write
# Ensure the move is still well balanced.
if 'line_ids' in vals:
if self._context.get('check_move_validity', True):
self._check_balanced()
self.update_lines_tax_exigibility()
During the create or write of an account.move with only invoice_line_ids set and not line_ids, the _move_autocomplete_invoice_lines_create or _move_autocomplete_invoice_lines_write method is called to auto compute accounting lines of the invoice. In that case, accounts will be retrieved and taxes, cash rounding, and payment terms will be computed. In the end, the values will contain all accounting lines in line_ids and the moves should be balanced.
Latest version of Odoo 13 dated December 10, 2021.
Edit file: /path_of_odoo/addons/account/models/account_move.py
Example:
vim /odoo/addons/account/models/account_move.py
Modify function named _check_balanced and comment line 1582 and add new line whit return
Example:
############################### Before ##################################
############################### A F T E R ###############################

How can I set the pricelist discount to a product when I create a sale order line? In Odoo 9

I have a function who retrieves sale orders from an external server.
Then, I insert each sale order with order lines in the odoo database.
Everything is inserted fine, except the discount.
I have the pricelist in the sale order, with a discount (for example, a discount of 10% in every product), but in all the sale order lines the discount is 0%.
If I add a sale order line manually, the discount appears correctly (10%).
This is my code:
vals = {}
vals['order_id'] = downloaded_sale_order_id
vals['product_id'] = downloaded_product_id
vals['product_uom'] = downloaded_product_uom
new_line_id = self.env['sale.order.line'].create(vals)
I have entered in debug mode and realized that if I call some of these functions after the creation, the discount is applied
Option 1:
new_line_id.product_id_change()
Option 2:
new_line_id.product_uom_change()
But... why they are not called when I launch the create order?
Am I missing something in the code?
You have following options for set discount inside the sale order line while creating it from external server source.
1) Just set discount as like other parameter like uom, product, price etc from the source data of external server if you got discount value from their.
2) You have to call product or uom onchange method to set the discount based on the onchange calling and this is the default and safe method to set most of the data according to the onchange. It will not miss any special fields which are inside any customization with onchange method. I specially recommend this method to use if any discount data is not coming from external server source.
3) You can manage manually calculation of discount based on the external server source like price and qty etc. And set it inside sale order line.
I hope this is very helpful to you. Do not hesitate to ask any thing if not clear.

Computed many2many field dependencies in Odoo 10

I am trying to create a new field on the sale.order.line model. This field is called x_all_route_ids, and is meant to contain all of the available stock.location.route for an Order Line.
It should look up the product_id.route_ids and product_id.routes_from_categ_ids for the Order Line, and join them together into a single set of Routes.
I am trying to set this field up through the Odoo UI, but getting error related to my "Dependencies".
I have Dependencies defined as:
product_id, product_id.route_ids, product_id.routes_from_categ_ids
I have Compute defined as:
for record in self:
record['x_all_route_ids'] = record.product_id.route_ids
To start I am just trying to get the field to show the same value as product_id.route_ids, but it's not working. When I save, I get the following error:
Error while validating constraint
Unknown field u'product_id' in dependency u'product_id'
Any idea what I'm doing wrong here?
I was able to get this working. I think the issue was just a bug in the UI that came about because I had been trying so many different things. After refreshing the page, the following worked:
Dependency = product_id
Field type = many2many
Compute method:
for record in self:
full = record.product_id.route_ids | record.product_id.route_from_categ_ids
record['x_all_route_ids'] = full.filtered('sale_selectable')

Can I use the the power of Generics to solve my issue

I have a wierd issue. I am loading 1k invoice objects, header first then details in my DAL. I am using VB.NET on this project. I am able to get the invoice headers just fine. When I get to loading the details for each invoice I am getting a timeout on SQL Server. I increased the timeout to 5 minutes but still the same thing. If I reduce the invoice count to 200 it works fine.
Here is what I am doing
//I already loaded the invoice headers. I am now iterating each invoice to get it's detail
For Each invoice As Invoice In invoices
drInvoiceItems = DBSqlHelperFactory.ExecuteReader(CONNECTION_STRING, CommandType.StoredProcedure, "dbo.getinvoiceitem", _
New SqlParameter("#invoicenumber", invoice.InvoiceNumber))
While drInvoiceItems.Read()
invoice.LineItems.Add(New InvoiceLine(drInvoiceItems("id"), drInvoiceItems("inv_id"), drInvoiceItems("prodid"), drInvoiceItems("name"), drInvoiceItems("barcode"), drInvoiceItems("quantity"), drInvoiceItems("costprice")))
End While
Next
Return invoices
I am aware that I am firing 1k connections to the DB due to the iterations. Can't I load all the line items with one select statement and then do something like
For Each invoice As Invoice In invoices
invoice.Items.Add(invoiceItems.Find(Function(i as InvoiceItem),i.InvoiceNumber = invoice.InvoiceNumber))
Next
I get the error whenusing the lambda funcion above
Error 1 Value of type 'System.Collections.Generic.List(Of BizComm.InvoiceLine)' cannot be converted to 'BizComm.InvoiceLine'. C:\Projects\BizComm\InvoiceDAL.vb 75 35 BizComm
One thing I have done when iterating through items in the past is use the same Connection object for all the necessary read activities. It seems to greatly enhance performance.
I'd also look at the database to see whether the dbo.getinvoiceitem procedure can be improved, or if another procedure can be written which will give you all the line items for a group of invoices (perhaps by date or customer/vendor) rather than just one header at a time. Then you can more effectively apply your iteration over the invoice collection and add the lines to the headers.
You can also check to see whether there is an effective index on column that the #invoicenumber parameter references.
From your code, it looks like you are not closing the connections and datareaders. See if you can place your connections and datareaders in a USING statement:
Using con As New SqlConnection(connectionString)
....
End Using
The DBSqlHelperFactory opens a connection, but can't close it since the connection is needed after its return. I'd modify the code, so that you open one connection and pass it to DBSqlHelperFactory as a parameter.
To quickly pick up these issues, I always debug with:
Max Pool Size=1;
added to the end of the connection string. That will quickly throw an error any time you forget to close a connection.
Why load InvoiceItems before hand? Can't you load it on demand?
i.e. when you need to get the Items, call a method on Invoice instance (myInvoice.GetItems)
EDIT: It will be better to understand the full picture of what you are trying to do.
Is it really required to get all Invoices as well?
Why not select all the line items for all the invoices you need in a single query. then split the results up into multiple invoice objects?
Re: how do I map between collections?
One implementation could be: create 1000 anemic Invoice object, chuck them in a Dictionary which goes from Id to Invoice. Then when you select the line items you include the invoice id, look up the anemic invoice and add the line to it.