I'm following the external APIs documentation : https://www.odoo.com/documentation/13.0/webservices/odoo.html
to implement our companies requirements. I'm required to create a sales order and automatically create an invoice after that. The sales order part is done but I cant seem to be able to attach the Invoice to the Sales order
I've tried linking it via the 'invoice_ids' field but the documentation does not mention how to provide a many2many field in it. here is the code:
many2manyInvoice = [(4, invoice_id)]
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
#Admin user Id
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
models.execute_kw(db, uid, password, 'sale.order', 'write', [[sales_order_id], {'invoice_ids':many2manyInvoice}])
The response returned is 200 , but nothing is happening on the sales order level. I think its the way that I defined the field that might be incorrect.
Can someone help with this issue ? Thanks in advance
Nothing is happening on the sales order level because you are not creating a sales record, writing to it without doing anything. Not sure if this would work in your specific case but here is what I would do.
Use the Pro-forma invoice https://www.odoo.com/documentation/user/13.0/sales/invoicing/proforma.html
Then when a sales record is created run the "Send pro-forma invoice" method using the web api. This takes care of the db linking, as it can get very complicated.
Related
I am trying to make a single action on a sales order in Odoo v15 CE that creates an invoice for the sales order and immediately posts it and registers a payment for it. The way I'm doing so is through a wizard method that looks like this:
def create_invoices(self):
sale_orders = self.env['sale.order'].browse(self._context.get('active_ids', []))
for order in sale_orders:
order._create_invoices()
for inv in order.invoice_ids:
# make invoice:
inv.action_post()
# register payment
# ????
Currently, it creates the invoice and posts it. I would like to add something like inv.register_payment() to the final line in order to register the payment.
I've fount the action_register_payment method of the account.move model and also looked into using the account.payment.register wizard but neither worked. I've also found this question, which is trying to do something similar, but through an XML-RPC call (from what I can tell).
Can anyone please explain how to do this? Thanks!
You have to post the invoices using action_post then register payment by creating a payment like in
https://github.com/odoo/odoo/blob/15.0/addons/account/wizard/account_payment_register.py#L496
account.payment.register is a wizard, that's why you need to create values for it, otherwise you can action_register_payment which is a window action that will trigger the wizard and then it's for the user to register the payment (which is the standard behavior of Odoo)
You can create an account.payment.register record and pass the model and invoice ids in context then call action_create_payments to create the payment with the default values.
Example:
payment_register.with_context(
{'active_model': 'account.move',
'active_ids': inv.ids}
).create({}).action_create_payments()
I'm trying to change the state of a created invoice from 'draft' to 'posted' using the Web APIs (Python) by referring to this documentation : https://www.odoo.com/documentation/13.0/webservices/odoo.html
I'm updating the invoice as follows :
def makeInvoicePosted(invoice_id):
invoice_ids = []
invoice_ids.append(invoice_id)
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
print(common)
uid = common.authenticate(db, username, password, {})
print("makeInvoicePosted : Odoo Admin User Id : ", uid)
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
models.execute_kw(db, uid, password, 'account.move', 'write', [[invoice_id], {'state':"posted"}])
But I'm getting this error : odoo.exceptions.ValidationError: ('Posted journal entry must have an unique sequence number per company.', None)\n'
What could be causing this ? is there something missing in the request?
Thanks in advance!
I recommend to use Odoo's workflow and business logic here by calling post instead of directly writing the state.
models.execute_kw(db, uid, password, 'account.move', 'post', [[invoice_id],])
Why: because there are a lot of checks and also a lot of things done in this method, you could miss or just do wrong (invoices are very complex). You probably will find some mistakes in your calls right before doing the post, because of the checks in it.
I'm creating a bill (supplier invoice) in Xero API (C# .Net). Everything populates perfectly except for the Reference number which remains blank.
Excerpt:
var invoiceObject = new Invoice
{
Reference = "TEST123",
Contact = contact,
Date = DateTime.Now,
DueDate = DateTime.Now,
ExpectedPaymentDate = DateTime.Now,
Status = Xero.Api.Core.Model.Status.InvoiceStatus.Draft,
LineItems = lineItems,
Type = Xero.Api.Core.Model.Types.InvoiceType.AccountsPayable
};
var invoice = api.Invoices.Create(invoiceObject);
The following screenshot demonstrates the issue:
Every other field, lineitem, tax code, etc. populates perfectly.
I've tried different combinations of upper and lowercase characters, numbers, etc. but it doesn't work.
If I log in to Xero, open the Invoice and manually enter TEST123 an save the invoice, it works perfectly.
I've also tried saving the invoice, then editing it and re-saving in the API and the reference still does not populate.
How can I set the reference in the API?
Quick answer
Xero Invoice API docs indicate that you can't set the reference value for an ACCPAY invoice, but that whatever you put for the Invoice Number (which is a non-unique field on ACCPAY Invoices) will also appear in the reference field.
Explanation
I ran into this same issue. I found this comment on Xero's support forum:
https://community.xero.com/developer/discussion/40489223
... which says this:
Reference is presently slightly differently based on whether the
invoice is a sales invoice (ACCREC) or a purchase invoice/bill
(ACCPAY). For a bill the reference is presented in the InvoiceNumber
element, check our documentation on invoices here where we explain
this in more detail.
From the linked to docs
All that said, the screenshot you include in your post does have a "reference" input on it, but that's not an input for the invoice's reference value - that's an input for a possible reference value for a payment you enter against the invoice. The reference value for an invoice appears at the top next to the due date:
I have the exact same issue. I'm using Python Xero but hopefully, it is the same for Javascript.
In my case, I have to use InvoiceNumber instead of Reference for bills.
In odoo 9, I have added a record rule on the model mrp.production as:
['|', ('user_id', '=', user.id), ('user_id', '=', False)]
This will show users only the MOs that belongs to them. Now when I am trying to confirm the sale order which will then create a MO for the lines in that sale order I am getting an access error as:
The requested operation cannot be completed due to security restrictions. Please contact your system administrator.
(Document type: mrp.production, Operation: read)
Diagnosing more I found that it is causing due to the missing_ids. Take a look at this.
Before that I have used the same solution in openerp 7 and it is still working perfect without any access error while confirming SO.
From which user you are trying ? i think you are trying with admin login, and you write security rule that only user of that record can access that. I think that is the problem.
Finally I found the reason of this issue.
In opernep/addons/mrp/procurement.py there is line
production_obj.create(cr, SUPERUSER_ID, vals, context=dict(context, force_company=procurement.company_id.id))
which is using SUPERUSER_ID to create the production order from the procurement.
I don't know why they changed it to use SUPERUSER_ID. May be to enable non mrp users or external users to create mrp orders even if they have not rights. BTW I have not such requirement and I have solved my problem by replacing this SUPERUSER_ID with uid.
I have a question about the rbac system. I think I've pretty well understood it but I need more informations about a special case.
I would like to do the autorisations on groups instead of users. I mean for instance the group "HR" has permission to create a person. Then any person who join this group would have it as well.
Let me give you more informations.
A part of my database:
And this a part of what my group hierarchy could be:
So what I'm looking for, this would be a must, is a system where each group has some autorizations. People get the autorizations of their group and of their parents group (for instance people in "Forsys" has the autorizations of "Forsys", "R&D" and "Administration").
The solution I see at the moment is using bizrule. But I'm not sure write php code in database is a good idea and then if I update the group hierarchy (R&D inherits of RH instead of Administration) I would have to modify bizrule in database. I tried it and it works well but as you can see it require a lot of code.
$user = User::model()->with("people","people.groups")->findByPk(Yii::app()->user->id);
foreach($user->people[0]->groups as $group)
if($group->id == 2)
return true;
return false;
It's just for see if a user is in a group (without checking parent groups and hierarchy)
Another possibility could be create a new table "group_auth" where we would say for instance:
-Group_2 has role "managePerson"
-Group_3 has operation "deleteUser"
...
And then everytime a user is added in or removed of a group we would update his autorizations in the auth_assigment table.
I'd like to hear other opinions on this subject.
All comments will be appreciated :)
Thank you for reading and sorry for my English if you had difficulties to understand me.
Michaƫl S.
Do users ever get their own authorization items? If not, seems like you could in essence swap out the userid column in auth_assignment and name it / treat it as groupID instead. That way you wouldn't need to worry about keeping user auth assignments in sync with your group roles.
A couple of places you'd probably need to make some changes:
- by default CWebUser passes in the logged in userid for use in bizrules. Might be good to change that our with your own override that passes in groupId/groupIds instead.
- you'd need to override CDbAuthManager and rework some of how things work there
We've done something similar on a project I've worked on (we were handling multi-tenant RBAC custom permissions), which required custom CDbAuthManager overrides. It gets a bit tricky if you do it, but there is an awful lot of power available to you.
Edit:
Understood about your users sometimes needing to have additional authorizations. What if your group has a 'roles' field with different roles serialized in it (or some other method of having multiple roles stored for that group, could also be a relationship).
Then, on user login (for efficiency), you'd store those roles in session. Probably the easiest way to handle things would be to write a custom checkAccess for your WebUser override:
https://github.com/yiisoft/yii/blob/1.1.13/framework/web/auth/CWebUser.php#L801
as that will make things simpler to do your custom checking. Then I'd probably do something like:
if(Yii::app()->user->hasGroupAccess() || Yii::app()->user->checkAccess('operation/task/role')) {
....
}
In your WebUser hasGroupAccess method, you could loop over all group roles and send those to checkAccess as well.
Think that will work?
What I use to check access for groups when it's in another table, or somewhere else in the application I give the user the role per default. By using this:
return array(
'components'=>array(
'authManager'=>array(
'class'=>'CDbAuthManager',
'defaultRoles'=>array('authenticated', 'R&D', 'Administration'),
),
),
);
Under: Using Default Roles
By using this, every user gets these assignments. Now, I create a business rule to make sure that the checkAccess('group') will return the correct value.
For example in your case the business rule for R&D would be:
return (
count(
Person::model()->findByPk(Yii::app()->user->id)->groups(array('name'=>'R&D'))
) > 0
) ? true : false;
So what this does is:
find the logged-in person by primary key
look into groups (from the user) for the group with name R&D
if there is a group: return true (else return false)