@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 rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix schema: <https://schema.org/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

:OrderShape
    a sh:NodeShape ;
    rdfs:label "order shape" ;
    rdfs:comment "An order states who placed it and when, which together identify it, and answers the three state questions separately. The inherited schema.org order status is forbidden: it merges those questions into one value, and admitting it alongside the separated axes would let a producer state a contradiction and a consumer read whichever it found first." ;
    sh:targetClass :Order ;
    sh:property [
        sh:path :orderIdentifier ;
        sh:name "order identifier" ;
        sh:description "Required and non-empty: an order that cannot be traced back to its source cannot be reconciled against it." ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:datatype xsd:string ;
        sh:minLength 1 ;
    ] ;
    sh:property [
        sh:path :placedBy ;
        sh:name "placed by" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :Buyer ;
    ] ;
    sh:property [
        sh:path :placedAt ;
        sh:name "placed at" ;
        sh:description "Required: an order with no instant cannot be matched against a reporting window, so it can never be compared with the advertising that produced it." ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:nodeKind sh:IRI ;
    ] ;
    sh:property [
        sh:path :orderTotal ;
        sh:name "order total" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class adm:MonetaryAmount ;
    ] ;
    sh:property [
        sh:path :paymentState ;
        sh:name "payment state" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :PaymentState ;
    ] ;
    sh:property [
        sh:path :fulfillmentState ;
        sh:name "fulfilment state" ;
        sh:description "Separate from payment and equally required: paid but not yet shipped is the commonest state in retail and the one a merged status cannot express." ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :FulfillmentState ;
    ] ;
    sh:property [
        sh:path :orderLifecycle ;
        sh:name "order lifecycle state" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :OrderLifecycleState ;
    ] ;
    sh:property [
        sh:path :orderContains ;
        sh:name "order contains" ;
        sh:description "Repeatable and optional. Absent where a source publishes totals without contents, which is a real limitation of that source rather than an order with nothing in it." ;
        sh:class :LineItem ;
    ] ;
    sh:property [
        sh:path schema:orderStatus ;
        sh:name "schema.org order status" ;
        sh:description "Forbidden. Its enumeration mixes payment due, in transit, delivered, cancelled, and returned in one list, which is the conflation this module separates. Its members are reachable through skos:closeMatch on the separated values, so translating in loses nothing." ;
        sh:maxCount 0 ;
    ] .

:LineItemShape
    a sh:NodeShape ;
    rdfs:label "line item shape" ;
    rdfs:comment "A line names one product, a quantity, and what it sold for. The cost of supplying it is optional, because most sources do not publish it, and its absence is what makes a margin question unanswerable rather than wrong." ;
    sh:targetClass :LineItem ;
    sh:property [
        sh:path :lineItemProduct ;
        sh:name "line item product" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class cmi:Product ;
    ] ;
    sh:property [
        sh:path :lineItemQuantity ;
        sh:name "line item quantity" ;
        sh:description "Strictly positive: a line selling nothing is not a line." ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:datatype xsd:decimal ;
        sh:minExclusive 0 ;
    ] ;
    sh:property [
        sh:path :lineItemRevenue ;
        sh:name "line item revenue" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class adm:MonetaryAmount ;
    ] ;
    sh:property [
        sh:path :costOfGoods ;
        sh:name "cost of goods" ;
        sh:maxCount 1 ;
        sh:class adm:MonetaryAmount ;
    ] ;
    sh:property [
        sh:path schema:orderItemStatus ;
        sh:name "schema.org order item status" ;
        sh:description "Forbidden for the same reason as the order status it draws its values from." ;
        sh:maxCount 0 ;
    ] .

:RefundShape
    a sh:NodeShape ;
    rdfs:label "refund shape" ;
    rdfs:comment "A refund states an amount, the order it reverses, and when. All three are required: an amount without an order cannot be subtracted from anything, and an order without an instant cannot be placed in the window the money left in, which is often later than the one it arrived in." ;
    sh:targetClass :Refund ;
    sh:property [
        sh:path :refundedAmount ;
        sh:name "refunded amount" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class adm:MonetaryAmount ;
    ] ;
    sh:property [
        sh:path :refundOf ;
        sh:name "refund of" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :Order ;
    ] ;
    sh:property [
        sh:path :refundedAt ;
        sh:name "refunded at" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:nodeKind sh:IRI ;
    ] .

:BuyerShape
    a sh:NodeShape ;
    rdfs:label "buyer shape" ;
    rdfs:comment "A buyer carries whether this was their first purchase, which is the one thing a purchase question needs of them. Everything else about who they are belongs elsewhere." ;
    sh:targetClass :Buyer ;
    sh:property [
        sh:path :buyerStatus ;
        sh:name "buyer status" ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:class :BuyerStatus ;
    ] .

:PaymentStateShape
    a sh:NodeShape ;
    rdfs:label "payment state shape" ;
    rdfs:comment "Payment states must be resolvable IRIs so a rule branches on identity rather than on a label." ;
    sh:targetClass :PaymentState ;
    sh:nodeKind sh:IRI .

:FulfillmentStateShape
    a sh:NodeShape ;
    rdfs:label "fulfilment state shape" ;
    rdfs:comment "Fulfilment states must be resolvable IRIs, for the same reason as payment states." ;
    sh:targetClass :FulfillmentState ;
    sh:nodeKind sh:IRI .

:OrderLifecycleStateShape
    a sh:NodeShape ;
    rdfs:label "order lifecycle state shape" ;
    rdfs:comment "Lifecycle values are a closed set defined by this module. The restriction sits on the order's own standing rather than on the class, so a provider profile may still declare a concept aliasing one of these to carry its own token." ;
    sh:targetClass :OrderLifecycleState ;
    sh:nodeKind sh:IRI .

:BuyerStatusShape
    a sh:NodeShape ;
    rdfs:label "buyer status shape" ;
    rdfs:comment "Buyer statuses must be resolvable IRIs so a new-customer rule branches on identity." ;
    sh:targetClass :BuyerStatus ;
    sh:nodeKind sh:IRI .
