Closed xewl closed 2 years ago
Hi @xewl,
i'm sorry the Readme was kinda outdated...
The Readme is updated now and includes some examples.
The command for publishing the config is:
php artisan vendor:publish --provider="Obuchmann\OdooJsonRpc\OdooServiceProvider" --tag="config"
I used Ripcord/xmlrpc for many years and it was that pain that made me create this library ;)
Feel free to report issues you have with this library.
I'm actually trying to Identify models, by calling ir.model
, ir.model.fields
etc.
It would be nice to be able to generate those skeletons somehow, though there are some differences between versions. (eg image_medium vs image_1024 on product.product
)
Not sure how you're handling these, but some guidance would definitely help. (I see your examples for Models of course)
On v15, I'm getting an issue with a count that's being called where relation account_aged_payable
doesn't seem to exist. If I don't ask for the field 'count', it doesn't hit this. Not sure on which level this problem exists, atm. Like, I don't even know where I'm hitting this relationship at this moment, as I just call ir.model
to show all of it :')
-- When/why do you exactly do , Key
?
Given the Eloquent feel, I'm missing a Paginator, but that's easy enough to circumvent for now.
Edit: As an example, I'm currently able to generate these, but in any case it's a wip:
#[Model('sale.order')]
class SaleOrder extends OdooModel
{
/**
* Security Token
* Odoo modules: sale
*/
#[Field('access_token')]
public ?string $accessToken
/**
* Portal Access URL
* Customer Portal URL
* Odoo modules: sale
* @readonly
*/
#[Field('access_url')]
private ?string $accessUrl
/**
* Access warning
* Odoo modules: sale
* @readonly
*/
#[Field('access_warning')]
private ?string $accessWarning
/**
* Next Activity Calendar Event
* Odoo modules: sale
* @readonly
*/
#[BelongsTo(CalendarEvent::class, 'activity_calendar_event_id')]
private ?CalendarEvent $activityCalendarEventId
/**
* Next Activity Deadline
* Odoo modules: sale
* @readonly
*/
#[Field('activity_date_deadline')]
private ?Date $activityDateDeadline
/**
* Activity Exception Decoration
* Type of the exception activity on record.
* Odoo modules: sale
* @enum [('warning', 'Alert'), ('danger', 'Error')]
* @readonly
*/
#[Field('activity_exception_decoration')]
private ?Enum $activityExceptionDecoration
/**
* Icon
* Icon to indicate an exception activity.
* Odoo modules: sale
* @readonly
*/
#[Field('activity_exception_icon')]
private ?string $activityExceptionIcon
/**
* Activities
* Odoo modules: sale
*/
#[HasMany(MailActivity::class, 'activity_ids')]
public ?array $activityIds
/**
* Activity State
* Status based on activities
Overdue: Due date is already passed
Today: Activity date is today
Planned: Future activities.
* Odoo modules: sale
* @enum [('overdue', 'Overdue'), ('today', 'Today'), ('planned', 'Planned')]
* @readonly
*/
#[Field('activity_state')]
private ?Enum $activityState
/**
* Next Activity Summary
* Odoo modules: sale
*/
#[Field('activity_summary')]
private ?string $activitySummary
/**
* Activity Type Icon
* Font awesome icon e.g. fa-tasks
* Odoo modules: sale
* @readonly
*/
#[Field('activity_type_icon')]
private ?string $activityTypeIcon
/**
* Next Activity Type
* Odoo modules: sale
*/
#[BelongsTo(MailActivityType::class, 'activity_type_id')]
private ?MailActivityType $activityTypeId
/**
* Responsible User
* Odoo modules: sale
*/
#[BelongsTo(ResUsers::class, 'activity_user_id')]
private ?ResUsers $activityUserId
/**
* Delivery Amount
* The amount without tax.
* Odoo modules: website_sale_delivery
* @readonly
*/
#[Field('amount_delivery')]
public ?double $amountDelivery
/**
* Taxes
* Odoo modules: sale
* @readonly
*/
#[Field('amount_tax')]
public ?double $amountTax
/**
* Total
* Odoo modules: sale
* @readonly
*/
#[Field('amount_total')]
public ?double $amountTotal
/**
* Amount Before Discount
* Odoo modules: sale
* @readonly
*/
#[Field('amount_undiscounted')]
private ?float $amountUndiscounted
/**
* Untaxed Amount
* Odoo modules: sale
* @readonly
*/
#[Field('amount_untaxed')]
public ?double $amountUntaxed
/**
* Analytic Account
* The analytic account related to a sales order.
* Odoo modules: sale
* @readonly
*/
#[BelongsTo(AccountAnalyticAccount::class, 'analytic_account_id')]
public ?AccountAnalyticAccount $analyticAccountId
/**
* Attendee Count
* Odoo modules: event_sale
* @readonly
*/
#[Field('attendee_count')]
private ?int $attendeeCount
/**
* Authorized Transactions
* Odoo modules: sale
* @readonly
*/
#[Field('authorized_transaction_ids')]
private ?array[PaymentTransaction] $authorizedTransactionIds
/**
* Campaign
* This is a name that helps you keep track of your different campaign efforts, e.g. Fall_Drive, Christmas_Special
* Odoo modules: sale
*/
#[BelongsTo(UtmCampaign::class, 'campaign_id')]
public ?UtmCampaign $campaignId
/**
* Delivery Method
* Fill this field if you plan to invoice the shipping based on picking.
* Odoo modules: delivery
*/
#[BelongsTo(DeliveryCarrier::class, 'carrier_id')]
public ?DeliveryCarrier $carrierId
/**
* Cart Quantity
* Odoo modules: website_sale
* @readonly
*/
#[Field('cart_quantity')]
private ?int $cartQuantity
/**
* Cart recovery email already sent
* Odoo modules: website_sale
*/
#[Field('cart_recovery_email_sent')]
public ?bool $cartRecoveryEmailSent
/**
* Customer Reference
* Odoo modules: sale
*/
#[Field('client_order_ref')]
public ?string $clientOrderRef
/**
* Delivery Date
* This is the delivery date promised to the customer. If set, the delivery order will be scheduled based on this date rather than product lead times.
* Odoo modules: sale
*/
#[Field('commitment_date')]
public ?DateTime $commitmentDate
/**
* Company
* Odoo modules: sale
*/
#[BelongsTo(ResCompany::class, 'company_id')]
public ResCompany $companyId
/**
* Creation Date
* Date on which sales order is created.
* Odoo modules: sale
* @readonly
*/
#[Field('create_date')]
public ?DateTime $createDate
/**
* Created by
* Odoo modules: sale
* @readonly
*/
#[BelongsTo(ResUsers::class, 'create_uid')]
public ?ResUsers $createUid
/**
* Currency
* Odoo modules: sale
* @readonly
*/
#[BelongsTo(ResCurrency::class, 'currency_id')]
public ?ResCurrency $currencyId
/**
* Currency Rate
* The rate of the currency to the currency of rate 1 applicable at the date of the order
* Odoo modules: sale
* @readonly
*/
#[Field('currency_rate')]
public ?float $currencyRate
/**
* Order Date
* Creation date of draft/sent orders,
Confirmation date of confirmed orders.
* Odoo modules: sale
* @readonly
*/
#[Field('date_order')]
public DateTime $dateOrder
/**
* Delivery Orders
* Odoo modules: sale_stock
* @readonly
*/
#[Field('delivery_count')]
private ?int $deliveryCount
/**
* Delivery Message
* Odoo modules: delivery
* @readonly
*/
#[Field('delivery_message')]
public ?string $deliveryMessage
/**
* Delivery Rating Success
* Odoo modules: delivery
*/
#[Field('delivery_rating_success')]
public ?bool $deliveryRatingSuccess
/**
* Delivery Set
* Odoo modules: delivery
* @readonly
*/
#[Field('delivery_set')]
private ?bool $deliverySet
/**
* Display Name
* Odoo modules: sale
* @readonly
*/
#[Field('display_name')]
private ?string $displayName
/**
* Effective Date
* Completion date of the first delivery order.
* Odoo modules: sale_stock
* @readonly
*/
#[Field('effective_date')]
public ?DateTime $effectiveDate
/**
* Expected Date
* Delivery date you can promise to the customer, computed from the minimum lead time of the order lines in case of Service products. In case of shipping, the shipping policy of the order will be taken into account to either use the minimum or maximum lead time of the order lines.
* Odoo modules: sale, sale_stock
* @readonly
*/
#[Field('expected_date')]
private ?DateTime $expectedDate
/**
* Fiscal Position
* Fiscal positions are used to adapt taxes and accounts for particular customers or sales orders/invoices.The default value comes from the customer.
* Odoo modules: sale
*/
#[BelongsTo(AccountFiscalPosition::class, 'fiscal_position_id')]
public ?AccountFiscalPosition $fiscalPositionId
/**
* Has Message
* Odoo modules: sale
* @readonly
*/
#[Field('has_message')]
private ?bool $hasMessage
/**
* ID
* Odoo modules: sale
* @readonly
*/
#[Field('id')]
public ?int $id
/**
* Incoterm
* International Commercial Terms are a series of predefined commercial terms used in international transactions.
* Odoo modules: sale_stock
*/
#[BelongsTo(AccountIncoterms::class, 'incoterm')]
public ?AccountIncoterms $incoterm
/**
* Invoice Count
* Odoo modules: sale
* @readonly
*/
#[Field('invoice_count')]
private ?int $invoiceCount
/**
* Invoices
* Odoo modules: sale
* @readonly
*/
#[Field('invoice_ids')]
private ?array[AccountMove] $invoiceIds
/**
* Invoice Status
* Odoo modules: sale
* @enum [('upselling', 'Upselling Opportunity'), ('invoiced', 'Fully Invoiced'), ('to invoice', 'To Invoice'), ('no', 'Nothing to Invoice')]
* @readonly
*/
#[Field('invoice_status')]
public ?Enum $invoiceStatus
/**
* Abandoned Cart
* Odoo modules: website_sale
* @readonly
*/
#[Field('is_abandoned_cart')]
private ?bool $isAbandonedCart
/**
* Service Product
* Odoo modules: delivery
* @readonly
*/
#[Field('is_all_service')]
private ?bool $isAllService
/**
* Is expired
* Odoo modules: sale
* @readonly
*/
#[Field('is_expired')]
private ?bool $isExpired
/**
* JSON data for the popover widget
* Odoo modules: sale_stock
* @readonly
*/
#[Field('json_popover')]
private ?string $jsonPopover
/**
* Medium
* This is the method of delivery, e.g. Postcard, Email, or Banner Ad
* Odoo modules: sale
*/
#[BelongsTo(UtmMedium::class, 'medium_id')]
public ?UtmMedium $mediumId
/**
* Attachment Count
* Odoo modules: sale
* @readonly
*/
#[Field('message_attachment_count')]
private ?int $messageAttachmentCount
/**
* Followers
* Odoo modules: sale
*/
#[HasMany(MailFollowers::class, 'message_follower_ids')]
public ?array $messageFollowerIds
/**
* Message Delivery error
* If checked, some messages have a delivery error.
* Odoo modules: sale
* @readonly
*/
#[Field('message_has_error')]
private ?bool $messageHasError
/**
* Number of errors
* Number of messages with delivery error
* Odoo modules: sale
* @readonly
*/
#[Field('message_has_error_counter')]
private ?int $messageHasErrorCounter
/**
* SMS Delivery error
* If checked, some messages have a delivery error.
* Odoo modules: sale
* @readonly
*/
#[Field('message_has_sms_error')]
private ?bool $messageHasSmsError
/**
* Messages
* Odoo modules: sale
*/
#[HasMany(MailMessage::class, 'message_ids')]
public ?array $messageIds
/**
* Is Follower
* Odoo modules: sale
* @readonly
*/
#[Field('message_is_follower')]
private ?bool $messageIsFollower
/**
* Main Attachment
* Odoo modules: sale
*/
#[BelongsTo(IrAttachment::class, 'message_main_attachment_id')]
public ?IrAttachment $messageMainAttachmentId
/**
* Action Needed
* If checked, new messages require your attention.
* Odoo modules: sale
* @readonly
*/
#[Field('message_needaction')]
private ?bool $messageNeedaction
/**
* Number of Actions
* Number of messages which requires an action
* Odoo modules: sale
* @readonly
*/
#[Field('message_needaction_counter')]
private ?int $messageNeedactionCounter
/**
* Followers (Partners)
* Odoo modules: sale
* @readonly
*/
#[Field('message_partner_ids')]
private ?array[ResPartner] $messagePartnerIds
/**
* Unread Messages
* If checked, new messages require your attention.
* Odoo modules: sale
* @readonly
*/
#[Field('message_unread')]
private ?bool $messageUnread
/**
* Unread Messages Counter
* Number of unread messages
* Odoo modules: sale
* @readonly
*/
#[Field('message_unread_counter')]
private ?int $messageUnreadCounter
/**
* My Activity Deadline
* Odoo modules: sale
* @readonly
*/
#[Field('my_activity_date_deadline')]
private ?Date $myActivityDateDeadline
/**
* Order Reference
* Odoo modules: sale
* @readonly
*/
#[Field('name')]
public string $name
/**
* Terms and conditions
* Odoo modules: sale
*/
#[Field('note')]
public ?string $note
/**
* Only Services
* Odoo modules: website_sale
* @readonly
*/
#[Field('only_services')]
private ?bool $onlyServices
/**
* Order Lines
* Odoo modules: sale
*/
#[HasMany(SaleOrderLine::class, 'order_line')]
public ?array $orderLine
/**
* Source Document
* Reference of the document that generated this sales order request.
* Odoo modules: sale
*/
#[Field('origin')]
public ?string $origin
/**
* Customer
* Odoo modules: sale
* @readonly
*/
#[BelongsTo(ResPartner::class, 'partner_id')]
public ResPartner $partnerId
/**
* Invoice Address
* Odoo modules: sale
* @readonly
*/
#[BelongsTo(ResPartner::class, 'partner_invoice_id')]
public ResPartner $partnerInvoiceId
/**
* Delivery Address
* Odoo modules: sale
* @readonly
*/
#[BelongsTo(ResPartner::class, 'partner_shipping_id')]
public ResPartner $partnerShippingId
/**
* Payment Terms
* Odoo modules: sale
*/
#[BelongsTo(AccountPaymentTerm::class, 'payment_term_id')]
public ?AccountPaymentTerm $paymentTermId
/**
* Transfers
* Odoo modules: sale_stock
*/
#[HasMany(StockPicking::class, 'picking_ids')]
public ?array $pickingIds
/**
* Shipping Policy
* If you deliver all products at once, the delivery order will be scheduled based on the greatest product lead time. Otherwise, it will be based on the shortest.
* Odoo modules: sale_stock
* @enum [('direct', 'As soon as possible'), ('one', 'When all products are ready')]
* @readonly
*/
#[Field('picking_policy')]
public Enum $pickingPolicy
/**
* Pos Order Count
* Odoo modules: pos_sale
* @readonly
*/
#[Field('pos_order_count')]
private ?int $posOrderCount
/**
* Order lines Transfered to Point of Sale
* Odoo modules: pos_sale
* @readonly
*/
#[HasMany(PosOrderLine::class, 'pos_order_line_ids')]
public ?array $posOrderLineIds
/**
* Pricelist
* If you change the pricelist, only newly added lines will be affected.
* Odoo modules: sale
* @readonly
*/
#[BelongsTo(ProductPricelist::class, 'pricelist_id')]
public ProductPricelist $pricelistId
/**
* Procurement Group
* Odoo modules: sale_stock
*/
#[BelongsTo(ProcurementGroup::class, 'procurement_group_id')]
public ?ProcurementGroup $procurementGroupId
/**
* Number of Purchase Order Generated
* Odoo modules: sale_purchase
* @readonly
*/
#[Field('purchase_order_count')]
private ?int $purchaseOrderCount
/**
* Delivery cost should be recomputed
* Odoo modules: delivery
*/
#[Field('recompute_delivery_price')]
public ?bool $recomputeDeliveryPrice
/**
* Payment Ref.
* The payment communication of this sale order.
* Odoo modules: sale
*/
#[Field('reference')]
public ?string $reference
/**
* Online Payment
* Request an online payment to the customer in order to confirm orders automatically.
* Odoo modules: sale
* @readonly
*/
#[Field('require_payment')]
public ?bool $requirePayment
/**
* Online Signature
* Request a online signature to the customer in order to confirm orders automatically.
* Odoo modules: sale
* @readonly
*/
#[Field('require_signature')]
public ?bool $requireSignature
/**
* Optional Products Lines
* Odoo modules: sale_management
* @readonly
*/
#[HasMany(SaleOrderOption::class, 'sale_order_option_ids')]
public ?array $saleOrderOptionIds
/**
* Quotation Template
* Odoo modules: sale_management
* @readonly
*/
#[BelongsTo(SaleOrderTemplate::class, 'sale_order_template_id')]
public ?SaleOrderTemplate $saleOrderTemplateId
/**
* Has late picking
* Odoo modules: sale_stock
* @readonly
*/
#[Field('show_json_popover')]
private ?bool $showJsonPopover
/**
* Has Pricelist Changed
* Technical Field, True if the pricelist was changed;
this will then display a recomputation button
* Odoo modules: sale
*/
#[Field('show_update_pricelist')]
public ?bool $showUpdatePricelist
/**
* Signature
* Signature received through the portal.
* Odoo modules: sale
*/
#[Field('signature')]
public ?binary $signature
/**
* Signed By
* Name of the person that signed the SO.
* Odoo modules: sale
*/
#[Field('signed_by')]
public ?string $signedBy
/**
* Signed On
* Date of the signature.
* Odoo modules: sale
*/
#[Field('signed_on')]
public ?DateTime $signedOn
/**
* Source
* This is the source of the link, e.g. Search Engine, another domain, or name of email list
* Odoo modules: sale
*/
#[BelongsTo(UtmSource::class, 'source_id')]
public ?UtmSource $sourceId
/**
* Status
* Odoo modules: sale
* @enum [('draft', 'Quotation'), ('sent', 'Quotation Sent'), ('sale', 'Sales Order'), ('done', 'Locked'), ('cancel', 'Cancelled')]
* @readonly
*/
#[Field('state')]
public ?Enum $state
/**
* Tags
* Odoo modules: sale
*/
#[Field('tag_ids')]
public ?array[CrmTag] $tagIds
/**
* Tax Country
* Technical field to filter the available taxes depending on the fiscal country and fiscal position.
* Odoo modules: sale
* @readonly
*/
#[BelongsTo(ResCountry::class, 'tax_country_id')]
private ?ResCountry $taxCountryId
/**
* Tax Totals Json
* Odoo modules: sale
* @readonly
*/
#[Field('tax_totals_json')]
private ?string $taxTotalsJson
/**
* Sales Team
* Odoo modules: sale
*/
#[BelongsTo(CrmTeam::class, 'team_id')]
public ?CrmTeam $teamId
/**
* Terms & Conditions format
* Odoo modules: sale
* @enum []
* @readonly
*/
#[Field('terms_type')]
private ?Enum $termsType
/**
* Transactions
* Odoo modules: sale
* @readonly
*/
#[Field('transaction_ids')]
public ?array[PaymentTransaction] $transactionIds
/**
* Type Name
* Odoo modules: sale
* @readonly
*/
#[Field('type_name')]
private ?string $typeName
/**
* Salesperson
* Odoo modules: sale
*/
#[BelongsTo(ResUsers::class, 'user_id')]
public ?ResUsers $userId
/**
* Expiration
* Odoo modules: sale
* @readonly
*/
#[Field('validity_date')]
public ?Date $validityDate
/**
* Warehouse
* Odoo modules: sale_stock
* @readonly
*/
#[BelongsTo(StockWarehouse::class, 'warehouse_id')]
public StockWarehouse $warehouseId
/**
* Warning
* Odoo modules: website_sale_stock
*/
#[Field('warning_stock')]
public ?string $warningStock
/**
* Website
* Website through which this order was placed.
* Odoo modules: website_sale
* @readonly
*/
#[BelongsTo(Website::class, 'website_id')]
public ?Website $websiteId
/**
* Website Messages
* Website communication history
* Odoo modules: sale
*/
#[HasMany(MailMessage::class, 'website_message_ids')]
public ?array $websiteMessageIds
/**
* Order Lines displayed on Website
* Order Lines to be displayed on the website. They should not be used for computation purpose.
* Odoo modules: website_sale
* @readonly
*/
#[HasMany(SaleOrderLine::class, 'website_order_line')]
private ?array $websiteOrderLine
/**
* Last Updated on
* Odoo modules: sale
* @readonly
*/
#[Field('write_date')]
public ?DateTime $writeDate
/**
* Last Updated by
* Odoo modules: sale
* @readonly
*/
#[BelongsTo(ResUsers::class, 'write_uid')]
public ?ResUsers $writeUid
}
If you plan to support multiple Odoo version it might be better to not rely on the Model interface but to use the Odoo api directly via the $odoo->model('sale.order'). See https://github.com/obuchmann/odoo-jsonrpc/blob/main/tests/OdooTest.php for examples. Per default it returns all model fields and can be limited by calling ->fields(['name', 'display_name']) etc.
You can ask for the current odoo version via $odoo->version();
The Key attribute indicates that this is a Foreign relation property. When reading from Odoo the api returns an array with [id, name] for this relations. With the Key attribute only the id is stored and the name property is skipped.
Pagination would indeed be a nice feature. You may create a new issue for that.
I'm going just for v15 for now. Problem is that in the other versions, the keys are also different when using the direct call approach, so the Model approach can be nicer in the end as I can create a new set of models for that version and have something else grab the correct set of Models / fields based on the version of the connection. (v12 image_medium, v15 image_1024 etc) and create an accessor for it.
Thanks for the explanation of Key, I see clearly now :)
My way to go for this would be to have a Model Class for each Version and to use laravel service container to inject the model depending on the used version. https://laravel.com/docs/8.x/container
You can use the static model Methods SaleOrder::where(.... also from an injected Instance of this Model.
Wonderful respose @obuchmann
Sidenote: This library might actually hit off, because the Ripcord/xmlrpc way is quite painful.