From 318fc4adf8077aa7bfd588e408f9df45145051b8 Mon Sep 17 00:00:00 2001 From: Ahmad Sattar Date: Tue, 16 Jun 2026 19:17:38 +0200 Subject: [PATCH 1/5] Add migration for generic supply chain ontology --- .../migrate-ontology-types/currencies.ts | 161 ++ ...itial-currency-data-types.dev.migration.ts | 70 +- ...92-add-supply-chain-types.dev.migration.ts | 1462 +++++++++++++++++ 3 files changed, 1649 insertions(+), 44 deletions(-) create mode 100644 apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/currencies.ts create mode 100644 apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/currencies.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/currencies.ts new file mode 100644 index 00000000000..34d42ce932b --- /dev/null +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/currencies.ts @@ -0,0 +1,161 @@ +/** + * ISO 4217 currencies + */ +export const activeCurrencies: { code: string; name: string }[] = [ + { code: "AED", name: "UAE Dirham" }, + { code: "AUD", name: "Australian Dollar" }, + { code: "BRL", name: "Brazilian Real" }, + { code: "CAD", name: "Canadian Dollar" }, + { code: "CHF", name: "Swiss Franc" }, + { code: "CNY", name: "Yuan Renminbi" }, + { code: "EUR", name: "Euro" }, + { code: "GBP", name: "Pound Sterling" }, + { code: "IDR", name: "Rupiah" }, + { code: "JPY", name: "Yen" }, + { code: "KRW", name: "Won" }, + { code: "KWD", name: "Kuwaiti Dinar" }, + { code: "MXN", name: "Mexican Peso" }, + { code: "OMR", name: "Rial Omani" }, + { code: "PEN", name: "Sol" }, + { code: "QAR", name: "Qatari Rial" }, + { code: "RUB", name: "Russian Ruble" }, + { code: "SGD", name: "Singapore Dollar" }, + { code: "UAH", name: "Hryvnia" }, + { code: "USD", name: "US Dollar" }, + { code: "ZAR", name: "Rand" }, + { code: "AFN", name: "Afghani" }, + { code: "ALL", name: "Lek" }, + { code: "AMD", name: "Armenian Dram" }, + { code: "ANG", name: "Netherlands Antillean Guilder" }, + { code: "AOA", name: "Kwanza" }, + { code: "ARS", name: "Argentine Peso" }, + { code: "AWG", name: "Aruban Florin" }, + { code: "AZN", name: "Azerbaijan Manat" }, + { code: "BAM", name: "Convertible Mark" }, + { code: "BBD", name: "Barbados Dollar" }, + { code: "BDT", name: "Taka" }, + { code: "BGN", name: "Bulgarian Lev" }, + { code: "BHD", name: "Bahraini Dinar" }, + { code: "BIF", name: "Burundi Franc" }, + { code: "BMD", name: "Bermudian Dollar" }, + { code: "BND", name: "Brunei Dollar" }, + { code: "BOB", name: "Boliviano" }, + { code: "BSD", name: "Bahamian Dollar" }, + { code: "BTN", name: "Ngultrum" }, + { code: "BWP", name: "Pula" }, + { code: "BYN", name: "Belarusian Ruble" }, + { code: "BZD", name: "Belize Dollar" }, + { code: "CDF", name: "Congolese Franc" }, + { code: "CLP", name: "Chilean Peso" }, + { code: "COP", name: "Colombian Peso" }, + { code: "CRC", name: "Costa Rican Colon" }, + { code: "CUP", name: "Cuban Peso" }, + { code: "CVE", name: "Cabo Verde Escudo" }, + { code: "CZK", name: "Czech Koruna" }, + { code: "DJF", name: "Djibouti Franc" }, + { code: "DKK", name: "Danish Krone" }, + { code: "DOP", name: "Dominican Peso" }, + { code: "DZD", name: "Algerian Dinar" }, + { code: "EGP", name: "Egyptian Pound" }, + { code: "ERN", name: "Nakfa" }, + { code: "ETB", name: "Ethiopian Birr" }, + { code: "FJD", name: "Fiji Dollar" }, + { code: "FKP", name: "Falkland Islands Pound" }, + { code: "GEL", name: "Lari" }, + { code: "GHS", name: "Ghana Cedi" }, + { code: "GIP", name: "Gibraltar Pound" }, + { code: "GMD", name: "Dalasi" }, + { code: "GNF", name: "Guinean Franc" }, + { code: "GTQ", name: "Quetzal" }, + { code: "GYD", name: "Guyana Dollar" }, + { code: "HKD", name: "Hong Kong Dollar" }, + { code: "HNL", name: "Lempira" }, + { code: "HTG", name: "Gourde" }, + { code: "HUF", name: "Forint" }, + { code: "ILS", name: "New Israeli Sheqel" }, + { code: "INR", name: "Indian Rupee" }, + { code: "IQD", name: "Iraqi Dinar" }, + { code: "IRR", name: "Iranian Rial" }, + { code: "ISK", name: "Iceland Krona" }, + { code: "JMD", name: "Jamaican Dollar" }, + { code: "JOD", name: "Jordanian Dinar" }, + { code: "KES", name: "Kenyan Shilling" }, + { code: "KGS", name: "Som" }, + { code: "KHR", name: "Riel" }, + { code: "KMF", name: "Comorian Franc" }, + { code: "KPW", name: "North Korean Won" }, + { code: "KYD", name: "Cayman Islands Dollar" }, + { code: "KZT", name: "Tenge" }, + { code: "LAK", name: "Lao Kip" }, + { code: "LBP", name: "Lebanese Pound" }, + { code: "LKR", name: "Sri Lanka Rupee" }, + { code: "LRD", name: "Liberian Dollar" }, + { code: "LSL", name: "Loti" }, + { code: "LYD", name: "Libyan Dinar" }, + { code: "MAD", name: "Moroccan Dirham" }, + { code: "MDL", name: "Moldovan Leu" }, + { code: "MGA", name: "Malagasy Ariary" }, + { code: "MKD", name: "Denar" }, + { code: "MMK", name: "Kyat" }, + { code: "MNT", name: "Tugrik" }, + { code: "MOP", name: "Pataca" }, + { code: "MRU", name: "Ouguiya" }, + { code: "MUR", name: "Mauritius Rupee" }, + { code: "MVR", name: "Rufiyaa" }, + { code: "MWK", name: "Malawi Kwacha" }, + { code: "MYR", name: "Malaysian Ringgit" }, + { code: "MZN", name: "Mozambique Metical" }, + { code: "NAD", name: "Namibia Dollar" }, + { code: "NGN", name: "Naira" }, + { code: "NIO", name: "Cordoba Oro" }, + { code: "NOK", name: "Norwegian Krone" }, + { code: "NPR", name: "Nepalese Rupee" }, + { code: "NZD", name: "New Zealand Dollar" }, + { code: "PAB", name: "Balboa" }, + { code: "PGK", name: "Kina" }, + { code: "PHP", name: "Philippine Peso" }, + { code: "PKR", name: "Pakistan Rupee" }, + { code: "PLN", name: "Zloty" }, + { code: "PYG", name: "Guarani" }, + { code: "RON", name: "Romanian Leu" }, + { code: "RSD", name: "Serbian Dinar" }, + { code: "RWF", name: "Rwanda Franc" }, + { code: "SAR", name: "Saudi Riyal" }, + { code: "SBD", name: "Solomon Islands Dollar" }, + { code: "SCR", name: "Seychelles Rupee" }, + { code: "SDG", name: "Sudanese Pound" }, + { code: "SEK", name: "Swedish Krona" }, + { code: "SHP", name: "Saint Helena Pound" }, + { code: "SLE", name: "Leone" }, + { code: "SOS", name: "Somali Shilling" }, + { code: "SRD", name: "Surinam Dollar" }, + { code: "SSP", name: "South Sudanese Pound" }, + { code: "STN", name: "Dobra" }, + { code: "SVC", name: "El Salvador Colon" }, + { code: "SYP", name: "Syrian Pound" }, + { code: "SZL", name: "Lilangeni" }, + { code: "THB", name: "Baht" }, + { code: "TJS", name: "Somoni" }, + { code: "TMT", name: "Turkmenistan New Manat" }, + { code: "TND", name: "Tunisian Dinar" }, + { code: "TOP", name: "Pa'anga" }, + { code: "TRY", name: "Turkish Lira" }, + { code: "TTD", name: "Trinidad and Tobago Dollar" }, + { code: "TWD", name: "New Taiwan Dollar" }, + { code: "TZS", name: "Tanzanian Shilling" }, + { code: "UGX", name: "Uganda Shilling" }, + { code: "UYU", name: "Peso Uruguayo" }, + { code: "UZS", name: "Uzbekistan Sum" }, + { code: "VES", name: "Bolivar Soberano" }, + { code: "VND", name: "Dong" }, + { code: "VUV", name: "Vatu" }, + { code: "WST", name: "Tala" }, + { code: "XAF", name: "CFA Franc BEAC" }, + { code: "XCD", name: "East Caribbean Dollar" }, + { code: "XCG", name: "Caribbean Guilder" }, + { code: "XOF", name: "CFA Franc BCEAO" }, + { code: "XPF", name: "CFP Franc" }, + { code: "YER", name: "Yemeni Rial" }, + { code: "ZMW", name: "Zambian Kwacha" }, + { code: "ZWG", name: "Zimbabwe Gold" }, +]; diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/087-add-initial-currency-data-types.dev.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/087-add-initial-currency-data-types.dev.migration.ts index 435a913b2a2..6c90948a682 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/087-add-initial-currency-data-types.dev.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/087-add-initial-currency-data-types.dev.migration.ts @@ -1,15 +1,26 @@ import { blockProtocolDataTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; +import { activeCurrencies } from "../currencies"; import { createSystemDataTypeIfNotExists } from "../util"; import type { MigrationFunction } from "../types"; +// Currencies with a well-known symbol; the rest display with their ISO code. +const currencySymbols: Record = { + USD: "$", + GBP: "£", + EUR: "€", + JPY: "¥", + CNY: "¥", + INR: "₹", +}; + const migrate: MigrationFunction = async ({ context, authentication, migrationState, }) => { - const currencyDataTypes = await createSystemDataTypeIfNotExists( + const currencyDataType = await createSystemDataTypeIfNotExists( context, authentication, { @@ -27,50 +38,21 @@ const migrate: MigrationFunction = async ({ }, ); - await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: currencyDataTypes.schema.$id }], - title: "USD", - description: "An amount denominated in US Dollars.", - type: "number", - label: { - left: "$", - }, - }, - conversions: {}, - webShortname: "h", - migrationState, - }); - - await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: currencyDataTypes.schema.$id }], - title: "GBP", - description: "An amount denominated in British pounds sterling.", - type: "number", - label: { - left: "£", - }, - }, - conversions: {}, - webShortname: "h", - migrationState, - }); - - await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: currencyDataTypes.schema.$id }], - title: "EUR", - description: "An amount denominated in Euros.", - type: "number", - label: { - left: "€", + for (const { code, name } of activeCurrencies) { + const symbol = currencySymbols[code]; + await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: currencyDataType.schema.$id }], + title: code, + description: `An amount denominated in ${name} (ISO 4217 ${code}).`, + type: "number", + ...(symbol ? { label: { left: symbol } } : {}), }, - }, - conversions: {}, - webShortname: "h", - migrationState, - }); + conversions: {}, + webShortname: "h", + migrationState, + }); + } return migrationState; }; diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts new file mode 100644 index 00000000000..e3d1ae6636c --- /dev/null +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts @@ -0,0 +1,1462 @@ +import { + blockProtocolDataTypes, + blockProtocolEntityTypes, + blockProtocolPropertyTypes, +} from "@local/hash-isomorphic-utils/ontology-type-ids"; + +import { versionedUrlFromComponents } from "@blockprotocol/type-system"; + +import { activeCurrencies } from "../currencies"; +import { + createSystemDataTypeIfNotExists, + createSystemEntityTypeIfNotExists, + createSystemPropertyTypeIfNotExists, + generateSystemTypeBaseUrl, + getCurrentHashDataTypeId, + getCurrentHashPropertyTypeId, +} from "../util"; + +import type { BaseUrl, Conversions, VersionedUrl } from "@blockprotocol/type-system"; + +import type { MigrationFunction } from "../types"; + +const migrate: MigrationFunction = async ({ + context, + authentication, + migrationState, +}) => { + + const dateDataTypeId = getCurrentHashDataTypeId({ + dataTypeKey: "date", + migrationState, + }); + const calendarYearDataTypeId = getCurrentHashDataTypeId({ + dataTypeKey: "calendarYear", + migrationState, + }); + const percentageDataTypeId = getCurrentHashDataTypeId({ + dataTypeKey: "percentage", + migrationState, + }); + const integerDataTypeId = getCurrentHashDataTypeId({ + dataTypeKey: "integer", + migrationState, + }); + const lengthValues = ( + ["meters", "centimeters", "millimeters", "kilometers", "feet", "inches", "yards", "miles"] as const + ).map((dataTypeKey) => ({ dataTypeId: getCurrentHashDataTypeId({ dataTypeKey, migrationState }) })); + const currencyValues = activeCurrencies.map(({ code }) => { + const baseUrl = generateSystemTypeBaseUrl({ + kind: "data-type", + title: code, + shortname: "h", + }); + const version = migrationState.dataTypeVersions[baseUrl]; + if (!version) { + throw new Error(`Currency data type '${code}' has not been seeded`); + } + return { dataTypeId: versionedUrlFromComponents(baseUrl, version) }; + }); + const cityPropertyTypeId = getCurrentHashPropertyTypeId({ + propertyTypeKey: "city", + migrationState, + }); + const statusPropertyTypeId = getCurrentHashPropertyTypeId({ + propertyTypeKey: "status", + migrationState, + }); + + const massDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + abstract: true, + title: "Mass", + description: "A measure of the amount of matter in an object.", + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", + }, + ); + + const kilogramsDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: massDataType.schema.$id }], + title: "Kilograms", + description: "The SI base unit of mass, equal to 1000 grams.", + label: { right: "kg" }, + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", + }, + ); + + const gramsDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: massDataType.schema.$id }], + title: "Grams", + description: + "A metric unit of mass equal to one thousandth of a kilogram.", + label: { right: "g" }, + type: "number", + }, + conversions: { + [kilogramsDataType.metadata.recordId.baseUrl]: { + from: { expression: ["*", "self", { const: 1000, type: "number" }] }, + to: { expression: ["/", "self", { const: 1000, type: "number" }] }, + }, + }, + migrationState, + webShortname: "h", + }, + ); + + const metricTonnesDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: massDataType.schema.$id }], + title: "Metric Tonnes", + description: "A metric unit of mass equal to 1000 kilograms.", + label: { right: "t" }, + type: "number", + }, + conversions: { + [kilogramsDataType.metadata.recordId.baseUrl]: { + from: { expression: ["/", "self", { const: 1000, type: "number" }] }, + to: { expression: ["*", "self", { const: 1000, type: "number" }] }, + }, + }, + migrationState, + webShortname: "h", + }, + ); + + const poundsDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: massDataType.schema.$id }], + title: "Pounds", + description: + "An imperial unit of mass equal to exactly 0.45359237 kilograms.", + label: { right: "lb" }, + type: "number", + }, + conversions: { + [kilogramsDataType.metadata.recordId.baseUrl]: { + from: { + expression: ["/", "self", { const: 0.45359237, type: "number" }], + }, + to: { + expression: ["*", "self", { const: 0.45359237, type: "number" }], + }, + }, + }, + migrationState, + webShortname: "h", + }, + ); + + const massValues = [ + { dataTypeId: kilogramsDataType.schema.$id }, + { dataTypeId: gramsDataType.schema.$id }, + { dataTypeId: metricTonnesDataType.schema.$id }, + { dataTypeId: poundsDataType.schema.$id }, + ]; + + const convTo = (canonicalBaseUrl: BaseUrl, factor: number): Record => ({ + [canonicalBaseUrl]: { + from: { expression: ["/", "self", { const: factor, type: "number" }] }, + to: { expression: ["*", "self", { const: factor, type: "number" }] }, + }, + }); + + const abstractMeasure = (title: string, description: string) => + createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + abstract: true, + title, + description, + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", + }); + + const volumeDataType = await abstractMeasure( + "Volume", + "A measure of the three-dimensional space occupied by something.", + ); + const litresDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: volumeDataType.schema.$id }], + title: "Litres", + description: "A metric unit of volume equal to one cubic decimetre.", + label: { right: "L" }, + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", + }); + const millilitresDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: volumeDataType.schema.$id }], + title: "Millilitres", + description: "A metric unit of volume equal to one thousandth of a litre.", + label: { right: "mL" }, + type: "number", + }, + conversions: convTo(litresDataType.metadata.recordId.baseUrl, 0.001), + migrationState, + webShortname: "h", + }); + const cubicMetresDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: volumeDataType.schema.$id }], + title: "Cubic Metres", + description: "A metric unit of volume equal to 1000 litres.", + label: { right: "m³" }, + type: "number", + }, + conversions: convTo(litresDataType.metadata.recordId.baseUrl, 1000), + migrationState, + webShortname: "h", + }); + + const unitDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + title: "Unit", + description: + "A dimensionless quantity: a count of discrete items, or an amount whose unit of measure has no dedicated data type.", + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", + }); + + const quantityUnitValues = [ + ...massValues, + { dataTypeId: litresDataType.schema.$id }, + { dataTypeId: millilitresDataType.schema.$id }, + { dataTypeId: cubicMetresDataType.schema.$id }, + ...lengthValues, + { dataTypeId: unitDataType.schema.$id }, + ]; + + const text = (title: string, description: string) => + createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title, + description, + possibleValues: [{ primitiveDataType: "text" }], + }, + migrationState, + webShortname: "h", + }); + + const num = (title: string, description: string) => + createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title, + description, + possibleValues: [{ primitiveDataType: "number" }], + }, + migrationState, + webShortname: "h", + }); + + const withDataType = ( + title: string, + description: string, + dataTypeId: VersionedUrl, + ) => + createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title, + description, + possibleValues: [{ dataTypeId }], + }, + migrationState, + webShortname: "h", + }); + + const grossWeightPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { + propertyTypeDefinition: { + title: "Gross Weight", + description: + "The total weight of an object including its packaging or container.", + possibleValues: massValues, + }, + migrationState, + webShortname: "h", + }, + ); + + const netWeightPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { + propertyTypeDefinition: { + title: "Net Weight", + description: + "The weight of an object excluding its packaging or container.", + possibleValues: massValues, + }, + migrationState, + webShortname: "h", + }, + ); + + const postalCodePropertyType = await text( + "Postal Code", + "A code used by postal services to identify a geographic area for sorting and delivery of mail.", + ); + const countryPropertyType = await text( + "Country", + "The country in which something is located, or to which it belongs.", + ); + const streetAddressPropertyType = await text( + "Street Address", + "The street name and number (with any additional detail) of a postal address.", + ); + const regionPropertyType = await text( + "Region", + "A region, state, province, or other administrative subdivision of a country.", + ); + + const unitOfMeasurePropertyType = await text( + "Unit of Measure", + "The base unit of measure declared for an item (e.g. each, kilograms, litres).", + ); + + const quantity = (title: string, description: string) => + createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { title, description, possibleValues: quantityUnitValues }, + migrationState, + webShortname: "h", + }); + + const currency = (title: string, description: string) => + createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { title, description, possibleValues: currencyValues }, + migrationState, + webShortname: "h", + }); + + const baseQuantityPropertyType = await quantity( + "Base Quantity", + "The base quantity an item is defined in, such as for a bill of materials.", + ); + + const identifierPropertyType = await text( + "Identifier", + "A unique identifier for a record in its source system.", + ); + const itemNumberPropertyType = await text( + "Item Number", + "The position of a line item within a document.", + ); + const scheduleLineNumberPropertyType = await text( + "Schedule Line Number", + "The number identifying a delivery schedule line within a document item.", + ); + + const orderTypePropertyType = await text( + "Order Type", + "The category of an order, such as a standard order, returns, or a quotation.", + ); + const deliveryTypePropertyType = await text( + "Delivery Type", + "The category of a delivery document.", + ); + const lineItemCategoryPropertyType = await text( + "Line Item Category", + "The category of a document line item, determining how it behaves.", + ); + const rejectionReasonPropertyType = await text( + "Rejection Reason", + "The reason a document item was rejected.", + ); + const currencyCodePropertyType = await text( + "Currency Code", + "An ISO 4217 currency code identifying the currency of monetary values.", + ); + const customerReferencePropertyType = await text( + "Customer Reference", + "A reference provided by the customer, such as their own purchase order number.", + ); + const referenceNumberPropertyType = await text( + "Reference Number", + "An external reference number associated with a document.", + ); + + const salesOrganizationPropertyType = await text( + "Sales Organization", + "The organizational unit responsible for selling goods or services.", + ); + const distributionChannelPropertyType = await text( + "Distribution Channel", + "The channel through which goods or services reach the customer.", + ); + const divisionPropertyType = await text( + "Division", + "A product line or business division within an organization.", + ); + + const productTypePropertyType = await text( + "Product Type", + "The category of a product, such as finished good, raw material, or service.", + ); + const productGroupPropertyType = await text( + "Product Group", + "A grouping of products for reporting or pricing.", + ); + const itemCategoryGroupPropertyType = await text( + "Item Category Group", + "A grouping used to classify products for sales and pricing logic.", + ); + const industryPropertyType = await text( + "Industry", + "An industry classification.", + ); + const languagePropertyType = await text( + "Language", + "A language, for example of a text or description.", + ); + + const storageLocationPropertyType = await text( + "Storage Location", + "A location within a facility where goods are stored.", + ); + const storageBinPropertyType = await text( + "Storage Bin", + "A specific bin or position within a storage location.", + ); + const batchNumberPropertyType = await text( + "Batch Number", + "A batch or lot identifier used for tracking goods.", + ); + const movementTypePropertyType = await text( + "Movement Type", + "The type of a goods movement, such as a goods receipt, goods issue, or transfer.", + ); + const movementCategoryPropertyType = await text( + "Movement Category", + "A broad category of goods movement.", + ); + const debitCreditIndicatorPropertyType = await text( + "Debit/Credit Indicator", + "Indicates whether a posting is a debit or a credit.", + ); + const legIndicatorPropertyType = await text( + "Leg Indicator", + "An indicator describing a leg of a transport route.", + ); + + const planningMethodPropertyType = await text( + "Planning Method", + "The method used to plan replenishment of an item.", + ); + const plannedDeliveryTimePropertyType = await num( + "Planned Delivery Time", + "The planned lead time to procure or deliver an item, in days.", + ); + const goodsReceiptProcessingTimePropertyType = await num( + "Goods Receipt Processing Time", + "The time required to process a goods receipt, in days.", + ); + const inHouseProductionTimePropertyType = await num( + "In-House Production Time", + "The time required for in-house production, in days.", + ); + + const priceControlIndicatorPropertyType = await text( + "Price Control Indicator", + "Indicates how a price is maintained, e.g. standard or moving average.", + ); + const priceUnitPropertyType = await num( + "Price Unit", + "The number of units to which a price refers.", + ); + const valuationClassPropertyType = await text( + "Valuation Class", + "A classification linking an item's valuation to accounting.", + ); + const valuationAreaPropertyType = await text( + "Valuation Area", + "The area within which an item's value is maintained.", + ); + const valuationTypePropertyType = await text( + "Valuation Type", + "The type or class of valuation, such as legal or group valuation.", + ); + const valuationCategoryPropertyType = await text( + "Valuation Category", + "Indicates the split-valuation category of an item.", + ); + + const netValuePropertyType = await currency( + "Net Value", + "The net monetary value of a document or item.", + ); + const standardPricePropertyType = await currency( + "Standard Price", + "The fixed standard price of an item.", + ); + const movingAveragePricePropertyType = await currency( + "Moving Average Price", + "The current moving-average per-unit price of an item.", + ); + const stockValuePropertyType = await currency( + "Stock Value", + "The total monetary value of stock on hand.", + ); + const futurePricePropertyType = await currency( + "Future Price", + "A validated future price of an item.", + ); + + const postingPeriodPropertyType = await withDataType( + "Posting Period", + "An accounting period within a fiscal year.", + integerDataTypeId, + ); + const fiscalYearPropertyType = await withDataType( + "Fiscal Year", + "The fiscal year to which data applies.", + calendarYearDataTypeId, + ); + const scrapPercentagePropertyType = await withDataType( + "Scrap Percentage", + "The expected percentage of a component lost as scrap.", + percentageDataTypeId, + ); + + const date = (title: string, description: string) => + withDataType(title, description, dateDataTypeId); + + const orderDatePropertyType = await date( + "Order Date", + "The date on which an order or purchasing document was created.", + ); + const requestedDeliveryDatePropertyType = await date( + "Requested Delivery Date", + "The delivery date requested by the customer.", + ); + const deliveryDatePropertyType = await date( + "Delivery Date", + "The date on which delivery is scheduled or expected.", + ); + const statisticalDeliveryDatePropertyType = await date( + "Statistical Delivery Date", + "A delivery date used for statistical reporting.", + ); + const plannedGoodsIssueDatePropertyType = await date( + "Planned Goods Issue Date", + "The planned date on which goods are issued.", + ); + const actualGoodsIssueDatePropertyType = await date( + "Actual Goods Issue Date", + "The actual date on which goods were issued.", + ); + const pickingDatePropertyType = await date( + "Picking Date", + "The date on which goods were picked.", + ); + const postingDatePropertyType = await date( + "Posting Date", + "The date on which a transaction was posted.", + ); + const documentDatePropertyType = await date( + "Document Date", + "The date shown on a document.", + ); + const scheduledStartDatePropertyType = await date( + "Scheduled Start Date", + "The date on which an activity is scheduled to start.", + ); + const actualFinishDatePropertyType = await date( + "Actual Finish Date", + "The date on which an activity actually finished.", + ); + const lastPriceChangeDatePropertyType = await date( + "Last Price Change Date", + "The date on which a price was last changed.", + ); + const futurePriceDatePropertyType = await date( + "Future Price Date", + "The date on which a future price takes effect.", + ); + const actualDepartureDatePropertyType = await date( + "Actual Departure Date", + "The actual date of departure of a shipment.", + ); + const actualShipmentCompletionDatePropertyType = await date( + "Actual Shipment Completion Date", + "The actual date a shipment was completed.", + ); + const actualShipmentEndDatePropertyType = await date( + "Actual Shipment End Date", + "The actual end date of a shipment.", + ); + const plannedShipmentEndDatePropertyType = await date( + "Planned Shipment End Date", + "The planned end date of a shipment.", + ); + + const deliveredQuantityPropertyType = await quantity( + "Delivered Quantity", + "The quantity actually delivered.", + ); + const orderQuantityPropertyType = await quantity( + "Order Quantity", + "The quantity ordered.", + ); + const requirementQuantityPropertyType = await quantity( + "Requirement Quantity", + "The quantity required.", + ); + const withdrawnQuantityPropertyType = await quantity( + "Withdrawn Quantity", + "The quantity already withdrawn against a requirement.", + ); + const goodsReceiptQuantityPropertyType = await quantity( + "Goods Receipt Quantity", + "The quantity received against an order or schedule line.", + ); + const productionQuantityPropertyType = await quantity( + "Production Quantity", + "The quantity to be produced.", + ); + const movementQuantityPropertyType = await quantity( + "Movement Quantity", + "The quantity recorded on a movement or document line.", + ); + const stockQuantityPropertyType = await quantity( + "Stock Quantity", + "The quantity of stock on hand.", + ); + const safetyStockPropertyType = await quantity( + "Safety Stock", + "The safety stock level maintained for an item.", + ); + const maximumLotSizePropertyType = await quantity( + "Maximum Lot Size", + "The maximum lot size allowed when planning orders.", + ); + + const link = (title: string, inverseTitle: string, description: string) => + createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title, + inverse: { title: inverseTitle }, + description, + }, + migrationState, + webShortname: "h", + }); + + const hasLineItemLink = await link( + "Has Line Item", + "Line Item Of", + "A line item belonging to this document.", + ); + const hasCustomerLink = await link( + "Has Customer", + "Customer For", + "The customer associated with this document.", + ); + const hasSupplierLink = await link( + "Has Supplier", + "Supplier For", + "The supplier associated with this document.", + ); + const hasProductLink = await link( + "Has Product", + "Product For", + "The product that this concerns.", + ); + const fulfillsLink = await link( + "Fulfills", + "Fulfilled By", + "A preceding document or item that this one fulfills.", + ); + const locatedAtLink = await link( + "Located At", + "Location For", + "The facility where this is located or takes place.", + ); + const producesLink = await link( + "Produces", + "Produced By", + "A material produced by this.", + ); + const consumesLink = await link( + "Consumes", + "Consumed By", + "A material consumed by this.", + ); + const procuresLink = await link( + "Procures", + "Procured By", + "A material procured by this.", + ); + const movesLink = await link( + "Moves", + "Moved By", + "A material moved by this.", + ); + const ofMaterialLink = await link( + "Of Material", + "Has Batch", + "The material this batch is of.", + ); + const recordsBatchLink = await link( + "Records Batch", + "Recorded On", + "A batch recorded by this movement.", + ); + const yieldsBatchLink = await link( + "Yields Batch", + "Yielded By", + "A batch produced by this order.", + ); + const deliversBatchLink = await link( + "Delivers Batch", + "Delivered In", + "A batch delivered by this.", + ); + + const companyEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Company", + titlePlural: "Companies", + description: + "A business or legal entity engaged in commercial activity, such as a customer or supplier.", + labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + }, + { propertyType: identifierPropertyType }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const customerEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + allOf: [companyEntityType.schema.$id], + title: "Customer", + titlePlural: "Customers", + description: "A company that purchases goods or services.", + properties: [ + { propertyType: streetAddressPropertyType }, + { propertyType: cityPropertyTypeId }, + { propertyType: regionPropertyType }, + { propertyType: postalCodePropertyType }, + { propertyType: countryPropertyType }, + { propertyType: industryPropertyType }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const supplierEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + allOf: [companyEntityType.schema.$id], + title: "Supplier", + titlePlural: "Suppliers", + description: "A company that provides goods or services.", + }, + migrationState, + webShortname: "h", + }, + ); + + const materialEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Material", + titlePlural: "Materials", + description: + "A good or material that can be produced, stored, sold, or procured — including raw materials, intermediates, and finished goods.", + labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, + properties: [ + { propertyType: blockProtocolPropertyTypes.name.propertyTypeId }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + }, + { propertyType: identifierPropertyType }, + { propertyType: productTypePropertyType }, + { propertyType: productGroupPropertyType }, + { propertyType: itemCategoryGroupPropertyType }, + { propertyType: grossWeightPropertyType }, + { propertyType: netWeightPropertyType }, + { propertyType: unitOfMeasurePropertyType }, + { propertyType: languagePropertyType }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const facilityEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Facility", + titlePlural: "Facilities", + description: + "A physical site, such as a plant or warehouse, where goods are produced or stored.", + labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, + properties: [ + { propertyType: blockProtocolPropertyTypes.name.propertyTypeId }, + { propertyType: identifierPropertyType }, + { propertyType: cityPropertyTypeId }, + { propertyType: countryPropertyType }, + { propertyType: storageLocationPropertyType }, + { propertyType: storageBinPropertyType }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const expiryDatePropertyType = await date( + "Expiry Date", + "The date on which a batch expires or is no longer usable.", + ); + + const batchEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Batch", + titlePlural: "Batches", + description: + "A specific lot of a material, tracked through production, storage, and movement.", + labelProperty: identifierPropertyType.metadata.recordId.baseUrl, + properties: [ + { propertyType: identifierPropertyType }, + { propertyType: expiryDatePropertyType }, + { propertyType: stockQuantityPropertyType }, + { propertyType: unitOfMeasurePropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: ofMaterialLink, + destinationEntityTypes: [materialEntityType.schema.$id], + maxItems: 1, + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const bomItemEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Bill of Materials Item", + titlePlural: "Bill of Materials Items", + description: "A component line within a bill of materials.", + properties: [ + { propertyType: itemNumberPropertyType }, + { propertyType: movementQuantityPropertyType }, + { propertyType: scrapPercentagePropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasProductLink, + destinationEntityTypes: [materialEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const _billOfMaterialsEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Bill of Materials", + titlePlural: "Bills of Materials", + description: + "A structured list of the components required to produce a product.", + labelProperty: identifierPropertyType.metadata.recordId.baseUrl, + properties: [ + { propertyType: identifierPropertyType }, + { propertyType: baseQuantityPropertyType }, + { propertyType: unitOfMeasurePropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasProductLink, + destinationEntityTypes: [materialEntityType.schema.$id], + }, + { + linkEntityType: hasLineItemLink, + destinationEntityTypes: [bomItemEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const salesOrderItemEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Sales Order Item", + titlePlural: "Sales Order Items", + description: "A line item within a sales order.", + properties: [ + { propertyType: itemNumberPropertyType }, + { propertyType: lineItemCategoryPropertyType }, + { propertyType: rejectionReasonPropertyType }, + { propertyType: orderQuantityPropertyType }, + { propertyType: netValuePropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasProductLink, + destinationEntityTypes: [materialEntityType.schema.$id], + }, + { + linkEntityType: locatedAtLink, + destinationEntityTypes: [facilityEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const salesOrderEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Sales Order", + titlePlural: "Sales Orders", + description: + "A commitment by a customer to purchase goods or services on agreed terms.", + labelProperty: identifierPropertyType.metadata.recordId.baseUrl, + properties: [ + { propertyType: identifierPropertyType }, + { propertyType: orderTypePropertyType }, + { propertyType: salesOrganizationPropertyType }, + { propertyType: distributionChannelPropertyType }, + { propertyType: divisionPropertyType }, + { propertyType: currencyCodePropertyType }, + { propertyType: netValuePropertyType }, + { propertyType: customerReferencePropertyType }, + { propertyType: orderDatePropertyType }, + { propertyType: requestedDeliveryDatePropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasCustomerLink, + destinationEntityTypes: [customerEntityType.schema.$id], + maxItems: 1, + }, + { + linkEntityType: hasLineItemLink, + destinationEntityTypes: [salesOrderItemEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const deliveryItemEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Delivery Item", + titlePlural: "Delivery Items", + description: "A line item within a delivery.", + properties: [ + { propertyType: itemNumberPropertyType }, + { propertyType: deliveredQuantityPropertyType }, + { propertyType: batchNumberPropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasProductLink, + destinationEntityTypes: [materialEntityType.schema.$id], + }, + { + linkEntityType: deliversBatchLink, + destinationEntityTypes: [batchEntityType.schema.$id], + }, + { + linkEntityType: locatedAtLink, + destinationEntityTypes: [facilityEntityType.schema.$id], + }, + { + linkEntityType: fulfillsLink, + destinationEntityTypes: [salesOrderItemEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const deliveryEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Delivery", + titlePlural: "Deliveries", + description: "An outbound shipment of goods against an order.", + labelProperty: identifierPropertyType.metadata.recordId.baseUrl, + properties: [ + { propertyType: identifierPropertyType }, + { propertyType: deliveryTypePropertyType }, + { propertyType: deliveryDatePropertyType }, + { propertyType: plannedGoodsIssueDatePropertyType }, + { propertyType: actualGoodsIssueDatePropertyType }, + { propertyType: pickingDatePropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasCustomerLink, + destinationEntityTypes: [customerEntityType.schema.$id], + maxItems: 1, + }, + { + linkEntityType: hasLineItemLink, + destinationEntityTypes: [deliveryItemEntityType.schema.$id], + }, + { + linkEntityType: fulfillsLink, + destinationEntityTypes: [salesOrderEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const purchaseOrderScheduleLineEntityType = + await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Purchase Order Schedule Line", + titlePlural: "Purchase Order Schedule Lines", + description: "A delivery schedule line within a purchase order item.", + properties: [ + { propertyType: scheduleLineNumberPropertyType }, + { propertyType: deliveryDatePropertyType }, + { propertyType: statisticalDeliveryDatePropertyType }, + { propertyType: orderQuantityPropertyType }, + { propertyType: goodsReceiptQuantityPropertyType }, + ], + }, + migrationState, + webShortname: "h", + }); + + const purchaseOrderItemEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Purchase Order Item", + titlePlural: "Purchase Order Items", + description: "A line item within a purchase order.", + properties: [{ propertyType: itemNumberPropertyType }], + outgoingLinks: [ + { + linkEntityType: procuresLink, + destinationEntityTypes: [materialEntityType.schema.$id], + }, + { + linkEntityType: locatedAtLink, + destinationEntityTypes: [facilityEntityType.schema.$id], + }, + { + linkEntityType: hasLineItemLink, + destinationEntityTypes: [ + purchaseOrderScheduleLineEntityType.schema.$id, + ], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const _purchaseOrderEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Purchase Order", + titlePlural: "Purchase Orders", + description: + "A commitment to purchase goods or services from a supplier on agreed terms.", + labelProperty: identifierPropertyType.metadata.recordId.baseUrl, + properties: [ + { propertyType: identifierPropertyType }, + { propertyType: orderDatePropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasSupplierLink, + destinationEntityTypes: [supplierEntityType.schema.$id], + maxItems: 1, + }, + { + linkEntityType: hasLineItemLink, + destinationEntityTypes: [purchaseOrderItemEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const productionOrderItemEntityType = + await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Production Order Item", + titlePlural: "Production Order Items", + description: "A line item within a production order.", + properties: [ + { propertyType: productionQuantityPropertyType }, + { propertyType: goodsReceiptQuantityPropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: producesLink, + destinationEntityTypes: [materialEntityType.schema.$id], + }, + { + linkEntityType: locatedAtLink, + destinationEntityTypes: [facilityEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }); + + const productionOrderEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Production Order", + titlePlural: "Production Orders", + description: "An order to manufacture a product.", + labelProperty: identifierPropertyType.metadata.recordId.baseUrl, + properties: [ + { propertyType: identifierPropertyType }, + { propertyType: scheduledStartDatePropertyType }, + { propertyType: actualFinishDatePropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasLineItemLink, + destinationEntityTypes: [productionOrderItemEntityType.schema.$id], + }, + { + linkEntityType: yieldsBatchLink, + destinationEntityTypes: [batchEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const _materialMovementEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Material Movement", + titlePlural: "Material Movements", + description: + "A record of material moving into, out of, or within inventory, including consumption and receipt against orders.", + labelProperty: identifierPropertyType.metadata.recordId.baseUrl, + properties: [ + { propertyType: identifierPropertyType }, + { propertyType: fiscalYearPropertyType }, + { propertyType: movementTypePropertyType }, + { propertyType: movementCategoryPropertyType }, + { propertyType: batchNumberPropertyType }, + { propertyType: postingDatePropertyType }, + { propertyType: documentDatePropertyType }, + { propertyType: referenceNumberPropertyType }, + { propertyType: movementQuantityPropertyType }, + { propertyType: debitCreditIndicatorPropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: movesLink, + destinationEntityTypes: [materialEntityType.schema.$id], + }, + { + linkEntityType: recordsBatchLink, + destinationEntityTypes: [batchEntityType.schema.$id], + }, + { + linkEntityType: locatedAtLink, + destinationEntityTypes: [facilityEntityType.schema.$id], + }, + { + linkEntityType: fulfillsLink, + destinationEntityTypes: [ + purchaseOrderItemEntityType.schema.$id, + productionOrderEntityType.schema.$id, + ], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const sitePropertyType = await text( + "Site", + "A location or facility at which an activity takes place.", + ); + const standardCostPropertyType = await num( + "Standard Cost", + "The standard cost of an item.", + ); + + const _costValuationEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Cost / Valuation", + titlePlural: "Cost / Valuations", + description: + "The cost and valuation of a material's stock — valuation prices, controls, and sourcing standard cost.", + properties: [ + { propertyType: sitePropertyType }, + { propertyType: standardCostPropertyType }, + { propertyType: valuationClassPropertyType }, + { propertyType: valuationAreaPropertyType }, + { propertyType: valuationTypePropertyType }, + { propertyType: valuationCategoryPropertyType }, + { propertyType: priceControlIndicatorPropertyType }, + { propertyType: standardPricePropertyType }, + { propertyType: movingAveragePricePropertyType }, + { propertyType: stockValuePropertyType }, + { propertyType: futurePricePropertyType }, + { propertyType: priceUnitPropertyType }, + { propertyType: currencyCodePropertyType }, + { propertyType: stockQuantityPropertyType }, + { propertyType: postingPeriodPropertyType }, + { propertyType: fiscalYearPropertyType }, + { propertyType: lastPriceChangeDatePropertyType }, + { propertyType: futurePriceDatePropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasProductLink, + destinationEntityTypes: [materialEntityType.schema.$id], + maxItems: 1, + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const _materialLocationEntityType = + await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Material Location", + titlePlural: "Material Locations", + description: + "A material at a specific facility, with its plant-level planning parameters such as safety stock and lead times.", + properties: [ + { propertyType: planningMethodPropertyType }, + { propertyType: statusPropertyTypeId }, + { propertyType: safetyStockPropertyType }, + { propertyType: maximumLotSizePropertyType }, + { propertyType: plannedDeliveryTimePropertyType }, + { propertyType: goodsReceiptProcessingTimePropertyType }, + { propertyType: inHouseProductionTimePropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasProductLink, + destinationEntityTypes: [materialEntityType.schema.$id], + maxItems: 1, + }, + { + linkEntityType: locatedAtLink, + destinationEntityTypes: [facilityEntityType.schema.$id], + maxItems: 1, + }, + ], + }, + migrationState, + webShortname: "h", + }); + + const _materialReservationEntityType = + await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Material Reservation", + titlePlural: "Material Reservations", + description: + "A reservation of a product as a component requirement, such as for a production order.", + properties: [ + { propertyType: requirementQuantityPropertyType }, + { propertyType: withdrawnQuantityPropertyType }, + { propertyType: debitCreditIndicatorPropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: consumesLink, + destinationEntityTypes: [materialEntityType.schema.$id], + }, + { + linkEntityType: locatedAtLink, + destinationEntityTypes: [facilityEntityType.schema.$id], + }, + { + linkEntityType: fulfillsLink, + destinationEntityTypes: [productionOrderEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }); + + const shipmentItemEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Shipment Item", + titlePlural: "Shipment Items", + description: + "A line within a shipment, linking it to a delivery being transported.", + labelProperty: identifierPropertyType.metadata.recordId.baseUrl, + properties: [{ propertyType: identifierPropertyType }], + outgoingLinks: [ + { + linkEntityType: fulfillsLink, + destinationEntityTypes: [deliveryEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + const _shipmentEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { + entityTypeDefinition: { + title: "Shipment", + titlePlural: "Shipments", + description: + "The transport of goods, potentially grouping several deliveries.", + labelProperty: identifierPropertyType.metadata.recordId.baseUrl, + properties: [ + { propertyType: identifierPropertyType }, + { propertyType: actualDepartureDatePropertyType }, + { propertyType: actualShipmentCompletionDatePropertyType }, + { propertyType: actualShipmentEndDatePropertyType }, + { propertyType: plannedShipmentEndDatePropertyType }, + { propertyType: legIndicatorPropertyType }, + ], + outgoingLinks: [ + { + linkEntityType: hasLineItemLink, + destinationEntityTypes: [shipmentItemEntityType.schema.$id], + }, + ], + }, + migrationState, + webShortname: "h", + }, + ); + + return migrationState; +}; + +export default migrate; From c0797116e8008152738c57cc124bfd793b06cc84 Mon Sep 17 00:00:00 2001 From: Ahmad Sattar Date: Wed, 24 Jun 2026 13:21:27 +0200 Subject: [PATCH 2/5] Add measurements to the migrations --- ...92-add-supply-chain-types.dev.migration.ts | 205 +++++++++--------- 1 file changed, 99 insertions(+), 106 deletions(-) diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts index e3d1ae6636c..ad4358fdf9e 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts @@ -38,10 +38,6 @@ const migrate: MigrationFunction = async ({ dataTypeKey: "percentage", migrationState, }); - const integerDataTypeId = getCurrentHashDataTypeId({ - dataTypeKey: "integer", - migrationState, - }); const lengthValues = ( ["meters", "centimeters", "millimeters", "kilometers", "feet", "inches", "yards", "miles"] as const ).map((dataTypeKey) => ({ dataTypeId: getCurrentHashDataTypeId({ dataTypeKey, migrationState }) })); @@ -241,6 +237,73 @@ const migrate: MigrationFunction = async ({ webShortname: "h", }); + const areaDataType = await abstractMeasure( + "Area", + "A measure of the extent of a two-dimensional surface.", + ); + const squareMetresDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: areaDataType.schema.$id }], + title: "Square Metres", + description: "A metric unit of area equal to a square one metre on each side.", + label: { right: "m²" }, + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", + }); + const squareCentimetresDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: areaDataType.schema.$id }], + title: "Square Centimetres", + description: "A metric unit of area equal to one ten-thousandth of a square metre.", + label: { right: "cm²" }, + type: "number", + }, + conversions: convTo(squareMetresDataType.metadata.recordId.baseUrl, 0.0001), + migrationState, + webShortname: "h", + }); + const squareFeetDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: areaDataType.schema.$id }], + title: "Square Feet", + description: "An imperial unit of area equal to a square one foot on each side.", + label: { right: "ft²" }, + type: "number", + }, + conversions: convTo(squareMetresDataType.metadata.recordId.baseUrl, 0.09290304), + migrationState, + webShortname: "h", + }); + + const durationDataType = await abstractMeasure("Duration", "A measure of elapsed time."); + const hoursDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: durationDataType.schema.$id }], + title: "Hours", + description: "A unit of time equal to 60 minutes.", + label: { right: "h" }, + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", + }); + const daysDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: durationDataType.schema.$id }], + title: "Days", + description: "A unit of time equal to 24 hours.", + label: { right: "d" }, + type: "number", + }, + conversions: convTo(hoursDataType.metadata.recordId.baseUrl, 24), + migrationState, + webShortname: "h", + }); + const unitDataType = await createSystemDataTypeIfNotExists(context, authentication, { dataTypeDefinition: { allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], @@ -260,6 +323,11 @@ const migrate: MigrationFunction = async ({ { dataTypeId: millilitresDataType.schema.$id }, { dataTypeId: cubicMetresDataType.schema.$id }, ...lengthValues, + { dataTypeId: squareMetresDataType.schema.$id }, + { dataTypeId: squareCentimetresDataType.schema.$id }, + { dataTypeId: squareFeetDataType.schema.$id }, + { dataTypeId: hoursDataType.schema.$id }, + { dataTypeId: daysDataType.schema.$id }, { dataTypeId: unitDataType.schema.$id }, ]; @@ -300,36 +368,6 @@ const migrate: MigrationFunction = async ({ webShortname: "h", }); - const grossWeightPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Gross Weight", - description: - "The total weight of an object including its packaging or container.", - possibleValues: massValues, - }, - migrationState, - webShortname: "h", - }, - ); - - const netWeightPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Net Weight", - description: - "The weight of an object excluding its packaging or container.", - possibleValues: massValues, - }, - migrationState, - webShortname: "h", - }, - ); - const postalCodePropertyType = await text( "Postal Code", "A code used by postal services to identify a geographic area for sorting and delivery of mail.", @@ -408,11 +446,6 @@ const migrate: MigrationFunction = async ({ "Customer Reference", "A reference provided by the customer, such as their own purchase order number.", ); - const referenceNumberPropertyType = await text( - "Reference Number", - "An external reference number associated with a document.", - ); - const salesOrganizationPropertyType = await text( "Sales Organization", "The organizational unit responsible for selling goods or services.", @@ -434,10 +467,6 @@ const migrate: MigrationFunction = async ({ "Product Group", "A grouping of products for reporting or pricing.", ); - const itemCategoryGroupPropertyType = await text( - "Item Category Group", - "A grouping used to classify products for sales and pricing logic.", - ); const industryPropertyType = await text( "Industry", "An industry classification.", @@ -451,10 +480,6 @@ const migrate: MigrationFunction = async ({ "Storage Location", "A location within a facility where goods are stored.", ); - const storageBinPropertyType = await text( - "Storage Bin", - "A specific bin or position within a storage location.", - ); const batchNumberPropertyType = await text( "Batch Number", "A batch or lot identifier used for tracking goods.", @@ -463,10 +488,6 @@ const migrate: MigrationFunction = async ({ "Movement Type", "The type of a goods movement, such as a goods receipt, goods issue, or transfer.", ); - const movementCategoryPropertyType = await text( - "Movement Category", - "A broad category of goods movement.", - ); const debitCreditIndicatorPropertyType = await text( "Debit/Credit Indicator", "Indicates whether a posting is a debit or a credit.", @@ -513,10 +534,6 @@ const migrate: MigrationFunction = async ({ "Valuation Type", "The type or class of valuation, such as legal or group valuation.", ); - const valuationCategoryPropertyType = await text( - "Valuation Category", - "Indicates the split-valuation category of an item.", - ); const netValuePropertyType = await currency( "Net Value", @@ -530,20 +547,7 @@ const migrate: MigrationFunction = async ({ "Moving Average Price", "The current moving-average per-unit price of an item.", ); - const stockValuePropertyType = await currency( - "Stock Value", - "The total monetary value of stock on hand.", - ); - const futurePricePropertyType = await currency( - "Future Price", - "A validated future price of an item.", - ); - const postingPeriodPropertyType = await withDataType( - "Posting Period", - "An accounting period within a fiscal year.", - integerDataTypeId, - ); const fiscalYearPropertyType = await withDataType( "Fiscal Year", "The fiscal year to which data applies.", @@ -590,10 +594,6 @@ const migrate: MigrationFunction = async ({ "Posting Date", "The date on which a transaction was posted.", ); - const documentDatePropertyType = await date( - "Document Date", - "The date shown on a document.", - ); const scheduledStartDatePropertyType = await date( "Scheduled Start Date", "The date on which an activity is scheduled to start.", @@ -602,14 +602,6 @@ const migrate: MigrationFunction = async ({ "Actual Finish Date", "The date on which an activity actually finished.", ); - const lastPriceChangeDatePropertyType = await date( - "Last Price Change Date", - "The date on which a price was last changed.", - ); - const futurePriceDatePropertyType = await date( - "Future Price Date", - "The date on which a future price takes effect.", - ); const actualDepartureDatePropertyType = await date( "Actual Departure Date", "The actual date of departure of a shipment.", @@ -667,6 +659,22 @@ const migrate: MigrationFunction = async ({ "Maximum Lot Size", "The maximum lot size allowed when planning orders.", ); + const minimumLotSizePropertyType = await quantity( + "Minimum Lot Size", + "The minimum lot size allowed when planning orders.", + ); + const procurementTypePropertyType = await text( + "Procurement Type", + "How an item is procured, such as in-house production or external procurement.", + ); + const mrpControllerPropertyType = await text( + "MRP Controller", + "The planner responsible for material requirements planning of an item at a location.", + ); + const lotSizeProcedurePropertyType = await text( + "Lot Size Procedure", + "The procedure used to determine order lot sizes when planning replenishment.", + ); const link = (title: string, inverseTitle: string, description: string) => createSystemEntityTypeIfNotExists(context, authentication, { @@ -823,20 +831,15 @@ const migrate: MigrationFunction = async ({ title: "Material", titlePlural: "Materials", description: - "A good or material that can be produced, stored, sold, or procured — including raw materials, intermediates, and finished goods.", + "A good or material: a raw material, intermediate, or finished good.", labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, properties: [ { propertyType: blockProtocolPropertyTypes.name.propertyTypeId }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - }, { propertyType: identifierPropertyType }, { propertyType: productTypePropertyType }, { propertyType: productGroupPropertyType }, - { propertyType: itemCategoryGroupPropertyType }, - { propertyType: grossWeightPropertyType }, - { propertyType: netWeightPropertyType }, { propertyType: unitOfMeasurePropertyType }, + { propertyType: statusPropertyTypeId }, { propertyType: languagePropertyType }, ], }, @@ -858,10 +861,11 @@ const migrate: MigrationFunction = async ({ properties: [ { propertyType: blockProtocolPropertyTypes.name.propertyTypeId }, { propertyType: identifierPropertyType }, + { propertyType: streetAddressPropertyType }, { propertyType: cityPropertyTypeId }, + { propertyType: regionPropertyType }, + { propertyType: postalCodePropertyType }, { propertyType: countryPropertyType }, - { propertyType: storageLocationPropertyType }, - { propertyType: storageBinPropertyType }, ], }, migrationState, @@ -1093,10 +1097,6 @@ const migrate: MigrationFunction = async ({ linkEntityType: hasLineItemLink, destinationEntityTypes: [deliveryItemEntityType.schema.$id], }, - { - linkEntityType: fulfillsLink, - destinationEntityTypes: [salesOrderEntityType.schema.$id], - }, ], }, migrationState, @@ -1253,13 +1253,11 @@ const migrate: MigrationFunction = async ({ { propertyType: identifierPropertyType }, { propertyType: fiscalYearPropertyType }, { propertyType: movementTypePropertyType }, - { propertyType: movementCategoryPropertyType }, { propertyType: batchNumberPropertyType }, { propertyType: postingDatePropertyType }, - { propertyType: documentDatePropertyType }, - { propertyType: referenceNumberPropertyType }, { propertyType: movementQuantityPropertyType }, { propertyType: debitCreditIndicatorPropertyType }, + { propertyType: storageLocationPropertyType }, ], outgoingLinks: [ { @@ -1305,26 +1303,17 @@ const migrate: MigrationFunction = async ({ title: "Cost / Valuation", titlePlural: "Cost / Valuations", description: - "The cost and valuation of a material's stock — valuation prices, controls, and sourcing standard cost.", + "How a material is valued and costed: valuation prices and controls, plus sourcing standard cost.", properties: [ { propertyType: sitePropertyType }, { propertyType: standardCostPropertyType }, { propertyType: valuationClassPropertyType }, { propertyType: valuationAreaPropertyType }, { propertyType: valuationTypePropertyType }, - { propertyType: valuationCategoryPropertyType }, { propertyType: priceControlIndicatorPropertyType }, { propertyType: standardPricePropertyType }, { propertyType: movingAveragePricePropertyType }, - { propertyType: stockValuePropertyType }, - { propertyType: futurePricePropertyType }, { propertyType: priceUnitPropertyType }, - { propertyType: currencyCodePropertyType }, - { propertyType: stockQuantityPropertyType }, - { propertyType: postingPeriodPropertyType }, - { propertyType: fiscalYearPropertyType }, - { propertyType: lastPriceChangeDatePropertyType }, - { propertyType: futurePriceDatePropertyType }, ], outgoingLinks: [ { @@ -1348,8 +1337,12 @@ const migrate: MigrationFunction = async ({ "A material at a specific facility, with its plant-level planning parameters such as safety stock and lead times.", properties: [ { propertyType: planningMethodPropertyType }, + { propertyType: procurementTypePropertyType }, + { propertyType: mrpControllerPropertyType }, + { propertyType: lotSizeProcedurePropertyType }, { propertyType: statusPropertyTypeId }, { propertyType: safetyStockPropertyType }, + { propertyType: minimumLotSizePropertyType }, { propertyType: maximumLotSizePropertyType }, { propertyType: plannedDeliveryTimePropertyType }, { propertyType: goodsReceiptProcessingTimePropertyType }, From 3ba9d2f21b2e2b9185e1378517d4097a191ae4c6 Mon Sep 17 00:00:00 2001 From: Ahmad Sattar Date: Wed, 24 Jun 2026 13:22:00 +0200 Subject: [PATCH 3/5] fix format --- ...92-add-supply-chain-types.dev.migration.ts | 310 +++++++++++------- 1 file changed, 194 insertions(+), 116 deletions(-) diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts index ad4358fdf9e..f09004c527b 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts @@ -1,11 +1,10 @@ +import { versionedUrlFromComponents } from "@blockprotocol/type-system"; import { blockProtocolDataTypes, blockProtocolEntityTypes, blockProtocolPropertyTypes, } from "@local/hash-isomorphic-utils/ontology-type-ids"; -import { versionedUrlFromComponents } from "@blockprotocol/type-system"; - import { activeCurrencies } from "../currencies"; import { createSystemDataTypeIfNotExists, @@ -16,16 +15,18 @@ import { getCurrentHashPropertyTypeId, } from "../util"; -import type { BaseUrl, Conversions, VersionedUrl } from "@blockprotocol/type-system"; - import type { MigrationFunction } from "../types"; +import type { + BaseUrl, + Conversions, + VersionedUrl, +} from "@blockprotocol/type-system"; const migrate: MigrationFunction = async ({ context, authentication, migrationState, }) => { - const dateDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "date", migrationState, @@ -39,8 +40,19 @@ const migrate: MigrationFunction = async ({ migrationState, }); const lengthValues = ( - ["meters", "centimeters", "millimeters", "kilometers", "feet", "inches", "yards", "miles"] as const - ).map((dataTypeKey) => ({ dataTypeId: getCurrentHashDataTypeId({ dataTypeKey, migrationState }) })); + [ + "meters", + "centimeters", + "millimeters", + "kilometers", + "feet", + "inches", + "yards", + "miles", + ] as const + ).map((dataTypeKey) => ({ + dataTypeId: getCurrentHashDataTypeId({ dataTypeKey, migrationState }), + })); const currencyValues = activeCurrencies.map(({ code }) => { const baseUrl = generateSystemTypeBaseUrl({ kind: "data-type", @@ -175,7 +187,10 @@ const migrate: MigrationFunction = async ({ { dataTypeId: poundsDataType.schema.$id }, ]; - const convTo = (canonicalBaseUrl: BaseUrl, factor: number): Record => ({ + const convTo = ( + canonicalBaseUrl: BaseUrl, + factor: number, + ): Record => ({ [canonicalBaseUrl]: { from: { expression: ["/", "self", { const: factor, type: "number" }] }, to: { expression: ["*", "self", { const: factor, type: "number" }] }, @@ -200,122 +215,171 @@ const migrate: MigrationFunction = async ({ "Volume", "A measure of the three-dimensional space occupied by something.", ); - const litresDataType = await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: volumeDataType.schema.$id }], - title: "Litres", - description: "A metric unit of volume equal to one cubic decimetre.", - label: { right: "L" }, - type: "number", + const litresDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: volumeDataType.schema.$id }], + title: "Litres", + description: "A metric unit of volume equal to one cubic decimetre.", + label: { right: "L" }, + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", }, - conversions: {}, - migrationState, - webShortname: "h", - }); - const millilitresDataType = await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: volumeDataType.schema.$id }], - title: "Millilitres", - description: "A metric unit of volume equal to one thousandth of a litre.", - label: { right: "mL" }, - type: "number", + ); + const millilitresDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: volumeDataType.schema.$id }], + title: "Millilitres", + description: + "A metric unit of volume equal to one thousandth of a litre.", + label: { right: "mL" }, + type: "number", + }, + conversions: convTo(litresDataType.metadata.recordId.baseUrl, 0.001), + migrationState, + webShortname: "h", }, - conversions: convTo(litresDataType.metadata.recordId.baseUrl, 0.001), - migrationState, - webShortname: "h", - }); - const cubicMetresDataType = await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: volumeDataType.schema.$id }], - title: "Cubic Metres", - description: "A metric unit of volume equal to 1000 litres.", - label: { right: "m³" }, - type: "number", + ); + const cubicMetresDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: volumeDataType.schema.$id }], + title: "Cubic Metres", + description: "A metric unit of volume equal to 1000 litres.", + label: { right: "m³" }, + type: "number", + }, + conversions: convTo(litresDataType.metadata.recordId.baseUrl, 1000), + migrationState, + webShortname: "h", }, - conversions: convTo(litresDataType.metadata.recordId.baseUrl, 1000), - migrationState, - webShortname: "h", - }); + ); const areaDataType = await abstractMeasure( "Area", "A measure of the extent of a two-dimensional surface.", ); - const squareMetresDataType = await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: areaDataType.schema.$id }], - title: "Square Metres", - description: "A metric unit of area equal to a square one metre on each side.", - label: { right: "m²" }, - type: "number", + const squareMetresDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: areaDataType.schema.$id }], + title: "Square Metres", + description: + "A metric unit of area equal to a square one metre on each side.", + label: { right: "m²" }, + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", }, - conversions: {}, - migrationState, - webShortname: "h", - }); - const squareCentimetresDataType = await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: areaDataType.schema.$id }], - title: "Square Centimetres", - description: "A metric unit of area equal to one ten-thousandth of a square metre.", - label: { right: "cm²" }, - type: "number", + ); + const squareCentimetresDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: areaDataType.schema.$id }], + title: "Square Centimetres", + description: + "A metric unit of area equal to one ten-thousandth of a square metre.", + label: { right: "cm²" }, + type: "number", + }, + conversions: convTo( + squareMetresDataType.metadata.recordId.baseUrl, + 0.0001, + ), + migrationState, + webShortname: "h", }, - conversions: convTo(squareMetresDataType.metadata.recordId.baseUrl, 0.0001), - migrationState, - webShortname: "h", - }); - const squareFeetDataType = await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: areaDataType.schema.$id }], - title: "Square Feet", - description: "An imperial unit of area equal to a square one foot on each side.", - label: { right: "ft²" }, - type: "number", + ); + const squareFeetDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: areaDataType.schema.$id }], + title: "Square Feet", + description: + "An imperial unit of area equal to a square one foot on each side.", + label: { right: "ft²" }, + type: "number", + }, + conversions: convTo( + squareMetresDataType.metadata.recordId.baseUrl, + 0.09290304, + ), + migrationState, + webShortname: "h", }, - conversions: convTo(squareMetresDataType.metadata.recordId.baseUrl, 0.09290304), - migrationState, - webShortname: "h", - }); + ); - const durationDataType = await abstractMeasure("Duration", "A measure of elapsed time."); - const hoursDataType = await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: durationDataType.schema.$id }], - title: "Hours", - description: "A unit of time equal to 60 minutes.", - label: { right: "h" }, - type: "number", + const durationDataType = await abstractMeasure( + "Duration", + "A measure of elapsed time.", + ); + const hoursDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: durationDataType.schema.$id }], + title: "Hours", + description: "A unit of time equal to 60 minutes.", + label: { right: "h" }, + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", }, - conversions: {}, - migrationState, - webShortname: "h", - }); - const daysDataType = await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: durationDataType.schema.$id }], - title: "Days", - description: "A unit of time equal to 24 hours.", - label: { right: "d" }, - type: "number", + ); + const daysDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: durationDataType.schema.$id }], + title: "Days", + description: "A unit of time equal to 24 hours.", + label: { right: "d" }, + type: "number", + }, + conversions: convTo(hoursDataType.metadata.recordId.baseUrl, 24), + migrationState, + webShortname: "h", }, - conversions: convTo(hoursDataType.metadata.recordId.baseUrl, 24), - migrationState, - webShortname: "h", - }); + ); - const unitDataType = await createSystemDataTypeIfNotExists(context, authentication, { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], - title: "Unit", - description: - "A dimensionless quantity: a count of discrete items, or an amount whose unit of measure has no dedicated data type.", - type: "number", + const unitDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + title: "Unit", + description: + "A dimensionless quantity: a count of discrete items, or an amount whose unit of measure has no dedicated data type.", + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", }, - conversions: {}, - migrationState, - webShortname: "h", - }); + ); const quantityUnitValues = [ ...massValues, @@ -392,14 +456,22 @@ const migrate: MigrationFunction = async ({ const quantity = (title: string, description: string) => createSystemPropertyTypeIfNotExists(context, authentication, { - propertyTypeDefinition: { title, description, possibleValues: quantityUnitValues }, + propertyTypeDefinition: { + title, + description, + possibleValues: quantityUnitValues, + }, migrationState, webShortname: "h", }); const currency = (title: string, description: string) => createSystemPropertyTypeIfNotExists(context, authentication, { - propertyTypeDefinition: { title, description, possibleValues: currencyValues }, + propertyTypeDefinition: { + title, + description, + possibleValues: currencyValues, + }, migrationState, webShortname: "h", }); @@ -1184,8 +1256,10 @@ const migrate: MigrationFunction = async ({ }, ); - const productionOrderItemEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const productionOrderItemEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { title: "Production Order Item", titlePlural: "Production Order Items", @@ -1207,7 +1281,8 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); const productionOrderEntityType = await createSystemEntityTypeIfNotExists( context, @@ -1328,8 +1403,10 @@ const migrate: MigrationFunction = async ({ }, ); - const _materialLocationEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const _materialLocationEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { title: "Material Location", titlePlural: "Material Locations", @@ -1363,7 +1440,8 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); const _materialReservationEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { From c79ded4cc6768e2eee9a1f1e1beb97608dc93325 Mon Sep 17 00:00:00 2001 From: Ahmad Sattar Date: Thu, 25 Jun 2026 12:08:44 +0200 Subject: [PATCH 4/5] Split links out, add icons --- ...92-add-supply-chain-types.dev.migration.ts | 708 +++++++++++++++--- .../public/icons/types/arrows-rotate.svg | 1 + apps/hash-frontend/public/icons/types/box.svg | 1 + .../public/icons/types/boxes-packing.svg | 1 + .../public/icons/types/boxes-stacked.svg | 1 + .../public/icons/types/building.svg | 1 + .../public/icons/types/calendar-days.svg | 1 + .../public/icons/types/clipboard-check.svg | 1 + .../public/icons/types/clipboard-list.svg | 1 + .../public/icons/types/coins.svg | 1 + .../icons/types/file-invoice-dollar.svg | 1 + .../public/icons/types/file-invoice.svg | 1 + .../public/icons/types/handshake.svg | 1 + .../public/icons/types/industry.svg | 1 + .../public/icons/types/list-ol.svg | 1 + .../public/icons/types/list-tree.svg | 1 + .../public/icons/types/receipt.svg | 1 + .../public/icons/types/truck-container.svg | 1 + .../public/icons/types/truck-ramp-box.svg | 1 + .../public/icons/types/truck.svg | 1 + .../public/icons/types/user-tag.svg | 1 + .../public/icons/types/warehouse.svg | 1 + 22 files changed, 606 insertions(+), 123 deletions(-) create mode 100644 apps/hash-frontend/public/icons/types/arrows-rotate.svg create mode 100644 apps/hash-frontend/public/icons/types/box.svg create mode 100644 apps/hash-frontend/public/icons/types/boxes-packing.svg create mode 100644 apps/hash-frontend/public/icons/types/boxes-stacked.svg create mode 100644 apps/hash-frontend/public/icons/types/building.svg create mode 100644 apps/hash-frontend/public/icons/types/calendar-days.svg create mode 100644 apps/hash-frontend/public/icons/types/clipboard-check.svg create mode 100644 apps/hash-frontend/public/icons/types/clipboard-list.svg create mode 100644 apps/hash-frontend/public/icons/types/coins.svg create mode 100644 apps/hash-frontend/public/icons/types/file-invoice-dollar.svg create mode 100644 apps/hash-frontend/public/icons/types/file-invoice.svg create mode 100644 apps/hash-frontend/public/icons/types/handshake.svg create mode 100644 apps/hash-frontend/public/icons/types/industry.svg create mode 100644 apps/hash-frontend/public/icons/types/list-ol.svg create mode 100644 apps/hash-frontend/public/icons/types/list-tree.svg create mode 100644 apps/hash-frontend/public/icons/types/receipt.svg create mode 100644 apps/hash-frontend/public/icons/types/truck-container.svg create mode 100644 apps/hash-frontend/public/icons/types/truck-ramp-box.svg create mode 100644 apps/hash-frontend/public/icons/types/truck.svg create mode 100644 apps/hash-frontend/public/icons/types/user-tag.svg create mode 100644 apps/hash-frontend/public/icons/types/warehouse.svg diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts index f09004c527b..551a53867db 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts @@ -39,6 +39,10 @@ const migrate: MigrationFunction = async ({ dataTypeKey: "percentage", migrationState, }); + const integerDataTypeId = getCurrentHashDataTypeId({ + dataTypeKey: "integer", + migrationState, + }); const lengthValues = ( [ "meters", @@ -432,6 +436,36 @@ const migrate: MigrationFunction = async ({ webShortname: "h", }); + const grossWeightPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { + propertyTypeDefinition: { + title: "Gross Weight", + description: + "The total weight of an object including its packaging or container.", + possibleValues: massValues, + }, + migrationState, + webShortname: "h", + }, + ); + + const netWeightPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { + propertyTypeDefinition: { + title: "Net Weight", + description: + "The weight of an object excluding its packaging or container.", + possibleValues: massValues, + }, + migrationState, + webShortname: "h", + }, + ); + const postalCodePropertyType = await text( "Postal Code", "A code used by postal services to identify a geographic area for sorting and delivery of mail.", @@ -494,9 +528,17 @@ const migrate: MigrationFunction = async ({ "The number identifying a delivery schedule line within a document item.", ); - const orderTypePropertyType = await text( - "Order Type", - "The category of an order, such as a standard order, returns, or a quotation.", + const salesDocumentTypePropertyType = await text( + "Sales Document Type", + "The sales document type, such as an order, return, or quotation.", + ); + const purchasingDocumentTypePropertyType = await text( + "Purchasing Document Type", + "The purchasing document type, such as a standard purchase order or scheduling agreement.", + ); + const productionOrderTypePropertyType = await text( + "Production Order Type", + "The production order type.", ); const deliveryTypePropertyType = await text( "Delivery Type", @@ -518,10 +560,68 @@ const migrate: MigrationFunction = async ({ "Customer Reference", "A reference provided by the customer, such as their own purchase order number.", ); + const referenceNumberPropertyType = await text( + "Reference Number", + "An external reference number associated with a document.", + ); + const materialDocumentNumberPropertyType = await text( + "Material Document Number", + "A number identifying a material document.", + ); + + /** + * @todo maybe we don't need distinct item numbers + */ + const materialDocumentItemPropertyType = await text( + /** Should this just be "Item Number"? */ + "Material Document Item", + "An item number within document.", + ); + const purchaseOrderNumberPropertyType = await text( + "Purchase Order Number", + "The purchase order number.", + ); + const purchaseOrderItemNumberPropertyType = await text( + "Purchase Order Item Number", + "The item number within a purchase order.", + ); + const productionOrderNumberPropertyType = await text( + "Production Order Number", + "The production order number.", + ); + const deliveryNumberPropertyType = await text( + "Delivery Number", + "The delivery document number.", + ); + const deliveryItemNumberPropertyType = await text( + "Delivery Item Number", + "The item number within a delivery document.", + ); + const shipmentNumberPropertyType = await text( + "Shipment Number", + "The shipment or transport document number.", + ); + const vendorNumberPropertyType = await text( + "Vendor Number", + "The vendor account number.", + ); + const customerNumberPropertyType = await text( + "Customer Number", + "The customer account number.", + ); + const salesOrganizationPropertyType = await text( "Sales Organization", "The organizational unit responsible for selling goods or services.", ); + const purchasingOrganizationPropertyType = await text( + "Purchasing Organization", + "The organizational unit responsible for purchasing goods or services.", + ); + const purchasingGroupPropertyType = await text( + "Purchasing Group", + "The buyer or group responsible for purchasing activity.", + ); const distributionChannelPropertyType = await text( "Distribution Channel", "The channel through which goods or services reach the customer.", @@ -531,13 +631,33 @@ const migrate: MigrationFunction = async ({ "A product line or business division within an organization.", ); - const productTypePropertyType = await text( - "Product Type", - "The category of a product, such as finished good, raw material, or service.", + const materialNumberPropertyType = await text( + "Material Number", + "The material number.", + ); + const materialTypePropertyType = await text( + "Material Type", + "The material type, such as finished good, raw material, or service.", + ); + const materialGroupPropertyType = await text( + "Material Group", + "A grouping of materials for reporting, purchasing, or pricing.", + ); + const itemCategoryGroupPropertyType = await text( + "Item Category Group", + "A grouping used to classify materials for sales and pricing logic.", ); - const productGroupPropertyType = await text( - "Product Group", - "A grouping of products for reporting or pricing.", + const procurementTypePropertyType = await text( + "Procurement Type", + "The procurement type for a material, such as in-house production or external procurement.", + ); + const mrpTypePropertyType = await text( + "MRP Type", + "The MRP procedure used to plan a material.", + ); + const mrpControllerPropertyType = await text( + "MRP Controller", + "The person or group responsible for material requirements planning.", ); const industryPropertyType = await text( "Industry", @@ -550,7 +670,31 @@ const migrate: MigrationFunction = async ({ const storageLocationPropertyType = await text( "Storage Location", - "A location within a facility where goods are stored.", + "A location within a site where goods are stored.", + ); + const storageBinPropertyType = await text( + "Storage Bin", + "A specific bin or position within a storage location.", + ); + const siteCodePropertyType = await text( + "Site Code", + "A code identifying a site, facility, plant etc.", + ); + const siteTypePropertyType = await text( + "Site Type", + "The type of site, such as a production plant, warehouse, or distribution hub.", + ); + const shippingPointPropertyType = await text( + "Shipping Point", + "The shipping point responsible for outbound delivery processing.", + ); + const routePropertyType = await text( + "Route", + "The transport route or route code.", + ); + const incotermsPropertyType = await text( + "Incoterms", + "The Incoterms rule and location for a sales or delivery document.", ); const batchNumberPropertyType = await text( "Batch Number", @@ -560,6 +704,14 @@ const migrate: MigrationFunction = async ({ "Movement Type", "The type of a goods movement, such as a goods receipt, goods issue, or transfer.", ); + const movementCategoryPropertyType = await text( + "Movement Category", + "A broad category of goods movement.", + ); + const stockTypePropertyType = await text( + "Stock Type", + "The stock category or inspection/blocking status for inventory.", + ); const debitCreditIndicatorPropertyType = await text( "Debit/Credit Indicator", "Indicates whether a posting is a debit or a credit.", @@ -568,11 +720,43 @@ const migrate: MigrationFunction = async ({ "Leg Indicator", "An indicator describing a leg of a transport route.", ); + const bomNumberPropertyType = await text( + "BOM Number", + "The bill of materials number.", + ); + const alternativeBomPropertyType = await text( + "Alternative BOM", + "The alternative bill of materials identifier.", + ); + const bomCategoryPropertyType = await text( + "BOM Category", + "The BOM category, such as material BOM.", + ); + const bomStatusPropertyType = await text( + "BOM Status", + "The status of a bill of materials, such as active or inactive.", + ); + const deletionIndicatorPropertyType = await text( + "Deletion Indicator", + "Indicates whether a source-system record is marked for deletion.", + ); + const itemCategoryPropertyType = await text( + "Item Category", + "The item category for a line item or BOM component.", + ); + const fixedQuantityIndicatorPropertyType = await text( + "Fixed Quantity Indicator", + "Indicates whether a component quantity is fixed rather than scaled by order quantity.", + ); const planningMethodPropertyType = await text( "Planning Method", "The method used to plan replenishment of an item.", ); + const lotSizeProcedurePropertyType = await text( + "Lot Size Procedure", + "The procedure used to determine order lot sizes when planning replenishment.", + ); const plannedDeliveryTimePropertyType = await num( "Planned Delivery Time", "The planned lead time to procure or deliver an item, in days.", @@ -585,6 +769,22 @@ const migrate: MigrationFunction = async ({ "In-House Production Time", "The time required for in-house production, in days.", ); + const minimumLotSizePropertyType = await quantity( + "Minimum Lot Size", + "The minimum lot size allowed when planning orders.", + ); + const fixedLotSizePropertyType = await quantity( + "Fixed Lot Size", + "The fixed lot size used when planning orders.", + ); + const roundingValuePropertyType = await quantity( + "Rounding Value", + "The quantity increment to which planned procurement or production is rounded.", + ); + const reorderPointPropertyType = await quantity( + "Reorder Point", + "The stock level that triggers replenishment planning.", + ); const priceControlIndicatorPropertyType = await text( "Price Control Indicator", @@ -606,6 +806,10 @@ const migrate: MigrationFunction = async ({ "Valuation Type", "The type or class of valuation, such as legal or group valuation.", ); + const valuationCategoryPropertyType = await text( + "Valuation Category", + "Indicates the split-valuation category of an item.", + ); const netValuePropertyType = await currency( "Net Value", @@ -619,7 +823,20 @@ const migrate: MigrationFunction = async ({ "Moving Average Price", "The current moving-average per-unit price of an item.", ); + const stockValuePropertyType = await currency( + "Stock Value", + "The total monetary value of stock on hand.", + ); + const futurePricePropertyType = await currency( + "Future Price", + "A validated future price of an item.", + ); + const postingPeriodPropertyType = await withDataType( + "Posting Period", + "An accounting period within a fiscal year.", + integerDataTypeId, + ); const fiscalYearPropertyType = await withDataType( "Fiscal Year", "The fiscal year to which data applies.", @@ -642,13 +859,13 @@ const migrate: MigrationFunction = async ({ "Requested Delivery Date", "The delivery date requested by the customer.", ); - const deliveryDatePropertyType = await date( - "Delivery Date", - "The date on which delivery is scheduled or expected.", + const scheduledDeliveryDatePropertyType = await date( + "Scheduled Delivery Date", + "The date on which delivery is scheduled or promised.", ); - const statisticalDeliveryDatePropertyType = await date( - "Statistical Delivery Date", - "A delivery date used for statistical reporting.", + const statisticsRelevantDeliveryDatePropertyType = await date( + "Statistics-Relevant Delivery Date", + "A delivery date used for vendor evaluation or statistical reporting.", ); const plannedGoodsIssueDatePropertyType = await date( "Planned Goods Issue Date", @@ -666,14 +883,50 @@ const migrate: MigrationFunction = async ({ "Posting Date", "The date on which a transaction was posted.", ); + const documentDatePropertyType = await date( + "Document Date", + "The date shown on a document.", + ); const scheduledStartDatePropertyType = await date( "Scheduled Start Date", "The date on which an activity is scheduled to start.", ); + const scheduledFinishDatePropertyType = await date( + "Scheduled Finish Date", + "The date on which an activity is scheduled to finish.", + ); + const actualStartDatePropertyType = await date( + "Actual Start Date", + "The date on which an activity actually started.", + ); const actualFinishDatePropertyType = await date( "Actual Finish Date", "The date on which an activity actually finished.", ); + const releaseDatePropertyType = await date( + "Release Date", + "The date on which an order or document was released.", + ); + const validFromDatePropertyType = await date( + "Valid From Date", + "The date from which a source-system record is valid.", + ); + const creationDatePropertyType = await date( + "Creation Date", + "The date on which a source-system record was created.", + ); + const lastChangeDatePropertyType = await date( + "Last Change Date", + "The date on which a source-system record was last changed.", + ); + const lastPriceChangeDatePropertyType = await date( + "Last Price Change Date", + "The date on which a price was last changed.", + ); + const futurePriceDatePropertyType = await date( + "Future Price Date", + "The date on which a future price takes effect.", + ); const actualDepartureDatePropertyType = await date( "Actual Departure Date", "The actual date of departure of a shipment.", @@ -690,15 +943,31 @@ const migrate: MigrationFunction = async ({ "Planned Shipment End Date", "The planned end date of a shipment.", ); + const plannedArrivalDatePropertyType = await date( + "Planned Arrival Date", + "The planned date on which a shipment arrives.", + ); + const actualArrivalDatePropertyType = await date( + "Actual Arrival Date", + "The actual date on which a shipment arrived.", + ); const deliveredQuantityPropertyType = await quantity( "Delivered Quantity", "The quantity actually delivered.", ); + const scheduledQuantityPropertyType = await quantity( + "Scheduled Quantity", + "The quantity scheduled for delivery.", + ); const orderQuantityPropertyType = await quantity( "Order Quantity", "The quantity ordered.", ); + const componentQuantityPropertyType = await quantity( + "Component Quantity", + "The quantity of a component required by a bill of materials.", + ); const requirementQuantityPropertyType = await quantity( "Requirement Quantity", "The quantity required.", @@ -731,28 +1000,18 @@ const migrate: MigrationFunction = async ({ "Maximum Lot Size", "The maximum lot size allowed when planning orders.", ); - const minimumLotSizePropertyType = await quantity( - "Minimum Lot Size", - "The minimum lot size allowed when planning orders.", - ); - const procurementTypePropertyType = await text( - "Procurement Type", - "How an item is procured, such as in-house production or external procurement.", - ); - const mrpControllerPropertyType = await text( - "MRP Controller", - "The planner responsible for material requirements planning of an item at a location.", - ); - const lotSizeProcedurePropertyType = await text( - "Lot Size Procedure", - "The procedure used to determine order lot sizes when planning replenishment.", - ); - const link = (title: string, inverseTitle: string, description: string) => + const link = ( + title: string, + inverseTitle: string, + description: string, + icon: string, + ) => createSystemEntityTypeIfNotExists(context, authentication, { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title, + icon, inverse: { title: inverseTitle }, description, }, @@ -763,72 +1022,117 @@ const migrate: MigrationFunction = async ({ const hasLineItemLink = await link( "Has Line Item", "Line Item Of", - "A line item belonging to this document.", + "A line item that something has.", + "/icons/types/list-ul.svg", ); const hasCustomerLink = await link( "Has Customer", "Customer For", - "The customer associated with this document.", + "A customer associated with something.", + "/icons/types/user-tag.svg", ); - const hasSupplierLink = await link( - "Has Supplier", - "Supplier For", - "The supplier associated with this document.", + const hasVendorLink = await link( + "Has Vendor", + "Vendor For", + "A vendor associated with something.", + "/icons/types/handshake.svg", ); - const hasProductLink = await link( - "Has Product", - "Product For", - "The product that this concerns.", + const hasMaterialLink = await link( + "Has Material", + "Material For", + "A material that something concerns.", + "/icons/types/box.svg", ); const fulfillsLink = await link( "Fulfills", "Fulfilled By", - "A preceding document or item that this one fulfills.", + "Something that something fulfills.", + "/icons/types/check-double.svg", ); const locatedAtLink = await link( "Located At", "Location For", - "The facility where this is located or takes place.", + "The site where something is located or takes place.", + "/icons/types/location-dot.svg", ); const producesLink = await link( "Produces", "Produced By", - "A material produced by this.", + "Something produced by something.", + "/icons/types/industry.svg", ); const consumesLink = await link( "Consumes", "Consumed By", - "A material consumed by this.", + "Something consumed by something.", + "/icons/types/arrow-down-to-bracket.svg", ); const procuresLink = await link( "Procures", "Procured By", - "A material procured by this.", + "Something procured by something.", + "/icons/types/cart-shopping.svg", ); const movesLink = await link( "Moves", "Moved By", - "A material moved by this.", + "Something moved by something.", + "/icons/types/arrows-turn-to-dots.svg", ); const ofMaterialLink = await link( "Of Material", - "Has Batch", - "The material this batch is of.", + "Makes up", + "The material that something is made up of.", + "/icons/types/link.svg", ); - const recordsBatchLink = await link( - "Records Batch", - "Recorded On", - "A batch recorded by this movement.", + + const recordsLink = await link( + "Records", + "Recorded By", + "Something recorded by something.", + "/icons/types/clipboard-list.svg", ); - const yieldsBatchLink = await link( - "Yields Batch", + const yieldsLink = await link( + "Yields", "Yielded By", - "A batch produced by this order.", - ); - const deliversBatchLink = await link( - "Delivers Batch", - "Delivered In", - "A batch delivered by this.", + "Something yielded by something.", + "/icons/types/boxes-packing.svg", + ); + const deliversLink = await link( + "Delivers", + "Delivered By", + "Something delivered by something.", + "/icons/types/truck-ramp-box.svg", + ); + const transportsLink = await link( + "Transports", + "Transported By", + "Something transported by something.", + "/icons/types/truck-container.svg", + ); + const departsFromLink = await link( + "Departs From", + "Departure For", + "Something from which something departs.", + "/icons/types/arrow-right-from-bracket.svg", + ); + const arrivesAtLink = await link( + "Arrives At", + "Arrival For", + "Something at which something arrives.", + "/icons/types/arrow-right-to-bracket.svg", + ); + const postedAgainstLink = await link( + "Posted Against", + "Has Posting", + "Something against which something is posted.", + "/icons/types/clipboard-check.svg", + ); + const referencesLink = await link( + "References", + "Referenced By", + "Something referenced by something.", + "/icons/types/file-lines.svg", ); const companyEntityType = await createSystemEntityTypeIfNotExists( @@ -838,8 +1142,9 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Company", titlePlural: "Companies", + icon: "/icons/types/building.svg", description: - "A business or legal entity engaged in commercial activity, such as a customer or supplier.", + "A business or legal entity engaged in commercial activity, such as a customer or vendor.", labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, properties: [ { @@ -865,8 +1170,10 @@ const migrate: MigrationFunction = async ({ allOf: [companyEntityType.schema.$id], title: "Customer", titlePlural: "Customers", + icon: "/icons/types/user-tag.svg", description: "A company that purchases goods or services.", properties: [ + { propertyType: customerNumberPropertyType }, { propertyType: streetAddressPropertyType }, { propertyType: cityPropertyTypeId }, { propertyType: regionPropertyType }, @@ -880,15 +1187,17 @@ const migrate: MigrationFunction = async ({ }, ); - const supplierEntityType = await createSystemEntityTypeIfNotExists( + const vendorEntityType = await createSystemEntityTypeIfNotExists( context, authentication, { entityTypeDefinition: { allOf: [companyEntityType.schema.$id], - title: "Supplier", - titlePlural: "Suppliers", + title: "Vendor", + titlePlural: "Vendors", + icon: "/icons/types/handshake.svg", description: "A company that provides goods or services.", + properties: [{ propertyType: vendorNumberPropertyType }], }, migrationState, webShortname: "h", @@ -902,14 +1211,28 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Material", titlePlural: "Materials", + icon: "/icons/types/box.svg", description: - "A good or material: a raw material, intermediate, or finished good.", + "A good or material that can be produced, stored, sold, or procured, including raw materials, intermediates, and finished goods.", labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, properties: [ { propertyType: blockProtocolPropertyTypes.name.propertyTypeId }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + }, + /** + * @todo replace identifier where we have added specific properties + */ { propertyType: identifierPropertyType }, - { propertyType: productTypePropertyType }, - { propertyType: productGroupPropertyType }, + { propertyType: materialNumberPropertyType }, + { propertyType: materialTypePropertyType }, + { propertyType: materialGroupPropertyType }, + { propertyType: procurementTypePropertyType }, + { propertyType: mrpControllerPropertyType }, + { propertyType: divisionPropertyType }, + { propertyType: itemCategoryGroupPropertyType }, + { propertyType: grossWeightPropertyType }, + { propertyType: netWeightPropertyType }, { propertyType: unitOfMeasurePropertyType }, { propertyType: statusPropertyTypeId }, { propertyType: languagePropertyType }, @@ -920,24 +1243,32 @@ const migrate: MigrationFunction = async ({ }, ); - const facilityEntityType = await createSystemEntityTypeIfNotExists( + const siteEntityType = await createSystemEntityTypeIfNotExists( context, authentication, { entityTypeDefinition: { - title: "Facility", - titlePlural: "Facilities", + title: "Site", + titlePlural: "Sites", + icon: "/icons/types/warehouse.svg", description: - "A physical site, such as a plant or warehouse, where goods are produced or stored.", + "A physical site, such as a plant, warehouse, or distribution hub, where goods are produced, stored, or shipped.", labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, properties: [ { propertyType: blockProtocolPropertyTypes.name.propertyTypeId }, { propertyType: identifierPropertyType }, + { propertyType: siteCodePropertyType }, + { propertyType: siteTypePropertyType }, + { propertyType: shippingPointPropertyType }, + { propertyType: purchasingOrganizationPropertyType }, + { propertyType: salesOrganizationPropertyType }, { propertyType: streetAddressPropertyType }, { propertyType: cityPropertyTypeId }, { propertyType: regionPropertyType }, { propertyType: postalCodePropertyType }, { propertyType: countryPropertyType }, + { propertyType: storageLocationPropertyType }, + { propertyType: storageBinPropertyType }, ], }, migrationState, @@ -957,14 +1288,15 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Batch", titlePlural: "Batches", + icon: "/icons/types/boxes-stacked.svg", description: "A specific lot of a material, tracked through production, storage, and movement.", - labelProperty: identifierPropertyType.metadata.recordId.baseUrl, + labelProperty: batchNumberPropertyType.metadata.recordId.baseUrl, properties: [ - { propertyType: identifierPropertyType }, + { propertyType: batchNumberPropertyType }, { propertyType: expiryDatePropertyType }, - { propertyType: stockQuantityPropertyType }, { propertyType: unitOfMeasurePropertyType }, + { propertyType: stockQuantityPropertyType }, ], outgoingLinks: [ { @@ -986,15 +1318,21 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Bill of Materials Item", titlePlural: "Bill of Materials Items", + icon: "/icons/types/list-ol.svg", description: "A component line within a bill of materials.", properties: [ { propertyType: itemNumberPropertyType }, - { propertyType: movementQuantityPropertyType }, + { propertyType: componentQuantityPropertyType }, + { propertyType: unitOfMeasurePropertyType }, + { propertyType: itemCategoryPropertyType }, { propertyType: scrapPercentagePropertyType }, + { propertyType: fixedQuantityIndicatorPropertyType }, + { propertyType: validFromDatePropertyType }, + { propertyType: deletionIndicatorPropertyType }, ], outgoingLinks: [ { - linkEntityType: hasProductLink, + linkEntityType: hasMaterialLink, destinationEntityTypes: [materialEntityType.schema.$id], }, ], @@ -1011,17 +1349,26 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Bill of Materials", titlePlural: "Bills of Materials", + icon: "/icons/types/list-tree.svg", description: - "A structured list of the components required to produce a product.", + "A structured list of the components required to produce a material.", labelProperty: identifierPropertyType.metadata.recordId.baseUrl, properties: [ { propertyType: identifierPropertyType }, + { propertyType: bomNumberPropertyType }, + { propertyType: alternativeBomPropertyType }, + { propertyType: bomCategoryPropertyType }, + { propertyType: bomStatusPropertyType }, + { propertyType: validFromDatePropertyType }, + { propertyType: deletionIndicatorPropertyType }, { propertyType: baseQuantityPropertyType }, { propertyType: unitOfMeasurePropertyType }, + { propertyType: creationDatePropertyType }, + { propertyType: lastChangeDatePropertyType }, ], outgoingLinks: [ { - linkEntityType: hasProductLink, + linkEntityType: hasMaterialLink, destinationEntityTypes: [materialEntityType.schema.$id], }, { @@ -1042,6 +1389,7 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Sales Order Item", titlePlural: "Sales Order Items", + icon: "/icons/types/receipt.svg", description: "A line item within a sales order.", properties: [ { propertyType: itemNumberPropertyType }, @@ -1052,12 +1400,12 @@ const migrate: MigrationFunction = async ({ ], outgoingLinks: [ { - linkEntityType: hasProductLink, + linkEntityType: hasMaterialLink, destinationEntityTypes: [materialEntityType.schema.$id], }, { linkEntityType: locatedAtLink, - destinationEntityTypes: [facilityEntityType.schema.$id], + destinationEntityTypes: [siteEntityType.schema.$id], }, ], }, @@ -1073,12 +1421,13 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Sales Order", titlePlural: "Sales Orders", + icon: "/icons/types/file-invoice-dollar.svg", description: "A commitment by a customer to purchase goods or services on agreed terms.", labelProperty: identifierPropertyType.metadata.recordId.baseUrl, properties: [ { propertyType: identifierPropertyType }, - { propertyType: orderTypePropertyType }, + { propertyType: salesDocumentTypePropertyType }, { propertyType: salesOrganizationPropertyType }, { propertyType: distributionChannelPropertyType }, { propertyType: divisionPropertyType }, @@ -1112,24 +1461,27 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Delivery Item", titlePlural: "Delivery Items", + icon: "/icons/types/truck-ramp-box.svg", description: "A line item within a delivery.", properties: [ { propertyType: itemNumberPropertyType }, + { propertyType: deliveryItemNumberPropertyType }, { propertyType: deliveredQuantityPropertyType }, + { propertyType: unitOfMeasurePropertyType }, { propertyType: batchNumberPropertyType }, ], outgoingLinks: [ { - linkEntityType: hasProductLink, + linkEntityType: hasMaterialLink, destinationEntityTypes: [materialEntityType.schema.$id], }, { - linkEntityType: deliversBatchLink, + linkEntityType: deliversLink, destinationEntityTypes: [batchEntityType.schema.$id], }, { linkEntityType: locatedAtLink, - destinationEntityTypes: [facilityEntityType.schema.$id], + destinationEntityTypes: [siteEntityType.schema.$id], }, { linkEntityType: fulfillsLink, @@ -1149,12 +1501,18 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Delivery", titlePlural: "Deliveries", - description: "An outbound shipment of goods against an order.", + icon: "/icons/types/truck.svg", + description: + "A logistics execution document for delivering goods against a sales order or transfer requirement.", labelProperty: identifierPropertyType.metadata.recordId.baseUrl, properties: [ { propertyType: identifierPropertyType }, + { propertyType: deliveryNumberPropertyType }, { propertyType: deliveryTypePropertyType }, - { propertyType: deliveryDatePropertyType }, + { propertyType: routePropertyType }, + { propertyType: shippingPointPropertyType }, + { propertyType: incotermsPropertyType }, + { propertyType: scheduledDeliveryDatePropertyType }, { propertyType: plannedGoodsIssueDatePropertyType }, { propertyType: actualGoodsIssueDatePropertyType }, { propertyType: pickingDatePropertyType }, @@ -1169,6 +1527,10 @@ const migrate: MigrationFunction = async ({ linkEntityType: hasLineItemLink, destinationEntityTypes: [deliveryItemEntityType.schema.$id], }, + { + linkEntityType: fulfillsLink, + destinationEntityTypes: [salesOrderEntityType.schema.$id], + }, ], }, migrationState, @@ -1181,12 +1543,13 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Purchase Order Schedule Line", titlePlural: "Purchase Order Schedule Lines", + icon: "/icons/types/calendar-days.svg", description: "A delivery schedule line within a purchase order item.", properties: [ { propertyType: scheduleLineNumberPropertyType }, - { propertyType: deliveryDatePropertyType }, - { propertyType: statisticalDeliveryDatePropertyType }, - { propertyType: orderQuantityPropertyType }, + { propertyType: scheduledDeliveryDatePropertyType }, + { propertyType: statisticsRelevantDeliveryDatePropertyType }, + { propertyType: scheduledQuantityPropertyType }, { propertyType: goodsReceiptQuantityPropertyType }, ], }, @@ -1201,8 +1564,15 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Purchase Order Item", titlePlural: "Purchase Order Items", + icon: "/icons/types/clipboard-list.svg", description: "A line item within a purchase order.", - properties: [{ propertyType: itemNumberPropertyType }], + properties: [ + { propertyType: itemNumberPropertyType }, + { propertyType: purchaseOrderItemNumberPropertyType }, + { propertyType: orderQuantityPropertyType }, + { propertyType: unitOfMeasurePropertyType }, + { propertyType: netValuePropertyType }, + ], outgoingLinks: [ { linkEntityType: procuresLink, @@ -1210,7 +1580,7 @@ const migrate: MigrationFunction = async ({ }, { linkEntityType: locatedAtLink, - destinationEntityTypes: [facilityEntityType.schema.$id], + destinationEntityTypes: [siteEntityType.schema.$id], }, { linkEntityType: hasLineItemLink, @@ -1232,17 +1602,24 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Purchase Order", titlePlural: "Purchase Orders", + icon: "/icons/types/file-invoice.svg", description: - "A commitment to purchase goods or services from a supplier on agreed terms.", + "A commitment to purchase goods or services from a vendor on agreed terms.", labelProperty: identifierPropertyType.metadata.recordId.baseUrl, properties: [ { propertyType: identifierPropertyType }, + { propertyType: purchaseOrderNumberPropertyType }, + { propertyType: purchasingDocumentTypePropertyType }, + { propertyType: purchasingOrganizationPropertyType }, + { propertyType: purchasingGroupPropertyType }, + { propertyType: currencyCodePropertyType }, + { propertyType: documentDatePropertyType }, { propertyType: orderDatePropertyType }, ], outgoingLinks: [ { - linkEntityType: hasSupplierLink, - destinationEntityTypes: [supplierEntityType.schema.$id], + linkEntityType: hasVendorLink, + destinationEntityTypes: [vendorEntityType.schema.$id], maxItems: 1, }, { @@ -1263,8 +1640,10 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Production Order Item", titlePlural: "Production Order Items", + icon: "/icons/types/gear.svg", description: "A line item within a production order.", properties: [ + { propertyType: itemNumberPropertyType }, { propertyType: productionQuantityPropertyType }, { propertyType: goodsReceiptQuantityPropertyType }, ], @@ -1275,7 +1654,7 @@ const migrate: MigrationFunction = async ({ }, { linkEntityType: locatedAtLink, - destinationEntityTypes: [facilityEntityType.schema.$id], + destinationEntityTypes: [siteEntityType.schema.$id], }, ], }, @@ -1291,11 +1670,18 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Production Order", titlePlural: "Production Orders", - description: "An order to manufacture a product.", + icon: "/icons/types/industry.svg", + description: "An order to manufacture a material.", labelProperty: identifierPropertyType.metadata.recordId.baseUrl, properties: [ { propertyType: identifierPropertyType }, + { propertyType: productionOrderNumberPropertyType }, + { propertyType: productionOrderTypePropertyType }, + { propertyType: alternativeBomPropertyType }, + { propertyType: releaseDatePropertyType }, { propertyType: scheduledStartDatePropertyType }, + { propertyType: scheduledFinishDatePropertyType }, + { propertyType: actualStartDatePropertyType }, { propertyType: actualFinishDatePropertyType }, ], outgoingLinks: [ @@ -1304,7 +1690,7 @@ const migrate: MigrationFunction = async ({ destinationEntityTypes: [productionOrderItemEntityType.schema.$id], }, { - linkEntityType: yieldsBatchLink, + linkEntityType: yieldsLink, destinationEntityTypes: [batchEntityType.schema.$id], }, ], @@ -1314,25 +1700,40 @@ const migrate: MigrationFunction = async ({ }, ); - const _materialMovementEntityType = await createSystemEntityTypeIfNotExists( + const _materialDocumentEntityType = await createSystemEntityTypeIfNotExists( context, authentication, { entityTypeDefinition: { - title: "Material Movement", - titlePlural: "Material Movements", + title: "Material Document", + titlePlural: "Material Documents", + icon: "/icons/types/arrows-rotate.svg", description: - "A record of material moving into, out of, or within inventory, including consumption and receipt against orders.", + "A record of activity related to a material, for example movement, production or consumption.", labelProperty: identifierPropertyType.metadata.recordId.baseUrl, properties: [ { propertyType: identifierPropertyType }, + { propertyType: materialDocumentNumberPropertyType }, { propertyType: fiscalYearPropertyType }, + { propertyType: materialDocumentItemPropertyType }, { propertyType: movementTypePropertyType }, + { propertyType: movementCategoryPropertyType }, { propertyType: batchNumberPropertyType }, + { propertyType: stockTypePropertyType }, { propertyType: postingDatePropertyType }, + { propertyType: documentDatePropertyType }, + { propertyType: referenceNumberPropertyType }, { propertyType: movementQuantityPropertyType }, - { propertyType: debitCreditIndicatorPropertyType }, + { propertyType: unitOfMeasurePropertyType }, { propertyType: storageLocationPropertyType }, + { propertyType: debitCreditIndicatorPropertyType }, + { propertyType: purchaseOrderNumberPropertyType }, + { propertyType: purchaseOrderItemNumberPropertyType }, + { propertyType: productionOrderNumberPropertyType }, + { propertyType: deliveryNumberPropertyType }, + { propertyType: deliveryItemNumberPropertyType }, + { propertyType: customerNumberPropertyType }, + { propertyType: vendorNumberPropertyType }, ], outgoingLinks: [ { @@ -1340,18 +1741,27 @@ const migrate: MigrationFunction = async ({ destinationEntityTypes: [materialEntityType.schema.$id], }, { - linkEntityType: recordsBatchLink, + linkEntityType: recordsLink, destinationEntityTypes: [batchEntityType.schema.$id], }, { linkEntityType: locatedAtLink, - destinationEntityTypes: [facilityEntityType.schema.$id], + destinationEntityTypes: [siteEntityType.schema.$id], }, { - linkEntityType: fulfillsLink, + linkEntityType: postedAgainstLink, destinationEntityTypes: [ purchaseOrderItemEntityType.schema.$id, productionOrderEntityType.schema.$id, + deliveryItemEntityType.schema.$id, + ], + }, + { + linkEntityType: referencesLink, + destinationEntityTypes: [ + purchaseOrderItemEntityType.schema.$id, + productionOrderEntityType.schema.$id, + deliveryItemEntityType.schema.$id, ], }, ], @@ -1369,33 +1779,52 @@ const migrate: MigrationFunction = async ({ "Standard Cost", "The standard cost of an item.", ); + const valuatedStockQuantityPropertyType = await quantity( + "Valuated Stock Quantity", + "The quantity of stock to which a valuation applies.", + ); const _costValuationEntityType = await createSystemEntityTypeIfNotExists( context, authentication, { entityTypeDefinition: { - title: "Cost / Valuation", - titlePlural: "Cost / Valuations", + title: "Material Valuation", + titlePlural: "Material Valuations", + icon: "/icons/types/coins.svg", description: - "How a material is valued and costed: valuation prices and controls, plus sourcing standard cost.", + "The cost and valuation of a material's stock — valuation prices, controls, and sourcing standard cost.", properties: [ { propertyType: sitePropertyType }, { propertyType: standardCostPropertyType }, { propertyType: valuationClassPropertyType }, { propertyType: valuationAreaPropertyType }, { propertyType: valuationTypePropertyType }, + { propertyType: valuationCategoryPropertyType }, { propertyType: priceControlIndicatorPropertyType }, { propertyType: standardPricePropertyType }, { propertyType: movingAveragePricePropertyType }, + { propertyType: stockValuePropertyType }, + { propertyType: futurePricePropertyType }, { propertyType: priceUnitPropertyType }, + { propertyType: currencyCodePropertyType }, + { propertyType: valuatedStockQuantityPropertyType }, + { propertyType: postingPeriodPropertyType }, + { propertyType: fiscalYearPropertyType }, + { propertyType: lastPriceChangeDatePropertyType }, + { propertyType: futurePriceDatePropertyType }, ], outgoingLinks: [ { - linkEntityType: hasProductLink, + linkEntityType: hasMaterialLink, destinationEntityTypes: [materialEntityType.schema.$id], maxItems: 1, }, + { + linkEntityType: locatedAtLink, + destinationEntityTypes: [siteEntityType.schema.$id], + maxItems: 1, + }, ], }, migrationState, @@ -1408,32 +1837,37 @@ const migrate: MigrationFunction = async ({ authentication, { entityTypeDefinition: { - title: "Material Location", - titlePlural: "Material Locations", + title: "Site Material Data", + titlePlural: "Site Material Data", + icon: "/icons/types/warehouse.svg", description: - "A material at a specific facility, with its plant-level planning parameters such as safety stock and lead times.", + "A material at a specific site, with its site-level planning parameters such as safety stock, lot sizes, and lead times.", properties: [ { propertyType: planningMethodPropertyType }, - { propertyType: procurementTypePropertyType }, - { propertyType: mrpControllerPropertyType }, { propertyType: lotSizeProcedurePropertyType }, + { propertyType: mrpTypePropertyType }, + { propertyType: mrpControllerPropertyType }, + { propertyType: procurementTypePropertyType }, { propertyType: statusPropertyTypeId }, + { propertyType: reorderPointPropertyType }, { propertyType: safetyStockPropertyType }, { propertyType: minimumLotSizePropertyType }, { propertyType: maximumLotSizePropertyType }, + { propertyType: fixedLotSizePropertyType }, + { propertyType: roundingValuePropertyType }, { propertyType: plannedDeliveryTimePropertyType }, { propertyType: goodsReceiptProcessingTimePropertyType }, { propertyType: inHouseProductionTimePropertyType }, ], outgoingLinks: [ { - linkEntityType: hasProductLink, + linkEntityType: hasMaterialLink, destinationEntityTypes: [materialEntityType.schema.$id], maxItems: 1, }, { linkEntityType: locatedAtLink, - destinationEntityTypes: [facilityEntityType.schema.$id], + destinationEntityTypes: [siteEntityType.schema.$id], maxItems: 1, }, ], @@ -1448,11 +1882,15 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Material Reservation", titlePlural: "Material Reservations", + icon: "/icons/types/clipboard-check.svg", description: - "A reservation of a product as a component requirement, such as for a production order.", + "A reservation of a material as a component requirement, such as for a production order.", properties: [ + { propertyType: productionOrderNumberPropertyType }, + { propertyType: componentQuantityPropertyType }, { propertyType: requirementQuantityPropertyType }, { propertyType: withdrawnQuantityPropertyType }, + { propertyType: unitOfMeasurePropertyType }, { propertyType: debitCreditIndicatorPropertyType }, ], outgoingLinks: [ @@ -1462,7 +1900,7 @@ const migrate: MigrationFunction = async ({ }, { linkEntityType: locatedAtLink, - destinationEntityTypes: [facilityEntityType.schema.$id], + destinationEntityTypes: [siteEntityType.schema.$id], }, { linkEntityType: fulfillsLink, @@ -1481,13 +1919,17 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Shipment Item", titlePlural: "Shipment Items", + icon: "/icons/types/boxes-packing.svg", description: "A line within a shipment, linking it to a delivery being transported.", labelProperty: identifierPropertyType.metadata.recordId.baseUrl, - properties: [{ propertyType: identifierPropertyType }], + properties: [ + { propertyType: identifierPropertyType }, + { propertyType: deliveryNumberPropertyType }, + ], outgoingLinks: [ { - linkEntityType: fulfillsLink, + linkEntityType: transportsLink, destinationEntityTypes: [deliveryEntityType.schema.$id], }, ], @@ -1504,12 +1946,17 @@ const migrate: MigrationFunction = async ({ entityTypeDefinition: { title: "Shipment", titlePlural: "Shipments", + icon: "/icons/types/truck-container.svg", description: "The transport of goods, potentially grouping several deliveries.", labelProperty: identifierPropertyType.metadata.recordId.baseUrl, properties: [ { propertyType: identifierPropertyType }, + { propertyType: shipmentNumberPropertyType }, + { propertyType: routePropertyType }, { propertyType: actualDepartureDatePropertyType }, + { propertyType: plannedArrivalDatePropertyType }, + { propertyType: actualArrivalDatePropertyType }, { propertyType: actualShipmentCompletionDatePropertyType }, { propertyType: actualShipmentEndDatePropertyType }, { propertyType: plannedShipmentEndDatePropertyType }, @@ -1520,6 +1967,21 @@ const migrate: MigrationFunction = async ({ linkEntityType: hasLineItemLink, destinationEntityTypes: [shipmentItemEntityType.schema.$id], }, + { + linkEntityType: transportsLink, + destinationEntityTypes: [deliveryEntityType.schema.$id], + }, + { + linkEntityType: departsFromLink, + destinationEntityTypes: [siteEntityType.schema.$id], + }, + { + linkEntityType: arrivesAtLink, + destinationEntityTypes: [ + siteEntityType.schema.$id, + customerEntityType.schema.$id, + ], + }, ], }, migrationState, diff --git a/apps/hash-frontend/public/icons/types/arrows-rotate.svg b/apps/hash-frontend/public/icons/types/arrows-rotate.svg new file mode 100644 index 00000000000..a60b4793795 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/arrows-rotate.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/box.svg b/apps/hash-frontend/public/icons/types/box.svg new file mode 100644 index 00000000000..a72d7e33425 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/box.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/boxes-packing.svg b/apps/hash-frontend/public/icons/types/boxes-packing.svg new file mode 100644 index 00000000000..cd44379005f --- /dev/null +++ b/apps/hash-frontend/public/icons/types/boxes-packing.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/boxes-stacked.svg b/apps/hash-frontend/public/icons/types/boxes-stacked.svg new file mode 100644 index 00000000000..658a99aa40d --- /dev/null +++ b/apps/hash-frontend/public/icons/types/boxes-stacked.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/building.svg b/apps/hash-frontend/public/icons/types/building.svg new file mode 100644 index 00000000000..da6dd66efcc --- /dev/null +++ b/apps/hash-frontend/public/icons/types/building.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/calendar-days.svg b/apps/hash-frontend/public/icons/types/calendar-days.svg new file mode 100644 index 00000000000..608b3eba7e8 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/calendar-days.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/clipboard-check.svg b/apps/hash-frontend/public/icons/types/clipboard-check.svg new file mode 100644 index 00000000000..717ecc36d6e --- /dev/null +++ b/apps/hash-frontend/public/icons/types/clipboard-check.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/clipboard-list.svg b/apps/hash-frontend/public/icons/types/clipboard-list.svg new file mode 100644 index 00000000000..387b3d7dc75 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/clipboard-list.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/coins.svg b/apps/hash-frontend/public/icons/types/coins.svg new file mode 100644 index 00000000000..3c7fcef9bb2 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/coins.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/file-invoice-dollar.svg b/apps/hash-frontend/public/icons/types/file-invoice-dollar.svg new file mode 100644 index 00000000000..90016f6e407 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/file-invoice-dollar.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/file-invoice.svg b/apps/hash-frontend/public/icons/types/file-invoice.svg new file mode 100644 index 00000000000..1bff2085a05 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/file-invoice.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/handshake.svg b/apps/hash-frontend/public/icons/types/handshake.svg new file mode 100644 index 00000000000..42289fd02b4 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/handshake.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/industry.svg b/apps/hash-frontend/public/icons/types/industry.svg new file mode 100644 index 00000000000..de151dc1660 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/industry.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/list-ol.svg b/apps/hash-frontend/public/icons/types/list-ol.svg new file mode 100644 index 00000000000..37a82de04b7 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/list-ol.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/list-tree.svg b/apps/hash-frontend/public/icons/types/list-tree.svg new file mode 100644 index 00000000000..82203ad0791 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/list-tree.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/receipt.svg b/apps/hash-frontend/public/icons/types/receipt.svg new file mode 100644 index 00000000000..2ca5cc720a2 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/receipt.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/truck-container.svg b/apps/hash-frontend/public/icons/types/truck-container.svg new file mode 100644 index 00000000000..c554e355210 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/truck-container.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/truck-ramp-box.svg b/apps/hash-frontend/public/icons/types/truck-ramp-box.svg new file mode 100644 index 00000000000..d43b2f2efd3 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/truck-ramp-box.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/truck.svg b/apps/hash-frontend/public/icons/types/truck.svg new file mode 100644 index 00000000000..a2a7ba1c9e7 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/truck.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/user-tag.svg b/apps/hash-frontend/public/icons/types/user-tag.svg new file mode 100644 index 00000000000..be5b8706702 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/user-tag.svg @@ -0,0 +1 @@ + diff --git a/apps/hash-frontend/public/icons/types/warehouse.svg b/apps/hash-frontend/public/icons/types/warehouse.svg new file mode 100644 index 00000000000..fe89733f9e9 --- /dev/null +++ b/apps/hash-frontend/public/icons/types/warehouse.svg @@ -0,0 +1 @@ + From 625a8fee8d93d0639c99e45615373f15c68f8327 Mon Sep 17 00:00:00 2001 From: Ahmad Sattar Date: Thu, 25 Jun 2026 17:46:40 +0200 Subject: [PATCH 5/5] Add cubic feet --- ...92-add-supply-chain-types.dev.migration.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts index 551a53867db..e2cc886576a 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/092-add-supply-chain-types.dev.migration.ts @@ -268,6 +268,26 @@ const migrate: MigrationFunction = async ({ webShortname: "h", }, ); + const cubicFeetDataType = await createSystemDataTypeIfNotExists( + context, + authentication, + { + dataTypeDefinition: { + allOf: [{ $ref: volumeDataType.schema.$id }], + title: "Cubic Feet", + description: + "An imperial unit of volume equal to approximately 28.317 litres.", + label: { right: "ft³" }, + type: "number", + }, + conversions: convTo( + litresDataType.metadata.recordId.baseUrl, + 28.316846592, + ), + migrationState, + webShortname: "h", + }, + ); const areaDataType = await abstractMeasure( "Area", @@ -390,6 +410,7 @@ const migrate: MigrationFunction = async ({ { dataTypeId: litresDataType.schema.$id }, { dataTypeId: millilitresDataType.schema.$id }, { dataTypeId: cubicMetresDataType.schema.$id }, + { dataTypeId: cubicFeetDataType.schema.$id }, ...lengthValues, { dataTypeId: squareMetresDataType.schema.$id }, { dataTypeId: squareCentimetresDataType.schema.$id },