Opportunity Intake (O2C / pipeline capture)
A vertical intake accelerator that lands opportunity / qualified-lead extracts from a marketing
automation or CRM platform and writes them to the LatticeOpportunity OData entity.
This is the catalog's exemplar for the odataEntity target style. The other bundles
(vendor-invoice-intake, sales-order-intake, asn-product-receipt-intake,
customer-payment-intake) use customService; this is the only bundle for the odataEntity style
that schema/bundle.schema.json defines and Authoring, section 4a documents.
Flow
Blob drop (OPPTY_*.csv)
-> File Ingestion connection (StorageType=Blob, FileFormat=Csv, CsvHasHeader=Yes)
-> one segment per data row
-> Liquid transform (transform.liquid, rendered ONCE PER SEGMENT) -> LatticeOpportunity record
-> POST /data/LatticeOpportunities <-- by an EXTERNAL client, see "Dispatch gap"
Target (verified against the AOT)
| Element | Value |
|---|---|
| AOT entity | MGCLatticeOpportunityEntity |
| Public entity name | LatticeOpportunity |
| Public collection | LatticeOpportunities |
| Entity category | Transaction |
| Primary key | EntityKey over OpportunityId |
| Company context | PrimaryCompanyContext = DataAreaId |
IsReadOnly | No (writable) |
SubscriberAccessLevel | Read only |
Field names and types come from the entity and its DMF staging table
(MGCLatticeOpportunityStaging), which mirrors the entity's field types exactly:
| Entity field | EDT / type | Mapped? |
|---|---|---|
dataAreaId | company (PrimaryCompanyContext) | yes - from the dataAreaId activation parameter |
OpportunityId | smmOpportunityId | yes (key) |
Subject | smmOpportunitySubject | yes |
SalesProcessName | smmOpportunitySalesProcess (table field ProcessName) | yes |
ProbabilityId | smmQuotationProbabilityId | yes |
EstimatedRevenue | smmOpportunityEstimatedRevenue | yes |
OpenedDate | smmOpportunityOpenedDate | yes |
PrognosisId | smmQuotationPrognosisId | yes |
SalesUnitId | smmSalesUnitId | yes - a blank column falls back to defaultSalesUnitId |
ClosedDate | smmOpportunityClosedDate | yes |
PartyNumber | DirPartyNumber (resolved to the party record) | yes |
OwnerPersonnelNumber | HcmPersonnelNumberId (resolved to the worker record) | yes |
Status | enum smmOpportunityStatus, AllowEdit = No | no - not settable |
Dispatch gap
The file-ingestion pipeline cannot deliver to an OData entity today.
MGCLatticeFileIngestDispatcherFactory::constructalways returnsMGCLatticeFileIngestCustomServiceDispatcher.- The only class implementing
MGCLatticeIFileIngestServiceTargetisMGCLatticeFileIngestServiceInvokeTarget, which invokes Lattice service operations - not entity writes.
So an odataEntity bundle is currently a design-time contract (entity identity, field mapping,
payload shape) that an external OData client fulfils; it is not executable through the pipeline the
way a customService bundle is. Closing this gap needs a change to the Lattice model; it is
tracked in productDecisions.
Write-access gap - model-wide, not bundle-specific
MGCLatticeOpportunityEntity grants SubscriberAccessLevel = Read only, so an integration
subscriber cannot create rows until that grant is widened. This is not specific to this
bundle: no entity in the Lattice model grants subscriber Create or Update. Every odataEntity bundle therefore inherits a
"widen the grant" provisioning step, and because that is a metadata change it cannot be done at
deploy time by a customer. Hence the required entityWriteAccessGranted activation parameter.
Other gaps
- Company scoping.
PrimaryCompanyContext = DataAreaIdmeans writes are company-scoped; a record withoutdataAreaIdlands in the OData client's default company. The transform therefore writesdataAreaIdinto every record from thedataAreaIdactivation parameter. - No request id. Unlike the
customServicebundles, an entity write carries noRequestIdand gets no run context: the record is identified by its key,OpportunityId.
Files
manifest.json- bundle manifest (conforms toschema/bundle.schema.json).sample.csv- three opportunities, including two deliberately unmapped columns.mapping.json- column -> entity-field mapping (targetKind: odataEntity, record-levellines).transform.liquid- Liquid template producing a single-element entity-record array.
Status
draft, not preview - deliberately. The target entity is real and every mapped field is verified,
but unlike the customService bundles this one has no executable delivery path in the pipeline
today. It earns preview once an OData dispatcher exists, and released once subscriber write
access and natural-key party resolution are settled.