Coder Social home page Coder Social logo

go-odoo's Introduction

go-odoo

An Odoo API client enabling Go programs to interact with Odoo in a simple and uniform way.

GitHub license GoDoc Go Report Card GitHub issues

Usage

Generate your models

./generator/generator -u admin_name -p admin_password -d database_name -o /the/directory/you/want/the/files/to/be/generated/in --url http://localhost:8069 -t ./generator/cmd/tmpl/model.tmpl -m crm.lead,res.users

That's it ! Your models have been generated !

Current generated models

Core models

Core models are ir_model.go and ir_model_fields.go since there are used to generate models.

It is highly recommanded to not remove them, since you would not be able to generate models again.

Custom skilld-labs models

All other models (not core one) are specific to skilld-labs usage. They use our own odoo instance which is version 11. (note that models structure changed between odoo major versions).

If you're ok to work with those models, you can use this library instance, if not you should fork the repository and generate you own models by following steps above.

Enjoy coding!

(All exemples on this README are based on model crm.lead)

package main

import (
	odoo "github.com/skilld-labs/go-odoo"
)

func main() {
	c, err := odoo.NewClient(&odoo.ClientConfig{
		Admin:    "admin_name",
		Password: "admin_password",
		Database: "database_name",
		URL:      "http://localhost:8069",
	})
	if err != nil {
		log.Fatal(err)
	}
	crm := &odoo.CrmLead{
		Name: odoo.NewString("my first opportunity"),
	}
	if id, err := c.CreateCrmLead(crm); err != nil {
		log.Fatal(err)
	} else {
		fmt.Printf("the id of the new crm.lead is %d", id)
	}
}

Models

Generated models contains high level functions to interact with models in an easy and golang way. It covers the most common usage and contains for each model those functions :

Create

func (c *Client) CreateCrmLead(cl *CrmLead) (int64, error) {}
func (c *Client) CreateCrmLeads(cls []*CrmLead) ([]int64, error) {} // !! Only for odoo 12+ versions !!

Update

func (c *Client) UpdateCrmLead(cl *CrmLead) error {}
func (c *Client) UpdateCrmLeads(ids []int64, cl *CrmLead) error {}

Delete

func (c *Client) DeleteCrmLead(id int64) error {}
func (c *Client) DeleteCrmLeads(ids []int64) error {}

Get

func (c *Client) GetCrmLead(id int64) (*CrmLead, error) {}
func (c *Client) GetCrmLeads(ids []int64) (*CrmLeads, error) {}

Find

Find is powerful and allow you to query a model and filter results. Criteria and Options

func (c *Client) FindCrmLead(criteria *Criteria) (*CrmLead, error) {}
func (c *Client) FindCrmLeads(criteria *Criteria, options *Options) (*CrmLeads, error) {}

Conversion

Generated models can be converted to Many2One easily.

func (cl *CrmLead) Many2One() *Many2One {}

Types

The library contains custom types to improve the usability :

Basic types

func NewString(v string) *String {}
func (s *String) Get() string {}

func NewInt(v int64) *Int {}
func (i *Int) Get() int64 {}

func NewBool(v bool) *Bool {}
func (b *Bool) Get() bool {}

func NewSelection(v interface{}) *Selection {}
func (s *Selection) Get() (interface{}) {}

func NewTime(v time.Time) *Time {}
func (t *Time) Get() time.Time {}

func NewFloat(v float64) *Float {}
func (f *Float) Get() float64 {}

Relational types

func NewMany2One(id int64, name string) *Many2One {}
func NewUnassignedMany2One() *Many2One {}
func (m *Many2One) Get() int64 {}

func NewRelation() *Relation {}
func (r *Relation) Get() []int64 {}

one2many and many2many are represented by the Relation type and allow you to execute special actions as defined here.

Criteria and Options

Criteria is a set of Criterion and allow you to query models. More informations

Combined Criterions

Criterions can be combined using AND (arity 2), OR (arity 2) and NOT (arity 1) operators. Criteria have And, Or and Not methods to be able to do such query eg:

c := odoo.NewCriteria().Or(
	odoo.NewCriterion("user_id.name", "=", "Jane Doe"),
	odoo.NewCriterion("user_id.name", "=", "John Doe"),
)

Options allow you to filter results.

cls, err := c.FindCrmLeads(odoo.NewCriteria().Add("user_id.name", "=", "John Doe"), odoo.NewOptions().Limit(2))

Low level functions

All high level functions are based on basic odoo webservices functions.

These functions give you more flexibility but less usability. We recommend you to use models functions (high level).

Here are available low level functions :

func (c *Client) Create(model string, values []interface{}, options *Options) ([]int64, error) {} !! Creating multiple instances is only for odoo 12+ versions !!
func (c *Client) Update(model string, ids []int64, values interface{}, options *Options) error {}
func (c *Client) Delete(model string, ids []int64) error {}
func (c *Client) SearchRead(model string, criteria *Criteria, options *Options, elem interface{}) error {}
func (c *Client) Read(model string, ids []int64, options *Options, elem interface{}) error {}
func (c *Client) Count(model string, criteria *Criteria, options *Options) (int64, error) {}
func (c *Client) Search(model string, criteria *Criteria, options *Options) ([]int64, error) {}
func (c *Client) FieldsGet(model string, options *Options) (map[string]interface{}, error) {}
func (c *Client) ExecuteKw(method, model string, args []interface{}, options *Options) (interface{}, error) {}

Todo

  • Tests
  • Modular template

Issues

go-odoo's People

Contributors

ahuret avatar bhuisgen avatar davidferlay avatar dragonis41 avatar edouard-claude avatar stolexiy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-odoo's Issues

Remove Many2One

Hi!

I have a model with a Many2One relation and I want to unassign it but I don't know how to do it.
I hope you can tell me the direction to follow.

Thank you in advance.

go generate not generating anything

It does not appear that "go generate" is working as expected. No files are being generated and no output is received on stderr or stdout. I may be missing something.

Please let me know if I can provide more information.

user@Computer:~/$
go version go1.16 linux/amd64

user@Computer:~/$echo $ODOO_ADMIN
[email protected]

user@Computer:~/$echo $ODOO_PASSWORD
Apassword123!

user@Computer:~/$echo $ODOO_DATABASE
odoo

user@Computer:~/$echo $ODOO_URL
http://odoo.contoso.com:8069

user@Computer:~/$echo $ODOO_REPO_PATH
/home/user/go/src/github.com/skilld-labs/go-odoo

user@Computer:~/$cd $ODOO_REPO_PATH

user@Computer:~/go/src/github.com/skilld-labs/go-odoo$ ls | grep -v "conversion.go\|generator\|go.mod\|go-odoo-generator\|go.sum\|ir_model_fields.go\|ir_model.go\|LICENSE\|odoo.go\|README.md\|types.go\|version.go"
account_account.go
account_analytic_account.go
account_analytic_line.go
account_analytic_tag.go
account_invoice.go
account_invoice_line.go
account_journal.go
crm_lead.go
crm_lead_tag.go
product_product.go
product_supplierinfo.go
project_project.go
project_task.go
res_company.go
res_partner.go
res_partner_category.go
res_users.go

user@Computer:~/go/src/github.com/skilld-labs/go-odoo$ ls | grep -v "conversion.go\|generator\|go.mod\|go-odoo-generator\|go.sum\|ir_model_fields.go\|ir_model.go\|LICENSE\|odoo.go\|README.md\|types.go\|version.go" | xargs rm

user@Computer:~/go/src/github.com/skilld-labs/go-odoo$ ls
LICENSE  README.md  conversion.go  generator  go.mod  go.sum  ir_model.go  ir_model_fields.go  odoo.go  types.go  version.go

user@Computer:~/go/src/github.com/skilld-labs/go-odoo$ go generate

user@Computer:~/go/src/github.com/skilld-labs/go-odoo$ ls
LICENSE  README.md  conversion.go  generator  go.mod  go.sum  ir_model.go  ir_model_fields.go  odoo.go  types.go  version.go

user@Computer:~/go/src/github.com/skilld-labs/go-odoo$ ls -la ../
total 0
drwxr-xr-x 1 user user 512 Feb 18 20:15 .
drwxr-xr-x 1 user user 512 Feb 18 20:15 ..
drwxr-xr-x 1 user user 512 Feb 18 20:17 go-odoo

Seeding Interface Discussion

Big question going forward for https://github.com/xoe-labs/odoo-operator:

  • What should be the best instance seeding interface?

Options:

  • SQL templates (advantage: use standard sql golang libraries)
  • CSV templates (disadvantage: need a wrapper around def load)
  • A full OdooEnv CLI in golang (disadvantage: code needed. advantage: poke around more easily through golang scripts)

But really is there anything that cannot be done through a well crafted SQL template?

#Disintermediation

Note: I post it here as you guys have built the most comprehensive golang Odoo interface...

type "not found" error + do it in low level functions

right now "not found" error are "soft", we should get it hard by typing it and do it in low level functions to not repeat every time the same code.
We should keep BC too.

eg not found error definition: https://github.com/skilld-labs/go-odoo/blob/master/account_bank_statement_cashbox.go#L81

where it should be instead: https://github.com/skilld-labs/go-odoo/blob/master/odoo.go#L291

right now here is output of odoo ExecuteKw method when it doesn't find :

resp: []interface{}{}
err: interface{}

Unify types and Methods

I think this whole structure is pretty confusing, why not define the types in the same file as the API is defined?? Not sure, but I thought go is pretty srict on how the folder layout should be and where the files should go, and how repos should be organized, and I have the feeling this is not how it should be done...

See: https://github.com/rancher/go-rancher/blob/master/v2/generated_client.go

Btw: if I run dep init it will not recognize the repo and when I run it within the api folder it get's even stranger...

Unable to retrieve data from certain field

I can retrieve data from res.partner object with the following script:

// Package customers displays the customers page.
package customers

import (
	"fmt"
	
	"net/http"
	"adsoft/lib/flight"
	"adsoft/core/router"
	"github.com/skilld-labs/go-odoo/api"
)

func Load() {
	router.Get("/customers", Index)
}

func Index(w http.ResponseWriter, r *http.Request) {
	c := flight.Context(w, r)

	d, err := api.NewClient("http://localhost:8405", nil)
	if err != nil {
		fmt.Println(err.Error())
	}
	err = d.Login("dbname", "admin", "password")
	if err != nil {
		fmt.Println(err.Error())
	}
	//get the sale order service
	s := api.NewResPartnerService(d)
	//call the function GetAll() linked to the sale order service
	partners, err := s.GetAll()
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Println(partners)

	v := c.View.New("customers/index")
	v.Vars["partners"] = partners
	v.Render(w, r)

}
{{define "title"}}Our Customers{{end}}
{{define "head"}}{{end}}
{{define "content"}}
	<div class="page-header">
		<h1>{{template "title" .}}</h1>
	</div>
	
	{{range $n := .partners}}
		<div class="panel panel-default">
			<div class="panel-body">
				<p>Data:{{.}}</p>
			</div>
		</div>
	{{end}}

	
	
{{end}}
{{define "foot"}}{{end}}

But how could I get data from specific field?

because when i type:

...
	{{range $n := .partners}}
		<div class="panel panel-default">
			<div class="panel-body">
				<p>Data:{{.name}}</p>
			</div>
		</div>
	{{end}}
...

the following message appear:

Data:Template File Error: template: index.tmpl:11:14: executing "content" at <.name>: can't evaluate field name in type types.ResPartner

How to create partner

Hey guys,

I can create a partner with the API but I can't seem to create certain fields. Anytime there is a field with more than 1 word in it's name I can't ever get that field to be added.
For example, if I want to create a partner then I can easily assign "name" to the map and that works but if I try ParentName then no matter what case I try it never works. Here are the cases I've tried

  1. ParentName
  2. parentname
  3. parentName
  4. parent_name

Is there an example of a create with one of these fields that has more than 1 word in it? Thanks!

Here is the script I've been using (I removed my credentials... didn't see a point in including those)

package main

import (
	"fmt"

	"github.com/davecgh/go-spew/spew"
	API "github.com/skilld-labs/go-odoo/api"
	TYPES "github.com/skilld-labs/go-odoo/types"
)

func main() {
	client, err := API.NewClient("some_url", nil)
	if err != nil {
		panic(err)
	}
	err = client.Login("some_database", "some_email", "some_email")
	if err != nil {
		panic(err)
	}

	fmt.Println("Connected!")

	service := API.NewResPartnerService(client)

	var relations TYPES.Relations

	n := make(map[string]interface{})

	n["name"] = "Nick Test"
	n["ref"] = 1654847
	n["parent_name"] = "ParentName"

	id, err := service.Create(n, &relations)
	if err != nil {
		panic(err)
	}

	// Products
	//service := api.NewProductProductService(client)

	// service := api.NewProductProductService(client)

	res, err := service.GetByIds([]int64{id})
	if err != nil {
		panic(err)
	}

	spew.Dump(res)

	err = service.Delete([]int64{id})
	if err != nil {
		panic(err)
	}
}

Also, what is the point in the relations object? It doesn't seem to do anything. Thanks!

Error when try to get ir.attachment

Hello friends, I am trying to obtain the ir.attachment model that is related to the sale.order, I am already obtaining the id and name of the relationship but when obtaining all the fields of the ir.attachment by id, it fails me with the following mistake:

"reading body XML syntax error on line 88: illegal character code U+000C"

I would be very grateful if you could help me,

Thank you very much for the help

.Get() on all fields ?

Hi,

When I want to get a partner I use a function like this :

func GetPartnerByID(id int64) (model.ResPartner, error) {
	client, err := model.NewClient(&model.ClientConfig{Admin: "[email protected]", Password: "odoopassword", Database: "odoo-db", URL: "http://localhost:8069"})
	
	partner, err := client.GetResPartner(id)
	if err != nil {
		return model.ResPartner{}, err
	}

	return *partner, nil
}

But I can't figure out how to convert the returned partner object to JSON.
Normally, if I want to get the partner name, I need to use partner.name.get(), but how can I do this on all fields of the respartner struct ?
If I do a dumb jsondata, _ := json.Marshal(&partner), the content of jsondata will be only the keys without the value except for Many2One field.
Is it possible to get all fields content before converting it to JSON ?

In the following json, the name is empty, but partner.Name.Get() give me the right name.

{
   "LastUpdate":{
      
   },
   "AccountRepresentedCompanyIds":{
      
   },
   "Active":{
      
   },
   "ActiveLangCount":{
      
   },
   "ActivityCalendarEventId":null,
   "ActivityDateDeadline":null,
   "ActivityExceptionDecoration":null,
   "ActivityExceptionIcon":null,
   "ActivityIds":{
      
   },
   "ActivityState":null,
   "ActivitySummary":null,
   "ActivityTypeIcon":null,
   "ActivityTypeId":null,
   "ActivityUserId":null,
   "AdditionalInfo":null,
   "BankAccountCount":{
      
   },
   "BankIds":{
      
   },
   "Barcode":null,
   "BillingId":{
      
   },
   "BillingIds":{
      
   },
   "CalendarLastNotifAck":{
      
   },
   "CategoryId":{
      
   },
   "ChannelIds":{
      
   },
   "ChildIds":{
      
   },
   "City":{
      
   },
   "ClientRef":null,
   "Color":{
      
   },
   "Comment":{
      
   },
   "CommercialCompanyName":{
      
   },
   "CommercialId":{
      
   },
   "CommercialIds":{
      
   },
   "CommercialPartnerId":{
      "ID":6355,
      "Name":"test user"
   },
   "CompanyId":{
      "ID":87,
      "Name":"company_name"
   },
   "CompanyName":null,
   "CompanyType":{
      
   },
   "ContactAddress":{
      
   },
   "ContactAddressComplete":{
      
   },
   "ContractIds":{
      
   },
   "CountryCode":{
      
   },
   "CountryId":{
      "ID":75,
      "Name":"France"
   },
   "CreateDate":{
      
   },
   "CreateUid":{
      "ID":90,
      "Name":"test_user"
   },
   "Credit":{
      
   },
   "CreditLimit":{
      
   },
   "CurrencyId":{
      "ID":1,
      "Name":"EUR"
   },
   "CustomerRank":{
      
   },
   "Date":null,
   "Debit":{
      
   },
   "DebitLimit":{
      
   },
   "DisplayName":{
      
   },
   "DocumentCount":{
      
   },
   "Email":{
      
   },
   "EmailFormatted":{
      
   },
   "EmailNormalized":{
      
   },
   "Employee":{
      
   },
   "EmployeeIds":null,
   "EmployeesCount":null,
   "FollowupLevel":{
      "ID":15,
      "Name":"Premier rappel"
   },
   "FollowupStatus":{
      
   },
   "FournisseurRef":null,
   "Function":null,
   "HasMessage":{
      
   },
   "HasUnreconciledEntries":{
      
   },
   "Id":{
      
   },
   "ImStatus":{
      
   },
   "IndustryId":null,
   "InvoiceIds":{
      
   },
   "InvoiceWarn":{
      
   },
   "InvoiceWarnMsg":null,
   "IsBlacklisted":{
      
   },
   "IsCompany":{
      
   },
   "JournalItemCount":{
      
   },
   "Lang":{
      
   },
   "LastTimeEntriesChecked":null,
   "MeetingCount":{
      
   },
   "MeetingIds":{
      
   },
   "MessageAttachmentCount":{
      
   },
   "MessageBounce":{
      
   },
   "MessageFollowerIds":{
      
   },
   "MessageHasError":{
      
   },
   "MessageHasErrorCounter":{
      
   },
   "MessageHasSmsError":{
      
   },
   "MessageIds":{
      
   },
   "MessageIsFollower":{
      
   },
   "MessageMainAttachmentId":null,
   "MessageNeedaction":{
      
   },
   "MessageNeedactionCounter":{
      
   },
   "MessagePartnerIds":{
      
   },
   "MessageUnread":{
      
   },
   "MessageUnreadCounter":{
      
   },
   "Mobile":null,
   "MobileBlacklisted":{
      
   },
   "MyActivityDateDeadline":null,
   "Name":{
      
   },
   "OcnToken":null,
   "OnTimeRate":{
      
   },
   "OnlinePartnerInformation":null,
   "OpportunityCount":{
      
   },
   "OpportunityIds":{
      
   },
   "ParentId":null,
   "ParentName":null,
   "PartnerGid":{
      
   },
   "PartnerLatitude":{
      
   },
   "PartnerLongitude":{
      
   },
   "PartnerShare":{
      
   },
   "PaymentNextActionDate":null,
   "PaymentResponsibleId":null,
   "PaymentTokenCount":{
      
   },
   "PaymentTokenIds":{
      
   },
   "Phone":{
      
   },
   "PhoneBlacklisted":{
      
   },
   "PhoneMobileSearch":null,
   "PhoneSanitized":{
      
   },
   "PhoneSanitizedBlacklisted":{
      
   },
   "PickingWarn":{
      
   },
   "PickingWarnMsg":null,
   "PropertyAccountPayableId":{
      "ID":34407,
      "Name":"401100 Fournisseurs - Achats de biens et prestations de services"
   },
   "PropertyAccountPositionId":null,
   "PropertyAccountReceivableId":{
      "ID":34421,
      "Name":"411100 Clients - Ventes de biens ou de prestations de services"
   },
   "PropertyPaymentTermId":null,
   "PropertyProductPricelist":{
      "ID":1,
      "Name":"Public Pricelist (EUR)"
   },
   "PropertyPurchaseCurrencyId":null,
   "PropertyStockCustomer":{
      "ID":9,
      "Name":"Partner Locations/Customers"
   },
   "PropertyStockSupplier":{
      "ID":8,
      "Name":"Partner Locations/Vendors"
   },
   "PropertySupplierPaymentTermId":null,
   "PurchaseLineIds":{
      
   },
   "PurchaseOrderCount":{
      
   },
   "PurchaseWarn":{
      
   },
   "PurchaseWarnMsg":null,
   "ReceiptReminderEmail":{
      
   },
   "Ref":null,
   "RefCompanyIds":{
      
   },
   "ReminderDateBeforeReceipt":{
      
   },
   "SaleOrderCount":{
      
   },
   "SaleOrderIds":{
      
   },
   "SaleWarn":{
      
   },
   "SaleWarnMsg":null,
   "SameVatPartnerId":{
      "ID":1971,
      "Name":"my_compagny_name*"
   },
   "SddCount":{
      
   },
   "SddMandateIds":{
      
   },
   "Self":{
      "ID":6355,
      "Name":"test user next"
   },
   "SignupExpiration":null,
   "SignupToken":null,
   "SignupType":null,
   "SignupUrl":null,
   "SignupValid":{
      
   },
   "Siret":{
      
   },
   "StateId":null,
   "Street":{
      
   },
   "Street2":null,
   "SubscriptionCount":{
      
   },
   "SupplierInvoiceCount":{
      
   },
   "SupplierRank":{
      
   },
   "TeamId":null,
   "TechnicalId":{
      
   },
   "TechnicalIds":{
      
   },
   "Title":null,
   "TotalDue":{
      
   },
   "TotalInvoiced":{
      
   },
   "TotalOverdue":{
      
   },
   "Trust":{
      
   },
   "Type":{
      
   },
   "Tz":null,
   "TzOffset":{
      
   },
   "UnpaidInvoices":{
      
   },
   "UnreconciledAmlIds":{
      
   },
   "UserId":null,
   "UserIds":{
      
   },
   "Vat":{
      
   },
   "Website":null,
   "WebsiteMessageIds":{
      
   },
   "WriteDate":{
      
   },
   "WriteUid":{
      "ID":90,
      "Name":"test_user"
   },
   "XStudioContactPrincipal":null,
   "XStudioContactTechnique":{
      
   },
   "XStudioContactsAdminEtFin":{
      
   },
   "XStudioDenominationLegale":{
      
   },
   "XStudioEstUnFournisseur":{
      
   },
   "XStudioIdNext":{
      
   },
   "XStudioNombreDabonnementsActifs":{
      
   },
   "XStudioOne2ManyFieldLwVOx":{
      
   },
   "XStudioSocietesLiees":{
      
   },
   "XStudioSubscriptionCount":{
      
   },
   "XStudioThisContact":{
      
   },
   "XStudioTiquettesDuPartenaire":{
      
   },
   "XStudioTypeDeContact":null,
   "Zip":{
      
   }
}

Split out the client.go/types.go

Best practice would command to split out the client.go into it's own module, as the bindings themselves depend on the target code base, which is not always very homogeneous...

Error on update operations with datetime fields

I have generated my models for odoo v15. Create and read operations are OK, but there is a problem with update operation about datetime fields:

	id, err := c.CreateResPartner(&odoo.ResPartner{
		Name: odoo.NewString("test"),
	})
	if err != nil {
		log.Print(err)
		return
	}

	resPartner, err := c.GetResPartner(id)
	if err != nil {
		log.Print(err)
		return
	}

	resPartner.Comment = odoo.NewString("test")

	// FIXME update error
	err = c.UpdateResPartner(resPartner)
	if err != nil {
		log.Print(err)
		return
	}
2022/08/10 12:21:51 Fault(1): Traceback (most recent call last):
  File "/usr/local/odoo/odoo/addons/base/controllers/rpc.py", line 93, in xmlrpc_2
    response = self._xmlrpc(service)
  File "/usr/local/odoo/odoo/addons/base/controllers/rpc.py", line 73, in _xmlrpc
    result = dispatch_rpc(service, method, params)
  File "/usr/local/odoo/odoo/http.py", line 141, in dispatch_rpc
    result = dispatch(method, params)
  File "/usr/local/odoo/odoo/service/model.py", line 41, in dispatch
    res = fn(db, uid, *params)
  File "/usr/local/odoo/odoo/service/model.py", line 169, in execute_kw
    return execute(db, uid, obj, method, *args, **kw or {})
  File "/usr/local/odoo/odoo/service/model.py", line 94, in wrapper
    return f(dbname, *args, **kwargs)
  File "/usr/local/odoo/odoo/service/model.py", line 176, in execute
    res = execute_cr(cr, uid, obj, method, *args, **kw)
  File "/usr/local/odoo/odoo/service/model.py", line 160, in execute_cr
    result = odoo.api.call_kw(recs, method, args, kw)
  File "/usr/local/odoo/odoo/api.py", line 464, in call_kw
    result = _call_kw_multi(method, model, args, kwargs)
  File "/usr/local/odoo/odoo/api.py", line 451, in _call_kw_multi
    result = method(recs, *args, **kwargs)
  File "/usr/local/odoo/addons/base_vat/models/res_partner.py", line 616, in write
    return super(ResPartner, self).write(values)
  File "/usr/local/odoo/addons/snailmail/models/res_partner.py", line 26, in write
    return super(ResPartner, self).write(vals)
  File "/usr/local/odoo/addons/partner_autocomplete/models/res_partner.py", line 179, in write
    res = super(ResPartner, self).write(values)
  File "/usr/local/odoo/odoo/addons/base/models/res_partner.py", line 603, in write
    result = result and super(Partner, self).write(vals)
  File "/usr/local/odoo/addons/mail/models/mail_activity_mixin.py", line 243, in write
    return super(MailActivityMixin, self).write(vals)
  File "/usr/local/odoo/addons/mail/models/mail_thread.py", line 323, in write
    result = super(MailThread, self).write(values)
  File "/usr/local/odoo/odoo/models.py", line 3858, in write
    field.write(self, value)
  File "/usr/local/odoo/odoo/fields.py", line 1015, in write
    cache_value = self.convert_to_cache(value, records)
  File "/usr/local/odoo/odoo/fields.py", line 2037, in convert_to_cache
    return self.to_datetime(value)
  File "/usr/local/odoo/odoo/fields.py", line 2017, in to_datetime
    return datetime.strptime(value, DATETIME_FORMAT[:len(value)-2])
TypeError: object of type 'DateTime' has no len()

Any suggestion about this ?

Error when try to get stock.picking

Hello again, I'm a bit insistent with this library lol.

I have this error that appears when I am consulting the model stock.picking by ids and I really don't know what the problem could be, I hope you can help me too: D, I leave the error here

Fault(1): Traceback (most recent call last):\n File \"/home/odoo/src/odoo/15.0/odoo/api.py\", line 886, in get\n return field_cache[record._ids[0]]\nKeyError: 8279\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/home/odoo/src/odoo/15.0/odoo/fields.py\", line 1082, in __get__\n value = env.cache.get(record, self)\n File \"/home/odoo/src/odoo/15.0/odoo/api.py\", line 889, in get\n raise CacheMiss(record, field)\nodoo.exceptions.CacheMiss: 'stock.picking(8279,).l10n_mx_edi_content'\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/home/odoo/src/odoo/15.0/odoo/addons/base/controllers/rpc.py\", line 93, in xmlrpc_2\n response = self._xmlrpc(service)\n File \"/home/odoo/src/custom/trial/saas_trial/controllers/main.py\", line 266, in _xmlrpc\n res = super(OdooRPC, self)._xmlrpc(service)\n File \"/home/odoo/src/odoo/15.0/odoo/addons/base/controllers/rpc.py\", line 73, in _xmlrpc\n result = dispatch_rpc(service, method, params)\n File \"/home/odoo/src/odoo/15.0/odoo/http.py\", line 141, in dispatch_rpc\n result = dispatch(method, params)\n File \"/home/odoo/src/odoo/15.0/odoo/service/model.py\", line 41, in dispatch\n res = fn(db, uid, *params)\n File \"/home/odoo/src/odoo/15.0/odoo/service/model.py\", line 169, in execute_kw\n return execute(db, uid, obj, method, *args, **kw or {})\n File \"/home/odoo/src/odoo/15.0/odoo/service/model.py\", line 94, in wrapper\n return f(dbname, *args, **kwargs)\n File \"/home/odoo/src/odoo/15.0/odoo/service/model.py\", line 176, in execute\n res = execute_cr(cr, uid, obj, method, *args, **kw)\n File \"/home/odoo/src/odoo/15.0/odoo/service/model.py\", line 160, in execute_cr\n result = odoo.api.call_kw(recs, method, args, kw)\n File \"/home/odoo/src/odoo/15.0/odoo/api.py\", line 464, in call_kw\n result = _call_kw_multi(method, model, args, kwargs)\n File \"/home/odoo/src/odoo/15.0/odoo/api.py\", line 451, in _call_kw_multi\n result = method(recs, *args, **kwargs)\n File \"/home/odoo/src/odoo/15.0/odoo/models.py\", line 3229, in read\n return self._read_format(fnames=fields, load=load)\n File \"/home/odoo/src/odoo/15.0/odoo/models.py\", line 3249, in _read_format\n vals[name] = convert(record[name], record, use_name_get)\n File \"/home/odoo/src/odoo/15.0/odoo/models.py\", line 5899, in __getitem__\n return self._fields[key].__get__(self, type(self))\n File \"/home/odoo/src/odoo/15.0/odoo/fields.py\", line 1131, in __get__\n self.compute_value(recs)\n File \"/home/odoo/src/odoo/15.0/odoo/fields.py\", line 2177, in compute_value\n super().compute_value(records)\n File \"/home/odoo/src/odoo/15.0/odoo/fields.py\", line 1290, in compute_value\n records._compute_field_value(self)\n File \"/home/odoo/src/odoo/15.0/addons/mail/models/mail_thread.py\", line 411, in _compute_field_value\n return super()._compute_field_value(field)\n File \"/home/odoo/src/odoo/15.0/odoo/models.py\", line 4263, in _compute_field_value\n fields.determine(field.compute, self)\n File \"/home/odoo/src/odoo/15.0/odoo/fields.py\", line 87, in determine\n return needle(*args)\n File \"/home/odoo/src/enterprise/15.0/l10n_mx_edi_stock/models/stock_picking.py\", line 94, in _l10n_mx_edi_compute_edi_content\n picking.l10n_mx_edi_content = base64.b64encode(picking._l10n_mx_edi_create_delivery_guide())\n File \"/home/odoo/src/enterprise/15.0/l10n_mx_edi_stock/models/stock_picking.py\", line 162, in _l10n_mx_edi_create_delivery_guide\n 'cfdi_date': record.date_done.astimezone(mx_tz).strftime(date_fmt),\nAttributeError: 'bool' object has no attribute 'astimezone'\n

Use relational type (to create an an invoice)

Odoo version: 15

Hello together :)

I am trying to figure out how to use the Relational type. My goal is to create an invoice.
For this I create an "account.move". (https://github.com/skilld-labs/go-odoo/blob/master/account_move.go)
In the most basic setup, I have an partner (PartnerId) and lineIds, the latter one is of type "Relation".

My questions
-- 1 --
From the documentation

func NewRelation() *Relation {}
func (r *Relation) Get() []int64 {}

I guess I have to create a new relation and use "AddRecord", where I hand over the "account.move.line" to the expected interface.
Is this correct?

-- 2 --
From the linked Odoo-documentation (https://www.odoo.com/documentation/13.0/reference/orm.html#odoo.models.Model.write) it seems I have to refer in the Relation-object to the "account.move.line" <-> "account.move".
But how do I do this, before I created "account.move"?

-- 3 --
In the case I am totally wrong with my assumptions, could someone point me to the steps how to proceed, or give me an example?

I wish you all a great weekend!

Best regards
Sebastian

update for go1.16

This is a really great project. Thank you for this!

With go1.16 old style modules are being deprecated (to be removed completely in 1.17 according to the blog).

From the instructions, "go generate" will not work because github.com/skilld-labs/go-odoo will not exist.

The instructions should be updated to reflect that.

Great work!

Fetching recurring event gives an error due to missmatching event's ID type

When fetching recurring calendar.event instead of event's ID beeing integer we get ID as a string.
Something like this :
'id': '10842-20190730060000'

And because of it we get an error during run time:
http: panic serving [::1]:58720: reflect.Set: value of type string is not assignable to type int64

Solution:
Change Id type inside go-odoo > types from int64 to interface{} like this:

Id                       interface{} `xmlrpc:"id"`

Didn't check updating or deleting such records yet. But I guess it would not work as this methods still use int64.

How to pass keywords to ExecuteKw() ?

Hello,

For a specific action I need to pass keywords to ExecuteKw(). Is this case possible with the current code ? The XML RPC client seems to not support that or am I wrong ? If you have any advice to achieve this part, I would be thankful.

How to consult with or?

Hello friends, I am trying to make a query to sale.order and I want to filter by state, currently I am doing it as follows:

criteria.Add("state", "=", "cancel").Add("state", "=", "draft").Add("state", "=", "sent")
where criteria is a variable NewCriteria()
this seems to work as an "logical operator and" and i need to work it as "logical operator or".

Could you please help me?, thanks for the answers.

Interface conversion problem when using FindProductProduct

I encountered a conversion problem when using the FindProductProduct and FindProductProducts. FindProductProductId works fine, just these two.

Here's the method:

pp, err := c.FindProductProducts(odoo.NewCriteria().Add("active", "=", true), odoo.NewOptions().Limit(30))
if err != nil {
	log.Fatal(err)
}

Here's the log:

panic: interface conversion: interface {} is float64, not int64

goroutine 1 [running]:
github.com/skilld-labs/go-odoo.convertFromDynamicToStaticValue(0x1506a20, 0x13e8c60, 0x13c77a0, 0xc0002b3fd0, 0x13e8c60, 0x1)
        /Users/maestro/go/pkg/mod/github.com/skilld-labs/[email protected]/conversion.go:115 +0x794
github.com/skilld-labs/go-odoo.convertFromDynamicToStaticOne(0xc0002820f0, 0x1506a20, 0x145d6c0, 0x0, 0x145d6c0, 0xc000165000)
        /Users/maestro/go/pkg/mod/github.com/skilld-labs/[email protected]/conversion.go:95 +0x218
github.com/skilld-labs/go-odoo.convertFromDynamicToStaticSlice(0xc0002ec980, 0x1, 0x1, 0x1506a20, 0x13dbda0, 0x13c2300, 0xc00000ed00, 0x13c2300)
        /Users/maestro/go/pkg/mod/github.com/skilld-labs/[email protected]/conversion.go:84 +0x7c
github.com/skilld-labs/go-odoo.convertFromDynamicToStatic(0x13c2300, 0xc0002f87a0, 0x13b81a0, 0xc00000eca0, 0xf, 0xc000013d70)
        /Users/maestro/go/pkg/mod/github.com/skilld-labs/[email protected]/conversion.go:67 +0x3f4
github.com/skilld-labs/go-odoo.(*Client).SearchRead(0xc000182510, 0x14681b9, 0xf, 0xc000195800, 0xc000010560, 0x13b81a0, 0xc00000eca0, 0x13ca920, 0x143e500)
        /Users/maestro/go/pkg/mod/github.com/skilld-labs/[email protected]/odoo.go:216 +0xd8
github.com/skilld-labs/go-odoo.(*Client).FindProductProducts(0xc000182510, 0xc000195800, 0xc000010560, 0x5, 0xc000111168, 0x13ca9a0)
        /Users/maestro/go/pkg/mod/github.com/skilld-labs/[email protected]/product_product.go:203 +0x8d
main.main()
        /Users/maestro/Documents/projects/odoo-go/example.go:21 +0x257
exit status 2

Modular templates

Template are used to configure models. Currently, default template covers what I think is the most common usage.
But would be nice to provide a way to configure this template so that user can customize it.

Strange error calling SaaS API from odoo.com lately

Hi I wrote a function which was working fine until lately

	//get the sale order service
	s := api.NewResPartnerService(c)
        ...
       	so, err := s.GetAll()

It turns out that err now is not nil and get me this message from the odoo server

error: "Traceback (most recent call last):
  File "/home/odoo/src/odoo/11.0/odoo/fields.py", line 949, in __get__
    value = record.env.cache.get(record, self)
  File "/home/odoo/src/odoo/11.0/odoo/api.py", line 977, in get
    value = self._data[key][field][record._ids[0]]
KeyError: 1924

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/odoo/src/odoo/11.0/odoo/service/wsgi_server.py", line 124, in wsgi_xmlrpc
    result = odoo.http.dispatch_rpc(service, method, params)
  File "/home/odoo/src/odoo/11.0/odoo/http.py", line 118, in dispatch_rpc
    result = dispatch(method, params)
  File "/home/odoo/src/odoo/11.0/odoo/service/model.py", line 39, in dispatch
    res = fn(db, uid, *params)
  File "/home/odoo/src/odoo/11.0/odoo/service/model.py", line 172, in execute_kw
    return execute(db, uid, obj, method, *args, **kw or {})
  File "/home/odoo/src/odoo/11.0/odoo/service/model.py", line 97, in wrapper
    return f(dbname, *args, **kwargs)
  File "/home/odoo/src/odoo/11.0/odoo/service/model.py", line 179, in execute
    res = execute_cr(cr, uid, obj, method, *args, **kw)
  File "/home/odoo/src/odoo/11.0/odoo/service/model.py", line 168, in execute_cr
    return odoo.api.call_kw(recs, method, args, kw)
  File "/home/odoo/src/odoo/11.0/odoo/api.py", line 697, in call_kw
    return call_kw_model(method, model, args, kwargs)
  File "/home/odoo/src/odoo/11.0/odoo/api.py", line 682, in call_kw_model
    result = method(recs, *args, **kwargs)
  File "/home/odoo/src/odoo/11.0/odoo/models.py", line 4296, in search_read
    result = records.read(fields)
  File "/home/odoo/src/odoo/11.0/odoo/models.py", line 2627, in read
    vals[name] = convert(record[name], record, use_name_get)
  File "/home/odoo/src/odoo/11.0/odoo/models.py", line 4823, in __getitem__
    return self._fields[key].__get__(self, type(self))
  File "/home/odoo/src/odoo/11.0/odoo/fields.py", line 953, in __get__
    self.determine_value(record)
  File "/home/odoo/src/odoo/11.0/odoo/fields.py", line 1066, in determine_value
    self.compute_value(recs)
  File "/home/odoo/src/odoo/11.0/odoo/fields.py", line 1020, in compute_value
    self._compute_value(records)
  File "/home/odoo/src/odoo/11.0/odoo/fields.py", line 1011, in _compute_value
    getattr(records, self.compute)()
  File "/home/odoo/src/odoo/11.0/odoo/addons/base/res/res_partner.py", line 374, in _compute_email_formatted
    partner.email_formatted = tools.formataddr((partner.name or u"False", partner.email or u"False"))
  File "/home/odoo/src/odoo/11.0/odoo/tools/mail.py", line 556, in formataddr
    address.encode('ascii')
UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' in position 11: ordinal not in range(128)

I did not change anything, do you have any idea ?

Thank you

There is no way to close off the connection

I couldn't find any way to close off the connection and corresponding goroutine. If I need to send request with different credentials than the last time it leaves previous connection hanging and it leads to goroutine leak and in consequence memory leak.

Iโ€™m not sure if this could be solved in this package or it is problem with dependency kolo/xmlrpc (or I'm simply missing something).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.