Skip to content
75 changes: 15 additions & 60 deletions crates/ogar-class-view/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,67 +64,19 @@ use lance_graph_contract::{
ontology::{DisplayTemplate, FieldRef, ObjectView},
};
use ogar_vocab::{
Class,
accounting_account,
// 0x0CXX — automation (HIRO MARS CMDB + DO-arm actuators)
action_applicability,
action_handler,
anatomical_structure,
auth_ory_keto,
auth_store,
auth_zanzibar,
auth_zitadel,
automation_trigger,
billable_work_entry,
billing_party,
bone,
canonical_concept_id,
commercial_document,
commercial_line_item,
currency_policy,
diagnosis,
joint,
knowledge_item,
lab_value,
mars_application,
mars_machine,
mars_node_template,
mars_resource,
mars_software,
medication,
patient,
payment_record,
priority,
product,
project,
project_actor,
project_attachment,
project_changeset,
project_comment,
project_custom_field,
project_custom_value,
project_enabled_module,
project_forum,
project_journal,
project_member_role,
project_membership,
project_message,
project_news,
project_query,
project_relation,
project_repository,
project_role,
project_status,
project_type,
project_version,
project_watcher,
project_wiki_page,
project_work_item,
skeleton,
tax_policy,
treatment,
visit,
vital_sign,
action_applicability, Class,
accounting_account, action_handler, anatomical_structure, auth_ory_keto, auth_store,
auth_zanzibar, auth_zitadel, automation_trigger, billable_work_entry, billing_party, bone,
canonical_concept_id, commercial_document, commercial_line_item, currency_policy, diagnosis,
joint, knowledge_item, lab_value, mars_application, mars_machine, mars_node_template,
mars_resource, mars_software, medication, patient, payment_record, pricelist, pricelist_rule,
priority, product, project, project_actor, project_attachment, project_changeset,
project_comment, project_custom_field, project_custom_value, project_enabled_module,
project_forum, project_journal, project_member_role, project_membership, project_message,
project_news, project_query, project_relation, project_repository, project_role,
project_status, project_type, project_version, project_watcher, project_wiki_page,
project_work_item, skeleton, tax_policy, treatment, unit_of_measure, visit, vital_sign,
};

/// All promoted canonical concepts: `(canonical_concept_name, Class)`.
Expand Down Expand Up @@ -171,6 +123,9 @@ fn all_canonical_classes() -> Vec<(&'static str, Class)> {
("currency_policy", currency_policy()),
("product", product()),
("accounting_account", accounting_account()),
("pricelist", pricelist()),
("pricelist_rule", pricelist_rule()),
("unit_of_measure", unit_of_measure()),
// ── 0x09XX — health (OGIT Healthcare) ──
("patient", patient()),
("diagnosis", diagnosis()),
Expand Down
79 changes: 78 additions & 1 deletion crates/ogar-vocab/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,12 @@ const CODEBOOK: &[(&str, u16)] = &[
// PR description for the queue.
("product", 0x0207),
("accounting_account", 0x0208),
// ProductCatalog cluster — closes 3 more of the 11-gap. All stay in 0x02XX
// (no new ConceptDomain needed). HR cluster (hr.*) remains queued; needs
// a new 0x0DXX concept domain (keystone-style §7 review).
("pricelist", 0x0209),
("pricelist_rule", 0x020A),
("unit_of_measure", 0x020B),
// ── 0x09XX — Health domain (clinical / patient / care) ──
// medcare-rs Healthcare-namespace promotion (Northstar T9). The 7
// entities the OGIT `NTO/Healthcare/entities/` TTL ships, projected
Expand Down Expand Up @@ -1533,6 +1539,16 @@ pub mod class_ids {
/// SMBAccounting (0x62); this id is the OGAR-side identity that closes
/// the same axis.
pub const ACCOUNTING_ACCOUNT: u16 = 0x0208;
/// `pricelist` (`0x0209`) — price-specification base. OSB `Pricelist`,
/// Odoo `product.pricelist` (`schema:PriceSpecification`). Phase-3
/// ProductCatalog cluster.
pub const PRICELIST: u16 = 0x0209;
/// `pricelist_rule` (`0x020A`) — per-tier unit-price rule. OSB
/// `PricelistTier`, Odoo `product.pricelist.item`.
pub const PRICELIST_RULE: u16 = 0x020A;
/// `unit_of_measure` (`0x020B`) — measurement unit. OSB `UoM`, Odoo
/// `uom.uom` (`qudt:Unit`).
pub const UNIT_OF_MEASURE: u16 = 0x020B;

// ── 0x09XX — health domain (medcare-rs Healthcare namespace) ──

Expand Down Expand Up @@ -1670,6 +1686,9 @@ pub mod class_ids {
("currency_policy", CURRENCY_POLICY),
("product", PRODUCT),
("accounting_account", ACCOUNTING_ACCOUNT),
("pricelist", PRICELIST),
("pricelist_rule", PRICELIST_RULE),
("unit_of_measure", UNIT_OF_MEASURE),
// 0x09XX — health
("patient", PATIENT),
("diagnosis", DIAGNOSIS),
Expand Down Expand Up @@ -2538,6 +2557,9 @@ pub fn all_promoted_classes() -> Vec<Class> {
currency_policy(),
product(),
accounting_account(),
pricelist(),
pricelist_rule(),
unit_of_measure(),
// 0x09XX — health arm (7 OGIT Healthcare concepts), in
// class_ids::ALL order.
patient(),
Expand Down Expand Up @@ -3418,6 +3440,58 @@ pub fn accounting_account() -> Class {
c
}

/// `pricelist` (`0x0209`) — price-specification base.
pub fn pricelist() -> Class {
let mut c = Class::new("Pricelist");
c.language = Language::Unknown;
c.canonical_concept = Some("pricelist".to_string());
c.associations = Vec::new();
let mut name = Attribute::new("name");
name.type_name = Some("string".to_string());
let mut currency = Attribute::new("currency");
currency.type_name = Some("string".to_string());
let mut active = Attribute::new("active");
active.type_name = Some("bool".to_string());
c.attributes = vec![name, currency, active];
c
}

/// `pricelist_rule` (`0x020A`) — per-tier unit-price rule.
pub fn pricelist_rule() -> Class {
let mut c = Class::new("PricelistRule");
c.language = Language::Unknown;
c.canonical_concept = Some("pricelist_rule".to_string());
c.associations = Vec::new();
let mut price = Attribute::new("price");
price.type_name = Some("decimal".to_string());
let mut min_quantity = Attribute::new("min_quantity");
min_quantity.type_name = Some("decimal".to_string());
let mut max_quantity = Attribute::new("max_quantity");
max_quantity.type_name = Some("decimal".to_string());
let mut pricelist_ref = Attribute::new("pricelist_ref");
pricelist_ref.type_name = Some("string".to_string());
c.attributes = vec![price, min_quantity, max_quantity, pricelist_ref];
c
}

/// `unit_of_measure` (`0x020B`) — measurement unit.
pub fn unit_of_measure() -> Class {
let mut c = Class::new("UnitOfMeasure");
c.language = Language::Unknown;
c.canonical_concept = Some("unit_of_measure".to_string());
c.associations = Vec::new();
let mut name = Attribute::new("name");
name.type_name = Some("string".to_string());
let mut symbol = Attribute::new("symbol");
symbol.type_name = Some("string".to_string());
let mut factor = Attribute::new("factor");
factor.type_name = Some("decimal".to_string());
let mut uom_type = Attribute::new("uom_type");
uom_type.type_name = Some("string".to_string());
c.attributes = vec![name, symbol, factor, uom_type];
c
}

// ─────────────────────────────────────────────────────────────────────
// 0x09XX — Health domain (OGIT Healthcare). The reusable Active-Record
// shape for the clinical concepts. `diagnosis` (0x0902) is the worked
Expand Down Expand Up @@ -4488,6 +4562,9 @@ mod tests {
"currency_policy",
"product",
"accounting_account",
"pricelist",
"pricelist_rule",
"unit_of_measure",
] {
let id = canonical_concept_id(commerce_concept)
.unwrap_or_else(|| panic!("{commerce_concept} missing from codebook"));
Expand Down Expand Up @@ -4633,7 +4710,7 @@ mod tests {
}
// Counts line up with the codebook blocks.
assert_eq!(concepts_in_domain(ConceptDomain::Health).count(), 7);
assert_eq!(concepts_in_domain(ConceptDomain::Commerce).count(), 8);
assert_eq!(concepts_in_domain(ConceptDomain::Commerce).count(), 11);
assert_eq!(concepts_in_domain(ConceptDomain::ProjectMgmt).count(), 26);
assert_eq!(concepts_in_domain(ConceptDomain::Anatomy).count(), 4);
assert_eq!(concepts_in_domain(ConceptDomain::Auth).count(), 4);
Expand Down
9 changes: 7 additions & 2 deletions crates/ogar-vocab/src/ports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,11 @@ pub const ODOO_ALIASES: &[(&str, u16)] = &[
// same `accounting_account` id. Phase-3 mint per odoo-rs PR #14 + #16.
("account.account", class_ids::ACCOUNTING_ACCOUNT),
("account.account.template", class_ids::ACCOUNTING_ACCOUNT),
// ProductCatalog cluster — pricing structure + UoM, Phase-3 per
// odoo-rs PR #14.
("product.pricelist", class_ids::PRICELIST),
("product.pricelist.item", class_ids::PRICELIST_RULE),
("uom.uom", class_ids::UNIT_OF_MEASURE),
// Cross-arm bridge: the timesheet / cost line converges on the
// project-arm `billable_work_entry` (0x0103) — the SAME id
// OpenProject `TimeEntry` and Redmine `TimeEntry` resolve to.
Expand Down Expand Up @@ -1000,13 +1005,13 @@ mod tests {
// 9 Odoo model aliases = 8 commerce-arm (account.move,
// sale.order, account.move.line, sale.order.line, account.tax,
// res.partner, account.payment, res.currency) + 4 product/accounting
// master-record aliases (product.template, product.product,
// master-record aliases + 3 ProductCatalog cluster aliases (product.template, product.product,
// account.account, account.account.template — Phase-3 mints per
// odoo-rs PR #14 + #16) + 1 cross-arm bridge
// (account.analytic.line → billable_work_entry). Re-count on drift.
assert_eq!(
OdooPort::aliases().len(),
13,
16,
"Odoo alias count drift — re-count the ODOO_ALIASES table",
);
}
Expand Down
Loading