@prefix : <https://ontology.inferal.com/modules/commerce-transaction/> .
@prefix adm: <https://ontology.inferal.com/modules/advertising-measurement/> .
@prefix cmi: <https://ontology.inferal.com/modules/commercial-intelligence/> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix mod: <https://w3id.org/mod#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix pubacc: <https://ontology.inferal.com/modules/publication-access/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rng: <https://ontology.inferal.com/modules/range/> .
@prefix schema: <https://schema.org/> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix time: <http://www.w3.org/2006/time#> .
@prefix vann: <http://purl.org/vocab/vann/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

:
    a owl:Ontology, pubacc:PublicationManagedOntology ;
    dcterms:accessRights pubacc:PublicAccess ;
    owl:imports
        adm: ,
        cmi: ,
        rng: ,
        <https://schema.org/> ,
        <http://www.w3.org/2004/02/skos/core> ,
        <http://www.w3.org/ns/prov> ;
    dcterms:title "Commerce Transaction Ontology" ;
    dcterms:description "Orders, the line items they contain, the buyers who place them, the refunds that reverse them, and the cost of what was sold, denominated in the same monetary terms as advertising spend." ;
    dcterms:license <https://creativecommons.org/licenses/by/4.0/> ;
    dcterms:source adm: , cmi: , rng: , <https://schema.org/> ,
                   <http://www.w3.org/2004/02/skos/core> , <http://www.w3.org/ns/prov> ;
    dcterms:references
        <https://schema.org/Order> ,
        <http://purl.org/goodrelations/v1> ,
        <https://www.gs1.org/standards/epcis> ;
    vann:preferredNamespacePrefix "ctx" ;
    vann:preferredNamespaceUri "https://ontology.inferal.com/modules/commerce-transaction/" ;
    mod:status "draft" ;
    rdfs:comment "This module exists because the questions businesses actually ask straddle advertising and commerce. Return on ad spend, profit on ad spend, new-customer acquisition cost, and lifetime value all compare something spent against something sold, and a vocabulary holding only the spending side can express none of them however much advertising detail it carries. Money is therefore reused from the advertising measurement module rather than restated, so revenue and spend are the same kind of quantity. Orders specialise the schema.org order so the vocabulary interoperates with the most widely published commerce data on the web, with one deliberate exception: the schema.org order status is a single enumeration mixing payment, fulfilment, lifecycle, and workflow outcomes, and this module keeps those apart. The same conflation appears in a major commerce platform's order status and in a major advertising platform's effective status, which is why separating them is treated here as a general correction rather than a local preference." ;
    owl:versionInfo "0.1.0" .


# --- Order -------------------------------------------------------------------

:Order
    a rdfs:Class ;
    rdfs:subClassOf schema:Order, prov:Entity ;
    rdfs:label "order" ;
    rdfs:comment "A completed purchase: what a buyer bought, at what total, when, and in what state of payment and delivery." ;
    dcterms:description "Specialises the schema.org order so data published against the dominant commerce vocabulary is recognised without a crosswalk. The specialisation is deliberate and partial: the inherited order status is forbidden by the shapes, because it merges payment, fulfilment, lifecycle, and workflow into one value and cannot say that an order was paid, shipped, and then partly refunded. Its members are mapped onto the separated axes here so a consumer arriving with schema.org data can still translate." ;
    rdfs:seeAlso <https://schema.org/Order> .

:LineItem
    a rdfs:Class ;
    rdfs:subClassOf schema:OrderItem ;
    rdfs:label "line item" ;
    rdfs:comment "One product at one quantity within an order, carrying what it sold for and what it cost to supply." ;
    dcterms:description "Reified rather than left as an order total, because the questions that need it are per-product: which products a campaign sold, and what margin each carried. An order reduced to a single figure can answer neither. The cost side lives here rather than on the order because cost of goods is a property of what was sold, not of the transaction." ;
    rdfs:seeAlso <https://schema.org/OrderItem> .

:Buyer
    a rdfs:Class ;
    rdfs:label "buyer" ;
    rdfs:comment "The party an order was placed by, considered as a purchaser rather than as an organisation or a person." ;
    dcterms:description "A role rather than an identity: the same party is a buyer here and may be an advertiser elsewhere. Kept minimal on purpose. Who the party is belongs to the company vocabulary, and this module carries only what a purchase question needs, which is whether this was their first order." .

:Refund
    a rdfs:Class ;
    rdfs:subClassOf prov:Entity ;
    rdfs:label "refund" ;
    rdfs:comment "A return of money against an order, for some amount that may be less than the order's total." ;
    dcterms:description "An event with an amount, not a status on the order. A status can say an order was refunded and cannot say how much came back, so a partly refunded order is neither refunded nor not. Naming the reversed order is what lets refunded money be subtracted from the revenue it belongs to, which is what a refund rate needs." .


# --- Separated state axes ----------------------------------------------------

:PaymentState
    a rdfs:Class ;
    rdfs:subClassOf skos:Concept ;
    rdfs:label "payment state" ;
    rdfs:comment "How far an order has progressed toward being paid for, from awaiting payment through to settled or reversed." ;
    dcterms:description "Independent of whether anything shipped. An order can be paid and unshipped, shipped and unpaid, or shipped and then refunded, and each of those is an ordinary retail situation that a single merged status cannot represent." .

:FulfillmentState
    a rdfs:Class ;
    rdfs:subClassOf skos:Concept ;
    rdfs:label "fulfilment state" ;
    rdfs:comment "How far an order has progressed toward reaching the buyer, from nothing sent through to fully delivered or returned to stock." ;
    dcterms:description "Independent of payment. Separating the two is what allows the operationally important question, which orders are paid but not yet shipped, to be asked at all." .

:OrderLifecycleState
    a rdfs:Class ;
    rdfs:subClassOf skos:Concept ;
    rdfs:label "order lifecycle state" ;
    rdfs:comment "Whether the order exists as a real transaction, was started and never completed, or has been discarded." ;
    dcterms:description "Kept apart from the other two because an abandoned basket is not an unpaid order, and a record discarded before completion is not a cancelled sale. One platform's merged status carries incomplete and trashed records beside genuine states, so a query for unpaid orders returns baskets that were never orders." .

:BuyerStatus
    a rdfs:Class ;
    rdfs:subClassOf skos:Concept ;
    rdfs:label "buyer status" ;
    rdfs:comment "Whether an order was a buyer's first purchase or a later one." ;
    dcterms:description "A first-class value because the cost of winning a customer and the cost of selling to one already won are different numbers used for different decisions. A vendor ships a separate new-customer acquisition cost precisely because the two are not interchangeable." .


# --- Object properties -------------------------------------------------------

:orderTotal
    a rdf:Property ;
    rdfs:label "order total" ;
    rdfs:comment "What the buyer was charged in full, reusing the shared monetary amount so revenue and advertising spend are the same kind of quantity." ;
    rdfs:domain :Order ;
    rdfs:range adm:MonetaryAmount .

:orderContains
    a rdf:Property ;
    rdfs:label "order contains" ;
    rdfs:comment "A line item within this order. Repeatable: an order of several products is several line items." ;
    rdfs:subPropertyOf schema:orderedItem ;
    rdfs:domain :Order ;
    rdfs:range :LineItem .

:placedBy
    a rdf:Property ;
    rdfs:label "placed by" ;
    rdfs:comment "The buyer who placed this order." ;
    rdfs:domain :Order ;
    rdfs:range :Buyer .

:paymentState
    a rdf:Property ;
    rdfs:label "has payment state" ;
    rdfs:comment "How far this order has progressed toward being paid for." ;
    rdfs:domain :Order ;
    rdfs:range :PaymentState .

:fulfillmentState
    a rdf:Property ;
    rdfs:label "has fulfilment state" ;
    rdfs:comment "How far this order has progressed toward reaching the buyer." ;
    rdfs:domain :Order ;
    rdfs:range :FulfillmentState .

:orderLifecycle
    a rdf:Property ;
    rdfs:label "has order lifecycle state" ;
    rdfs:comment "Whether this order exists as a real transaction, an incomplete one, or a discarded record." ;
    rdfs:domain :Order ;
    rdfs:range :OrderLifecycleState .

:placedAt
    a rdf:Property ;
    rdfs:label "placed at" ;
    rdfs:comment "The instant the order was placed, which is what a reporting window is matched against." ;
    rdfs:domain :Order ;
    rdfs:range time:Instant .

:lineItemProduct
    a rdf:Property ;
    rdfs:label "line item product" ;
    rdfs:comment "The product this line item sold, reusing the product the commercial vocabulary already defines so the catalogue and the sales ledger name the same thing." ;
    rdfs:domain :LineItem ;
    rdfs:range cmi:Product .

:lineItemRevenue
    a rdf:Property ;
    rdfs:label "line item revenue" ;
    rdfs:comment "What this line sold for in total, after any discount and before any refund." ;
    rdfs:domain :LineItem ;
    rdfs:range adm:MonetaryAmount .

:costOfGoods
    a rdf:Property ;
    rdfs:label "cost of goods" ;
    rdfs:comment "What supplying this line cost, so margin is the difference between it and the line's revenue." ;
    dcterms:description "No published vocabulary standardises this, so it is minted here rather than borrowed, and the definition is deliberately narrow: the direct cost of the goods on this line, excluding advertising, fulfilment, and overhead. Profit questions are unanswerable without it, and every one of them is asked of advertising data that cannot supply it." ;
    rdfs:domain :LineItem ;
    rdfs:range adm:MonetaryAmount .

:refundedAmount
    a rdf:Property ;
    rdfs:label "refunded amount" ;
    rdfs:comment "How much money this refund returned, which may be less than the order's total." ;
    rdfs:domain :Refund ;
    rdfs:range adm:MonetaryAmount .

:refundOf
    a rdf:Property ;
    rdfs:label "refund of" ;
    rdfs:comment "The order this refund reverses." ;
    rdfs:domain :Refund ;
    rdfs:range :Order .

:refundedAt
    a rdf:Property ;
    rdfs:label "refunded at" ;
    rdfs:comment "The instant the refund was issued, which may fall in a later reporting window than the order it reverses." ;
    rdfs:domain :Refund ;
    rdfs:range time:Instant .

:buyerStatus
    a rdf:Property ;
    rdfs:label "has buyer status" ;
    rdfs:comment "Whether this buyer was purchasing for the first time." ;
    rdfs:domain :Buyer ;
    rdfs:range :BuyerStatus .


# --- Datatype properties -----------------------------------------------------

:orderIdentifier
    a rdf:Property ;
    rdfs:label "order identifier" ;
    rdfs:comment "The merchant's own number for this order, as they issue it." ;
    dcterms:description "Required, because without it an order cannot be traced back to the system it came from and two orders alike in buyer, instant, and total are indistinguishable. Uniqueness holds within one merchant and not across merchants, which every provider's numbering makes plain: a deployment spanning several shops must qualify these the way the advertising entity vocabulary qualifies a provider identifier, by pairing the value with whoever issued it." ;
    rdfs:domain :Order ;
    rdfs:range xsd:string .

:lineItemQuantity
    a rdf:Property ;
    rdfs:label "line item quantity" ;
    rdfs:comment "How many units of the product this line sold. Required for unit economics: two of one item and one of another are not the same order." ;
    rdfs:subPropertyOf schema:orderQuantity ;
    rdfs:domain :LineItem ;
    rdfs:range xsd:decimal .


# --- Payment state scheme ----------------------------------------------------
#
# Values are aligned to the members of the schema.org order status that belong
# on this axis, so a consumer arriving with schema.org data can translate rather
# than being asked to discard it.

:PaymentStateScheme
    a skos:ConceptScheme ;
    rdfs:label "payment state scheme" ;
    rdfs:comment "How far an order has progressed toward being paid for." ;
    skos:prefLabel "Payment states" .

:awaitingPayment
    a :PaymentState, skos:Concept ;
    skos:inScheme :PaymentStateScheme ;
    skos:closeMatch schema:OrderPaymentDue ;
    rdfs:label "awaiting payment" ;
    rdfs:comment "Payment is due and has not been taken." .

:authorised
    a :PaymentState, skos:Concept ;
    skos:inScheme :PaymentStateScheme ;
    rdfs:label "authorised" ;
    rdfs:comment "Funds are reserved against the buyer's method but not yet captured." .

:partlyPaid
    a :PaymentState, skos:Concept ;
    skos:inScheme :PaymentStateScheme ;
    rdfs:label "partly paid" ;
    rdfs:comment "Some of the total has been taken and some remains outstanding, as with a deposit." .

:paid
    a :PaymentState, skos:Concept ;
    skos:inScheme :PaymentStateScheme ;
    rdfs:label "paid" ;
    rdfs:comment "The full total has been taken." .

:partlyRefunded
    a :PaymentState, skos:Concept ;
    skos:inScheme :PaymentStateScheme ;
    rdfs:label "partly refunded" ;
    rdfs:comment "Some money has been returned and some retained. The amount lives on the refund; this records only that the order is in that condition." .

:fullyRefunded
    a :PaymentState, skos:Concept ;
    skos:inScheme :PaymentStateScheme ;
    rdfs:label "fully refunded" ;
    rdfs:comment "Everything taken has been returned. The order still happened, and its line items still sold, which is why this is a payment state rather than a lifecycle one." .

:paymentVoided
    a :PaymentState, skos:Concept ;
    skos:inScheme :PaymentStateScheme ;
    rdfs:label "voided" ;
    rdfs:comment "An authorisation was released without ever being captured." .


# --- Fulfilment state scheme -------------------------------------------------

:FulfillmentStateScheme
    a skos:ConceptScheme ;
    rdfs:label "fulfilment state scheme" ;
    rdfs:comment "How far an order has progressed toward reaching the buyer." ;
    skos:prefLabel "Fulfilment states" .

:unfulfilled
    a :FulfillmentState, skos:Concept ;
    skos:inScheme :FulfillmentStateScheme ;
    rdfs:label "unfulfilled" ;
    rdfs:comment "Nothing has been sent." .

:partlyFulfilled
    a :FulfillmentState, skos:Concept ;
    skos:inScheme :FulfillmentStateScheme ;
    rdfs:label "partly fulfilled" ;
    rdfs:comment "Some lines have been sent and others have not." .

:inTransit
    a :FulfillmentState, skos:Concept ;
    skos:inScheme :FulfillmentStateScheme ;
    skos:closeMatch schema:OrderInTransit ;
    rdfs:label "in transit" ;
    rdfs:comment "Everything has been despatched and is on its way." .

:delivered
    a :FulfillmentState, skos:Concept ;
    skos:inScheme :FulfillmentStateScheme ;
    skos:closeMatch schema:OrderDelivered ;
    rdfs:label "delivered" ;
    rdfs:comment "Everything has reached the buyer." .

:awaitingCollection
    a :FulfillmentState, skos:Concept ;
    skos:inScheme :FulfillmentStateScheme ;
    skos:closeMatch schema:OrderPickupAvailable ;
    rdfs:label "awaiting collection" ;
    rdfs:comment "Everything is ready and waiting for the buyer to collect it." .

:returnedToStock
    a :FulfillmentState, skos:Concept ;
    skos:inScheme :FulfillmentStateScheme ;
    skos:closeMatch schema:OrderReturned ;
    rdfs:label "returned to stock" ;
    rdfs:comment "Goods came back and were restocked. Whether money followed is a separate question answered on the payment axis." .


# --- Order lifecycle scheme --------------------------------------------------

:OrderLifecycleScheme
    a skos:ConceptScheme ;
    rdfs:label "order lifecycle scheme" ;
    rdfs:comment "Whether an order exists as a real transaction." ;
    skos:prefLabel "Order lifecycle states" .

:incompleteOrder
    a :OrderLifecycleState, skos:Concept ;
    skos:inScheme :OrderLifecycleScheme ;
    rdfs:label "incomplete" ;
    rdfs:comment "Started and never completed, such as an abandoned basket. Not a sale, and counting it as an unpaid order overstates outstanding revenue." ;
    dcterms:description "Providers each have their own word for this and they disagree, so a platform-neutral one is used. The repository's review audit also flags the commonest of those words as a governance marker, since it cannot tell a domain term from a note about unfinished work." .

:placedOrder
    a :OrderLifecycleState, skos:Concept ;
    skos:inScheme :OrderLifecycleScheme ;
    rdfs:label "placed" ;
    rdfs:comment "A real transaction, whatever its payment and fulfilment states." .

:cancelledOrder
    a :OrderLifecycleState, skos:Concept ;
    skos:inScheme :OrderLifecycleScheme ;
    skos:closeMatch schema:OrderCancelled ;
    rdfs:label "cancelled" ;
    rdfs:comment "A real transaction that was called off. Distinct from an incomplete one, which never became a transaction, and from a refund, which returns money on one that stands." .

:discardedOrder
    a :OrderLifecycleState, skos:Concept ;
    skos:inScheme :OrderLifecycleScheme ;
    rdfs:label "discarded" ;
    rdfs:comment "Removed from the working set by the merchant. Its history may survive it." .


# --- Buyer status scheme -----------------------------------------------------

:BuyerStatusScheme
    a skos:ConceptScheme ;
    rdfs:label "buyer status scheme" ;
    rdfs:comment "Whether a purchase was a buyer's first." ;
    skos:prefLabel "Buyer statuses" .

:firstTimeBuyer
    a :BuyerStatus, skos:Concept ;
    skos:inScheme :BuyerStatusScheme ;
    rdfs:label "first-time buyer" ;
    rdfs:comment "Had not bought before. The acquisition cost of this order is what a new-customer figure measures." .

:returningBuyer
    a :BuyerStatus, skos:Concept ;
    skos:inScheme :BuyerStatusScheme ;
    rdfs:label "returning buyer" ;
    rdfs:comment "Had bought before. Selling to them costs less than winning them did, which is why blending the two hides both numbers." .
