skilld-labs / go-odoo

Golang wrapper for Odoo API
Apache License 2.0
86 stars 62 forks source link

.Get() on all fields ? #56

Closed dragonis41 closed 4 months ago

dragonis41 commented 4 months ago

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: "admin@example.com", 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":{

   }
}
ahuret commented 4 months ago

Hey there @dragonis41!

It seems like what's needed to fulfill your request is incorporating JSON management into the library. While json.Marshal can handle standard field marshaling, the challenge arises when dealing with custom types containing private content, making JSON marshaling not straightforward. However, we can address this by implementing custom marshal behavior for all the custom types in go-odoo by utilizing https://pkg.go.dev/encoding/json#Marshaler, and optionally https://pkg.go.dev/encoding/json#Unmarshaler if bidirectional conversion is necessary.

For instance, we can take the String type as an example and implement its MarshalJSON method like so:

// Get *String value.
func (s *String) MarshalJSON() ([]byte, error) {
    if s == nil {
        return nil, nil
    }
    return json.Marshal(s.v), nil
}

If there's a need to change field names, say from StateId to state_id, to respect standard json naming, we can achieve this by adding json:"state_id" tags in the model code. It would be even better to integrate this tag into the default template, ensuring its inclusion for all generated models.

I hope this explanation clarifies things. Feel free to ask any questions. Your contribution is welcome and I would be happy to help you with that ! :-)

dragonis41 commented 4 months ago

Hello ! Thanks for the explanation, I don't know why I did not think about this ^^' I was focus on the .Get() function.

Should I close this issue or leave it open for a future implementation of the un/marshaling function ?

ahuret commented 4 months ago

Closing it and feel free to contribute through a pull request !