diff --git a/.changeset/chilled-pumas-exist.md b/.changeset/chilled-pumas-exist.md new file mode 100644 index 0000000000..a0ced18231 --- /dev/null +++ b/.changeset/chilled-pumas-exist.md @@ -0,0 +1,5 @@ +--- +'@hey-api/openapi-ts': patch +--- + +fix(parser): add `propertiesRequiredByDefault` transform option diff --git a/docs/openapi-ts/configuration/parser.md b/docs/openapi-ts/configuration/parser.md index a3684fcf51..f5416ab240 100644 --- a/docs/openapi-ts/configuration/parser.md +++ b/docs/openapi-ts/configuration/parser.md @@ -376,6 +376,40 @@ export default { You can customize the naming and casing pattern for `enums` schemas using the `.name` and `.case` options. +### Properties required by default + +By default, any object schema with a missing `required` keyword is interpreted as "no properties are required." This is the correct behavior according to the OpenAPI standard. However, some specifications interpret a missing `required` keyword as "all properties should be required." + +This option allows you to change the default behavior so that properties are required by default unless explicitly marked as optional. + +::: code-group + +```js [default] +export default { + input: 'hey-api/backend', // sign up at app.heyapi.dev + output: 'src/client', + parser: { + transforms: { + propertiesRequiredByDefault: false, // [!code ++] + }, + }, +}; +``` + +```js [required] +export default { + input: 'hey-api/backend', // sign up at app.heyapi.dev + output: 'src/client', + parser: { + transforms: { + propertiesRequiredByDefault: true, // [!code ++] + }, + }, +}; +``` + +::: + ### Read-write Your schemas might contain read-only or write-only fields. Using such schemas directly could mean asking the user to provide a read-only field in requests, or expecting a write-only field in responses. We separate schemas for requests and responses if direct usage would result in such scenarios. diff --git a/packages/openapi-ts-tests/main/test/3.0.x.test.ts b/packages/openapi-ts-tests/main/test/3.0.x.test.ts index e54398c806..50ba49b5e8 100644 --- a/packages/openapi-ts-tests/main/test/3.0.x.test.ts +++ b/packages/openapi-ts-tests/main/test/3.0.x.test.ts @@ -635,6 +635,19 @@ describe(`OpenAPI ${version}`, () => { }), description: 'transforms an array', }, + { + config: createConfig({ + input: 'dutchie.json', + output: 'transforms-properties-required-by-default', + parser: { + transforms: { + propertiesRequiredByDefault: true, + }, + }, + plugins: ['@hey-api/typescript'], + }), + description: 'makes all object properties required by default', + }, { config: createConfig({ input: 'type-invalid.json', diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/transforms-properties-required-by-default/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/transforms-properties-required-by-default/index.ts new file mode 100644 index 0000000000..b43a5238d8 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/transforms-properties-required-by-default/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type * from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/transforms-properties-required-by-default/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/transforms-properties-required-by-default/types.gen.ts new file mode 100644 index 0000000000..dc59ef1d46 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/transforms-properties-required-by-default/types.gen.ts @@ -0,0 +1,10410 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: `${string}://${string}` | 'https://api.pos.dutchie.com' | (string & {}); +}; + +export type Address = { + addressId: number | null; + customerId: number; + street: string | null; + street2: string | null; + city: string | null; + state: string | null; + postal_code: string | null; + country_Code: string | null; + latitude: number | null; + longitude: number | null; + county: string | null; + additionalStateIdentifiers: string | null; +}; + +export type AllocatedDeliveryItem = { + transactionId: number; + productName: string | null; + quantity: number; + totalPrice: number; + totalDiscount: number; + totalTax: number; +}; + +export type AllocatedPreOrderItem = { + productName: string | null; + quantity: number; + totalPrice: number; + totalDiscount: number; + totalTax: number; +}; + +/** + * Anonymous transaction response model containing transaction identifiers for guest checkout operations. + */ +export type AnonymousTransaction = { + /** + * Unique identifier for the customer record associated with this anonymous transaction. + */ + customerId: number; + /** + * Unique identifier for the transaction record. + */ + transactionId: number; + /** + * String representation of the unique identifier for API responses. + */ + readonly uniqueId: string | null; +}; + +/** + * Discount information applied to a specific transaction item in cannabis retail operations. + */ +export type AppliedDiscount = { + /** + * Unique identifier for the discount program or campaign applied. + */ + discountId: number; + /** + * Display name of the discount for customer receipts and reporting. + */ + discountName: string | null; + /** + * Reason or justification for the discount application (e.g., "Loyalty Reward", "Medical Patient"). + */ + discountReason: string | null; + /** + * Discount amount applied to the transaction item (in USD, positive value represents savings). + */ + amount: number; + /** + * Reference identifier linking this discount back to the specific transaction line item. + * Not guaranteed to be unique outside of a single transaction. + */ + readonly transactionItemId: number; +}; + +/** + * Request model for assigning existing cannabis plants to a specific plant group for batch management and cultivation workflow organization. + * + * **Plant Group Assignment:** + * - Assigns existing plants to target plant group using serial numbers + * - Supports batch organization for cultivation workflow management + * - Plants identified by serial numbers for precise assignment + * - Validates target plant group exists before assignment + * + * **Serial Number Identification:** + * - Plants identified by their unique serial numbers rather than IDs + * - All serial numbers must correspond to existing plants in the facility + * - Plants must be accessible to the authenticated location + * - Serial numbers must match exact plant tracking identifiers + * + * **Batch Management:** + * - Plant groups enable batch-based cultivation tracking and compliance + * - Supports harvest planning and cultivation scheduling optimization + * - Facilitates cultivation management and operational efficiency + */ +export type AssignPlantsToGroupRequest = { + /** + * Name of target plant group for batch organization and cultivation tracking + */ + plantGroupName: string | null; + /** + * Collection of plant serial numbers to assign to the specified plant group + */ + plantSerialNumbers: Array | null; +}; + +/** + * Field-specific validation error details for BadRequest responses. + */ +export type BadRequestPropertyError = { + /** + * Name of the property that failed validation. + */ + propertyName: string | null; + /** + * Description of the validation error for the specified property. + */ + propertyError: string | null; +}; + +/** + * Standardized error response model for HTTP 400 Bad Request responses across the API. + */ +export type BadRequestResponse = { + /** + * General error message describing the nature of the bad request. + */ + message: string | null; + /** + * Collection of field-specific validation errors for detailed feedback. + */ + propertyErrors: Array | null; +}; + +/** + * Detailed specification for creating individual immature plant batches with cultivation and compliance information. + */ +export type BatchDetails = { + /** + * Display name for the immature plant batch for identification and organization. + */ + batchName: string | null; + /** + * Plant type designation for the batch (e.g., "Seedling", "Clone", "Cutting"). + */ + plantType: string | null; + /** + * Number of plants in the immature batch for inventory tracking and compliance. + */ + plantCount: number; + /** + * Strain identifier for the cannabis strain being cultivated in this batch. + */ + strainId: number; + /** + * Room identifier for the immature batch location assignment. + */ + roomId: number; + /** + * Table identifier within the room for precise location tracking (optional). + */ + tableId: number | null; + /** + * Mother plant identifier for tracking genetic lineage (required for clone batches). + */ + motherPlantId: number | null; + /** + * Date when the immature batch was created for cultivation timeline documentation. + */ + dateCreated: string | null; +}; + +export type BooleanNullableOptional = boolean; + +export type BooleanOptional = boolean; + +export type Brand = { + brandId: number; + brandName: string | null; + brandCatalogBrandId: string | null; +}; + +export type BrandEditRequest = { + brandId: number | null; + brandName: string | null; +}; + +export type BroadcastedResponses = { + responses: Array | null; +}; + +export type BulkCreateOrUpdateHarvest = { + harvests: Array | null; +}; + +export type BulkCreateOrUpdateHarvestResponse = { + createdHarvestIds: Array | null; + updatedHarvestIds: Array | null; +}; + +export type BulkHarvestDetail = { + harvestId: number | null; + harvestName: string | null; + harvestRoomId: number; + harvestDate: string | null; + strainId: number; +}; + +export type CalculationMethod = 1 | 2 | 3 | 4 | 5 | 6 | 15; + +/** + * Request model for canceling existing customer pre-orders before fulfillment. + */ +export type CancelPreorderRequest = { + /** + * Unique identifier of the pre-order to be canceled. + */ + orderId: number; + /** + * Required reason for canceling the order (used for business analytics and customer service). + */ + cancellationReason: string | null; +}; + +/** + * Laboratory test result value model for cannabinoid and terpene measurements in cannabis products. + */ +export type CannabinoidTerpeneValue = { + /** + * Name of the laboratory test result (e.g., "THC", "CBD", "Limonene") - must match predefined compound list. + */ + labResultName: string; + /** + * Measured value of the compound in the cannabis sample (decimal precision for accurate reporting). + */ + value: number; + /** + * Unit identifier for the measurement (references LabResultUnit enum - mg/g, percentage, etc.). + */ + labResultUnitId: number; +}; + +export type CartItemPrice = { + productName: string | null; + productId: number; + quantity: number; + subtotal: number; + pricingTierAdjustment: number | null; + discounts: Array | null; + tax: number; +}; + +export type CartPrice = { + cartItemPrices: Array | null; + subTotal: number; + taxes: number; + discount: number; + total: number; + originalTotal: number; + roundedDifference: number; +}; + +/** + * Request model for updating the cultivation growth phase of cannabis plants to track development stages. + * + * **Growth Phase Management:** + * - Updates plant cultivation phase for proper development tracking + * - Supports bulk processing of multiple plants in single operation + * - Validates growth phase against allowed phase values + * - Automatically sets phase start date if not provided + * + * **Valid Growth Phases:** + * - `Propagation`: Initial plant development and cloning phase + * - `Vegetative`: Active vegetative growth before flowering initiation + * - `Flowering`: Reproductive growth phase leading to harvest + * + * **Phase Transition Rules:** + * - Phase start date defaults to current UTC time if not specified + * - Phase changes are logged for cultivation timeline tracking + * - Integration with external cultivation systems for environmental control + */ +export type ChangeGrowthPhaseRequest = { + /** + * Collection of LeafLogix plant IDs to update to the new growth phase + */ + plantIds: Array | null; + /** + * Target cultivation growth phase. Must be one of: `Propagation`, `Vegetative`, `Flowering` + */ + growthPhase: string | null; + /** + * Date when new growth phase begins (optional, defaults to current UTC time if not specified) + */ + phaseStartDate: string | null; +}; + +/** + * Product category sales summary for cannabis retail closing reports and financial analysis. + */ +export type ClosingReportCategorySummary = { + /** + * Product category name (e.g., "Flower", "Edibles", "Concentrates"). + */ + category: string | null; + /** + * Total net sales for the category (calculated property returning CategoryNetTotal). + */ + readonly categoryTotal: number; + /** + * Gross sales total for the category before discounts (in USD). + */ + categoryGrossTotal: number; + /** + * Total discount amount applied to products in this category (in USD). + */ + categoryDiscountTotal: number; + /** + * Net sales total for the category after discounts (in USD). + */ + categoryNetTotal: number; + /** + * Total cost of goods sold for products in this category (in USD). + */ + categoryCost: number; +}; + +/** + * Customer type sales summary for cannabis retail closing reports and customer segment analysis. + */ +export type ClosingReportCustomerTypeSummary = { + /** + * Customer type classification (e.g., "Recreational", "Medical", "Industry"). + */ + customerType: string | null; + /** + * Total net sales for this customer type (calculated property returning NetTotal). + */ + readonly total: number; + /** + * Gross sales total for this customer type before discounts (in USD). + */ + grossTotal: number; + /** + * Net sales total for this customer type after discounts (in USD). + */ + netTotal: number; + /** + * Total discount amount applied to this customer type (in USD). + */ + discountTotal: number; + /** + * Total cost of goods sold for this customer type (in USD). + */ + customerTypeCost: number; + /** + * Cannabis product sales total for this customer type (in USD). + */ + cannabisSales: number; + /** + * Non-cannabis product sales total for this customer type (accessories, etc.) (in USD). + */ + nonCannabisSales: number; +}; + +/** + * Order source sales summary for cannabis retail closing reports and marketing channel analysis. + */ +export type ClosingReportOrderSourceSummary = { + /** + * Order origination source (e.g., "Website", "Mobile App", "Weedmaps", "Walk-In"). + */ + orderSource: string | null; + /** + * Total net sales for this order source (calculated property returning NetTotal). + */ + readonly total: number; + /** + * Gross sales total for this order source before discounts (in USD). + */ + grossTotal: number; + /** + * Net sales total for this order source after discounts (in USD). + */ + netTotal: number; + /** + * Total discount amount applied to this order source (in USD). + */ + discountTotal: number; + orderSourceCost: number; +}; + +/** + * Order type sales summary for cannabis retail closing reports and fulfillment channel analysis. + */ +export type ClosingReportOrderTypeSummary = { + /** + * Order fulfillment type (e.g., "In-Store", "Pickup", "Delivery", "Curbside"). + */ + orderType: string | null; + /** + * Total net sales for this order type (calculated property returning NetTotal). + */ + readonly total: number; + /** + * Gross sales total for this order type before discounts (in USD). + */ + grossTotal: number; + /** + * Net sales total for this order type after discounts (in USD). + */ + netTotal: number; + /** + * Total discount amount applied to this order type (in USD). + */ + discountTotal: number; + /** + * Total cost of goods sold for this order type (in USD). + */ + orderTypeCost: number; +}; + +/** + * Pay-by-Bank batch file summary for cannabis payment processing reconciliation. + */ +export type ClosingReportPayByBankBatchFileSums = { + /** + * Batch file name for payment processor identification and tracking. + */ + batchFileName: string | null; + /** + * Adjustment amount for the batch file for financial reconciliation. + */ + payByBankBatchFileAdjustmentAmount: number; +}; + +/** + * Payment method summary for cannabis retail closing reports and financial reconciliation. + */ +export type ClosingReportPaymentSummary = { + /** + * Payment method type (e.g., "Cash", "Credit Card", "CanPay", "Hypur"). + */ + paymentType: string | null; + /** + * Total amount paid using this payment method (in USD). + */ + totalPaid: number; +}; + +/** + * Tax rate summary for cannabis retail closing reports and tax liability tracking. + */ +export type ClosingReportTaxRateSummary = { + /** + * Tax rate name or type (e.g., "State Excise Tax", "City Cannabis Tax", "Sales Tax"). + */ + taxRate: string | null; + /** + * Total tax amount collected for this tax rate (in USD). + */ + totalTax: number; +}; + +/** + * Enhanced closing report model for cannabis dispensary daily financial operations with payment processing integration. + */ +export type ClosingReportV2 = { + /** + * Total tips aggregated for the closing period for staff distribution. + */ + readonly totalTips: number | null; + /** + * Tips processed through Pay-by-Bank system for electronic tip distribution. + */ + payByBankTips: number; + /** + * Transaction fees charged by Pay-by-Bank system for cost accounting. + */ + payByBankTransactionFees: number; + /** + * Batch file summaries for Pay-by-Bank transaction reconciliation. + */ + payByBankBatchFile: Array | null; + /** + * Fees and donations collected during the closing period for compliance reporting. + */ + feesDonations: Array | null; + /** + * DutchiePay tips processed for cannabis payment integration. + */ + readonly dutchiePayTips: number | null; + /** + * DutchiePay transaction adjustments for cannabis payment processing. + */ + readonly dutchiePayTotalAdjustmentAmount: number | null; + /** + * DutchiePay batch file summaries for cannabis payment reconciliation. + */ + readonly dutchiePayBatchFileSums: Array | null; + grossSales: number | null; + discount: number | null; + loyalty: number | null; + totalTax: number | null; + cost: number | null; + coupons: number | null; + itemTotal: number | null; + transactionCount: number; + itemCount: number; + customerCount: number; + newCustomerCount: number; + voidCount: number; + voidTotal: number | null; + returnTotal: number | null; + startingBalance: number | null; + endingBalance: number | null; + deposits: number | null; + adjustments: number | null; + totalPayments: number | null; + invoiceTotal: number | null; + cannabisSales: number | null; + nonCannabisSales: number | null; + netSales: number | null; + revenueFeesDonations: number | null; + nonRevenueFeesDonations: number | null; + rounding: number | null; + totalIncome: number | null; + averageCartNetSales: number | null; + readonly overShort: number | null; + categorySummary: Array | null; + paymentSummary: Array | null; + taxSummary: Array | null; + customerTypeSummary: Array | null; + orderTypeSummary: Array | null; + orderSourceSummary: Array | null; +}; + +/** + * Detailed specification for converting individual plant batches during cultivation growth phase transitions. + */ +export type ConvertBatchDetails = { + /** + * Batch identifier for the plant batch being converted to mature growth phase. + */ + batchId: number; + /** + * Collection of individual plant serial numbers within the batch for state tracking compliance. + */ + serialNumbers: Array | null; + /** + * Target growth stage for the batch conversion (e.g., "Vegetative", "Flowering"). + */ + batchStage: string | null; + /** + * Destination room identifier for the converted batch location tracking. + */ + roomId: number; + /** + * Destination table identifier within the room for precise location tracking (optional). + */ + tableId: number | null; + /** + * Date when the batch conversion was performed for cultivation timeline documentation. + */ + dateCreated: string | null; +}; + +/** + * Request model for converting immature plant batches to mature growth phases in cannabis cultivation operations. + */ +export type ConvertImmatureBatchRequest = { + /** + * Collection of plant batches to be converted from immature to mature growth phases. + */ + batches: Array | null; +}; + +/** + * Response model for immature plant batch conversion operations containing converted mature plant identifiers. + */ +export type ConvertImmaturePlantResponse = { + /** + * Collection of mature plants created from immature batch conversion. + */ + convertedPlants: Array | null; +}; + +export type ConvertImmaturePlantResponseApiResult = { + result: boolean; + message: string | null; + data: ConvertImmaturePlantResponse; +}; + +/** + * Request model for creating anonymous transactions for guest customer operations. + */ +export type CreateAnonymousTransactionRequest = { + /** + * Optional reference identifier for the transaction (for external system integration). + */ + transactionReference: string | null; +}; + +/** + * Response model for immature plant batch creation operations containing created batch and plant identifiers. + */ +export type CreateImmaturePlantBatchResponse = { + /** + * Collection of created immature plant batches with associated plant identifiers. + */ + batches: Array | null; +}; + +export type CreateImmaturePlantBatchResponseApiResult = { + result: boolean; + message: string | null; + data: CreateImmaturePlantBatchResponse; +}; + +/** + * Request model for creating new customer journal entries with interaction details and notes. + */ +export type CreateJournalEntryRequest = { + /** + * The customer ID to create the journal entry for. + */ + customerId: number; + /** + * Brief title or summary of the journal entry. + */ + subject: string; + /** + * Detailed content and notes for the journal entry. + */ + body: string; + /** + * Date and time when the journal entry should be dated. + */ + date: string; +}; + +/** + * Request model for creating mature plant batches in cannabis cultivation operations. + */ +export type CreateMatureBatchRequest = { + /** + * Collection of mature plant batch specifications for bulk batch creation operations. + */ + batches: Array | null; +}; + +/** + * Response model for mature plant batch creation operations containing created mature plant identifiers. + */ +export type CreateMaturePlantsResponse = { + /** + * Collection of mature plants created ready for flowering phase cultivation. + */ + createdPlants: Array | null; +}; + +export type CreateMaturePlantsResponseApiResult = { + result: boolean; + message: string | null; + data: CreateMaturePlantsResponse; +}; + +export type CreateOrUpdateHarvest = { + harvestId: number | null; + harvestName: string | null; + strainName: string | null; + harvestRoomId: number; + harvestDate: string; +}; + +export type CreatePlantRequest = { + serialNumber: string | null; + plantGroupName: string | null; + growthPhase: string | null; + phaseStartDate: string | null; + dateCreated: string | null; + bornDate: string | null; + strain: string | null; + room: string | null; + table: string | null; + isMother: boolean; + bypassStateIntegration: boolean; +}; + +export type CreatePreOrderRequest = { + customerId: number; + items?: Array | null; + redemptions?: Array | null; + isDelivery?: boolean; + /** + * @deprecated + */ + orderSource?: string | null; + orderType?: string | null; + deliveryStreet?: string | null; + deliveryStreet2?: string | null; + deliveryCity?: string | null; + deliveryState?: string | null; + deliveryPostalCode?: string | null; + idempotencyKey?: string | null; + notes?: string | null; + status?: string | null; + transactionReference?: string | null; + timeWindowStartDateUtc?: string | null; + timeWindowEndDateUtc?: string | null; + deliveryScheduleId?: DeliveryScheduleType; +}; + +export type CreateUpdatePurchaseOrderItemRequest = { + productId: number; + unitId: Int32NullableOptional; + quantity: Int32NullableOptional; + subtotal: DecimalNullableOptional; + tax: DecimalNullableOptional; +}; + +export type CreateUpdatePurchaseOrderRequest = { + purchaseOrderId: number | null; + expectedArrivalDate: DateTimeNullableOptional; + title: StringOptional; + dateReceived: DateTimeNullableOptional; + shippingInformation: StringOptional; + vendorContact: StringOptional; + status: StringOptional; + vendorId: Int32NullableOptional; + purchaseOrderNumber: Int32NullableOptional; + purchaseOrderItems: Array | null; +}; + +export type CreateUpdatePurchaseOrderResponse = { + createdPurchaseOrderIds: Array | null; + updatedPurchaseOrderIds: Array | null; +}; + +export type CreateUpdatePurchaseOrdersRequest = { + purchaseOrders: Array | null; +}; + +/** + * Individual created immature plant batch containing batch identifier and associated plant IDs. + */ +export type CreatedImmaturePlantBatch = { + /** + * Unique identifier assigned to the created immature plant batch. + */ + batchId: number; + /** + * Collection of unique plant identifiers created within this batch. + */ + plantIds: Array | null; +}; + +export type CreatedMaturePlant = { + batchId: number; + plantId: number; + plantSerialNumber: string | null; +}; + +/** + * Represents a customer profile with personal information, contact details, and cannabis compliance data. + */ +export type Customer = { + /** + * Unique internal identifier for the customer record. + */ + customerId: number; + /** + * String representation of UniqueId for external API consumption. + */ + readonly uniqueId: string | null; + /** + * Deprecated name field (use FirstName and LastName instead). + * @deprecated + */ + name: string | null; + /** + * Customer's first name. + */ + firstName: string | null; + /** + * Customer's last name. + */ + lastName: string | null; + /** + * Customer's middle name. + */ + middleName: string | null; + /** + * Name suffix (Jr., Sr., III, etc.). + */ + nameSuffix: string | null; + /** + * Name prefix (Mr., Mrs., Dr., etc.). + */ + namePrefix: string | null; + /** + * Primary street address line. + */ + address1: string | null; + /** + * Secondary address line (apartment, suite, etc.). + */ + address2: string | null; + /** + * City name. + */ + city: string | null; + /** + * State or province. + */ + state: string | null; + /** + * Postal or ZIP code. + */ + postalCode: string | null; + /** + * Primary phone number. + */ + phone: string | null; + /** + * Cell phone number. + */ + cellPhone: string | null; + /** + * Email address. + */ + emailAddress: string | null; + /** + * Customer account status. + */ + status: string | null; + /** + * Medical marijuana identification number. + */ + mmjidNumber: string | null; + /** + * Medical marijuana ID expiration date. + */ + mmjidExpirationDate: string | null; + /** + * Last modification timestamp in UTC format. + */ + lastModifiedDateUTC: string | null; + /** + * Customer record creation date. + */ + creationDate: string | null; + /** + * Customer type classification. + */ + customerType: string | null; + /** + * Customer's gender. + */ + gender: string | null; + /** + * SHA2_256 hash of the Driver License ID + */ + driversLicenseHash: string | null; + /** + * Customer's date of birth. + */ + dateOfBirth: string | null; + /** + * External system customer identifier. + */ + externalCustomerId: string | null; + /** + * Name of the integration system that created this customer. + */ + createdByIntegrator: string | null; + /** + * Indicates if this is an anonymous customer record. + */ + isAnonymous: boolean; + /** + * How the customer heard about the dispensary. + */ + referralSource: string | null; + /** + * Additional details about referral source when "Other" is selected. + */ + otherReferralSource: string | null; + /** + * SpringBig loyalty system member identifier. + */ + springBigMemberId: number; + /** + * Custom identifier for external system integration. + */ + customIdentifier: string | null; + /** + * Collection of active discount groups for this customer. + */ + readonly discountGroups: Array | null; + /** + * Location where this customer record was created. + */ + createdAtLocation: string | null; + /** + * Additional notes about the customer. + */ + notes: string | null; + /** + * Indicates if customer is enrolled in loyalty program. + */ + isLoyaltyMember: boolean | null; + /** + * Primary medical condition for medical marijuana patients. + */ + primaryQualifyingCondition: string | null; + /** + * Additional medical conditions for medical marijuana patients. + */ + secondaryQualifyingConditions: Array | null; + /** + * Customer ID this record was merged into (if applicable). + */ + mergedIntoCustomerId: number | null; + /** + * Customer's marketing communication preference. + */ + optedIntoMarketing: boolean | null; + /** + * Customer's current loyalty program tier. + */ + loyaltyTier: string | null; +}; + +/** + * Search criteria model for customer lookup operations with flexible matching options. + */ +export type CustomerSearchRequest = { + /** + * Customer's last name for name-based search matching. + */ + lastName: string | null; + /** + * Customer's date of birth for identity verification and precise matching. + */ + dateOfBirth: string | null; + /** + * Customer's phone number for contact-based search matching. + */ + phone: string | null; + /** + * Customer's email address for account-based search matching. + */ + emailAddress: string | null; + /** + * Medical marijuana identification number for regulatory compliance search. + */ + mmjidNumber: string | null; + /** + * Driver's license identifier for government ID-based search matching. + */ + driversLicenseId: string | null; +}; + +/** + * Extended customer model that includes search match type information for customer lookup operations. + */ +export type CustomerSearchResult = { + /** + * Indicates how the customer record was matched during the search operation. + */ + matchType: string | null; + /** + * Unique internal identifier for the customer record. + */ + customerId: number; + /** + * String representation of UniqueId for external API consumption. + */ + readonly uniqueId: string | null; + /** + * Deprecated name field (use FirstName and LastName instead). + * @deprecated + */ + name: string | null; + /** + * Customer's first name. + */ + firstName: string | null; + /** + * Customer's last name. + */ + lastName: string | null; + /** + * Customer's middle name. + */ + middleName: string | null; + /** + * Name suffix (Jr., Sr., III, etc.). + */ + nameSuffix: string | null; + /** + * Name prefix (Mr., Mrs., Dr., etc.). + */ + namePrefix: string | null; + /** + * Primary street address line. + */ + address1: string | null; + /** + * Secondary address line (apartment, suite, etc.). + */ + address2: string | null; + /** + * City name. + */ + city: string | null; + /** + * State or province. + */ + state: string | null; + /** + * Postal or ZIP code. + */ + postalCode: string | null; + /** + * Primary phone number. + */ + phone: string | null; + /** + * Cell phone number. + */ + cellPhone: string | null; + /** + * Email address. + */ + emailAddress: string | null; + /** + * Customer account status. + */ + status: string | null; + /** + * Medical marijuana identification number. + */ + mmjidNumber: string | null; + /** + * Medical marijuana ID expiration date. + */ + mmjidExpirationDate: string | null; + /** + * Last modification timestamp in UTC format. + */ + lastModifiedDateUTC: string | null; + /** + * Customer record creation date. + */ + creationDate: string | null; + /** + * Customer type classification. + */ + customerType: string | null; + /** + * Customer's gender. + */ + gender: string | null; + /** + * SHA2_256 hash of the Driver License ID + */ + driversLicenseHash: string | null; + /** + * Customer's date of birth. + */ + dateOfBirth: string | null; + /** + * External system customer identifier. + */ + externalCustomerId: string | null; + /** + * Name of the integration system that created this customer. + */ + createdByIntegrator: string | null; + /** + * Indicates if this is an anonymous customer record. + */ + isAnonymous: boolean; + /** + * How the customer heard about the dispensary. + */ + referralSource: string | null; + /** + * Additional details about referral source when "Other" is selected. + */ + otherReferralSource: string | null; + /** + * SpringBig loyalty system member identifier. + */ + springBigMemberId: number; + /** + * Custom identifier for external system integration. + */ + customIdentifier: string | null; + /** + * Collection of active discount groups for this customer. + */ + readonly discountGroups: Array | null; + /** + * Location where this customer record was created. + */ + createdAtLocation: string | null; + /** + * Additional notes about the customer. + */ + notes: string | null; + /** + * Indicates if customer is enrolled in loyalty program. + */ + isLoyaltyMember: boolean | null; + /** + * Primary medical condition for medical marijuana patients. + */ + primaryQualifyingCondition: string | null; + /** + * Additional medical conditions for medical marijuana patients. + */ + secondaryQualifyingConditions: Array | null; + /** + * Customer ID this record was merged into (if applicable). + */ + mergedIntoCustomerId: number | null; + /** + * Customer's marketing communication preference. + */ + optedIntoMarketing: boolean | null; + /** + * Customer's current loyalty program tier. + */ + loyaltyTier: string | null; +}; + +/** + * Represents a customer type classification for cannabis dispensary operations and compliance. + */ +export type CustomerType = { + /** + * Unique identifier for the customer type. + */ + id: number; + /** + * Display name of the customer type. + */ + name: string | null; + /** + * Indicates whether this customer type is for medical marijuana patients. + */ + isMedical: boolean; + /** + * Indicates whether this customer type is for retail (adult-use) customers. + */ + isRetail: boolean; +}; + +export type DateTimeNullableOptional = string; + +export type DecimalNullableOptional = number; + +/** + * Request model for deleting a product image through the product image management API. + */ +export type DeleteImageRequest = { + /** + * The unique identifier of the product that owns the image to be deleted. + */ + productId: number; + /** + * The unique identifier of the specific image to be deleted from the product. + */ + imageId: number; +}; + +export type DeliveryOrderStatus = { + preOrderId: number | null; + transactionId: number; + status: string | null; + orderDate: string; + customerFirstName: string | null; + customerLastName: string | null; + customerId: number; + orderType: string | null; + orderSource: string | null; + rejectedReason: string | null; + total: number | null; + subTotal: number | null; + totalTax: number | null; + streetAddress1: string | null; + streetAddress2: string | null; + city: string | null; + deliveryState: string | null; + postalCode: string | null; + customerPhone: string | null; + customerExpectedTimeStart: string; + customerExpectedTimeEnd: string; + dispatchDepartTime: string; + dispatchArriveTime: string; + items: Array | null; + payments: Array | null; + deliveryStatus: string | null; +}; + +export type DeliveryPayment = { + name: string | null; + amount: number; +}; + +export type DeliveryScheduleType = 1 | 2; + +export type Discount = { + name: string | null; + amount: number; + discountId: number | null; +}; + +export type DiscountApiResponse = { + id: number | null; + externalId: string | null; + validDateFrom: string | null; + validDateTo: string | null; + maxRedemptions: number | null; + redemptionLimit: number | null; + firstTimeCustomerOnly: DiscountFirstTimeCustomer; + discountDescription: string | null; + discountCode: string | null; + applicationMethodId: DiscountApplicationMethod; + readonly applicationMethod: string | null; + canStackAutomatically: boolean; + onlineName: string | null; + locationRestrictions: Array | null; + restrictToGroupIds: Array | null; + monday: boolean | null; + tuesday: boolean | null; + wednesday: boolean | null; + thursday: boolean | null; + friday: boolean | null; + saturday: boolean | null; + sunday: boolean | null; + isActive: boolean; + isBundledDiscount: boolean; + constraints: Array | null; + reward: DiscountRewardApiResponse; + menuDisplay: DiscountMenuDisplayApiResponse; + paymentRestrictions: DiscountPaymentRestrictionApiResponse; +}; + +export type DiscountApplicationMethod = 1 | 2 | 3 | 4 | 5 | 6; + +export type DiscountConstraintApiResponse = { + discountConstraintId: number | null; + discountId: number; + thresholdMin: number | null; + includeNonCannabis: boolean; + thresholdTypeId: DiscountThresholdType; + readonly thresholdType: string | null; + readonly hasThreshold: boolean; + discountItemGroupTypeId: DiscountItemGroupType; + readonly itemGroupType: string | null; + restrictions: { + [key: string]: IRestrictionApiResponse; + } | null; +}; + +export type DiscountFirstTimeCustomer = 0 | 1 | 2; + +/** + * Discount group model for organizing and categorizing related discounts. + */ +export type DiscountGroup = { + /** + * Unique identifier for the discount group. + */ + discountGroupId: number; + /** + * Display name of the discount group for management and organization. + */ + discountGroupName: string | null; +}; + +export type DiscountItemGroupType = 5 | 6; + +export type DiscountMenuDisplayApiResponse = { + menuDisplayDescription: string | null; + menuDisplayImageUrl: string | null; + menuDisplayName: string | null; + menuDisplayRank: number; +}; + +export type DiscountPaymentRestrictionApiResponse = { + payByBankSignupIncentive: boolean; +}; + +/** + * Discount restriction model defining entity inclusion or exclusion rules for discount application. + */ +export type DiscountRestriction = { + /** + * Collection of entity identifiers subject to the restriction rule. + */ + ids: Array | null; + /** + * Indicates if this is an exclusion rule (true) or inclusion rule (false). + */ + isExclusion: boolean; +}; + +export type DiscountRewardApiResponse = { + discountRewardId: number | null; + discountId: number; + calculationMethodId: CalculationMethod; + readonly calculationMethod: string | null; + discountValue: number; + includeNonCannabis: boolean; + highestOrLowest: string | null; + thresholdTypeId: DiscountThresholdType; + readonly thresholdType: string | null; + readonly hasThreshold: boolean; + itemGroupTypeId: DiscountItemGroupType; + readonly itemGroupType: string | null; + thresholdMin: number | null; + thresholdMax: number | null; + applyToOnlyOneItem: boolean; + restrictions: { + [key: string]: IRestrictionApiResponse; + } | null; +}; + +export type DiscountThresholdType = 1 | 2 | 3; + +export type DriverDetail = { + driverId: number; + name: string | null; + stateId: string | null; + driversLicense: string | null; +}; + +/** + * E-commerce customer data model for creating or updating customer profiles via API integration. + */ +export type EcomCustomerEdit = { + /** + * When specified, it updates the record, if the ID exists + * null / unspecified will create a new customer + */ + customerId?: number | null; + /** + * Unique identifier for external system integration. + */ + uniqueId?: string | null; + /** + * Deprecated full name field (use FirstName and LastName instead). + * @deprecated + */ + name?: string | null; + /** + * Customer's first name (required). + */ + firstName: string; + /** + * Customer's last name. + */ + lastName?: string | null; + /** + * Customer's middle name. + */ + middleName?: string | null; + /** + * Name suffix (Jr., Sr., III, etc.). + */ + nameSuffix?: string | null; + /** + * Name prefix (Mr., Mrs., Dr., etc.). + */ + namePrefix?: string | null; + /** + * Primary street address line (required). + */ + address1: string; + /** + * Secondary address line (apartment, suite, etc.). + */ + address2?: string | null; + /** + * City name (required). + */ + city: string; + /** + * State or province (required). + */ + state: string; + /** + * Postal or ZIP code (required). + */ + postalCode: string; + /** + * Phone number. + */ + phone?: string | null; + /** + * Email address. + */ + emailAddress?: string | null; + /** + * Active; Cancelled; Hold; Banned + */ + status: string; + /** + * Medical marijuana identification number. + */ + mmjidNumber?: string | null; + /** + * Driver's license ID. + */ + driversLicenseID?: string | null; + /** + * Driver's license expiration date. + */ + driversLicenseExpiration?: string | null; + /** + * Medical marijuana ID expiration date. + */ + mmjidExpirationDate?: string | null; + /** + * Customer type classification (required). Use CustomerTypes endpoint to retrieve active customer types for a given location. + */ + customerType: string; + /** + * Customer's date of birth. + */ + dateOfBirth?: string | null; + /** + * External system customer identifier. + */ + externalCustomerId?: string | null; + /** + * Customer's gender. + */ + gender?: string | null; + /** + * Optional idempotency key for duplicate prevention. When provided with a ConsumerKey header, ensures the same customer creation request is not processed multiple times. + */ + idempotencyKey?: string | null; + /** + * How the customer heard about the dispensary. Use ReferralSources endpoint to retrieve values. + */ + referralSource?: string | null; + /** + * Custom identifier for external system integration. + */ + customIdentifier?: string | null; + /** + * Additional notes about the customer. + */ + notes?: string | null; + /** + * Indicates if customer is enrolled in loyalty program. + */ + isLoyaltyMember?: boolean | null; +}; + +export type Employee = { + userId: number; + loginId: string | null; + fullName: string | null; + defaultLocation: string | null; + status: string | null; + stateId: string | null; + mmjExpiration: string; + permissionsLocation: string | null; + groups: string | null; +}; + +/** + * Fee and donation tracking model for cannabis dispensary compliance and accounting. + */ +export type FeeDonation = { + /** + * Name of the fee or donation for identification and reporting purposes. + */ + name: string | null; + /** + * Cash value of the fee or donation for financial accounting. + */ + cashValue: number; + /** + * Flag indicating whether the fee or donation counts as revenue for accounting purposes. + */ + isRevenue: boolean; +}; + +/** + * Fee and donation information associated with cannabis retail transactions. + */ +export type FeeDonationInfo = { + /** + * Unique identifier for the specific fee or donation program. + */ + feeDonationId: number; + /** + * Description of the fee or donation for customer receipts and reporting. + */ + description: string | null; + /** + * Amount of the fee or donation (in USD). + */ + amount: number; + /** + * Indicates whether this fee counts as business revenue for accounting purposes. + */ + isRevenue: boolean; +}; + +export type FinishOrUnfinishBatchDetails = { + batchId: number; + harvestCompletedOn: string | null; +}; + +export type GuestListEntry = { + name: string | null; + checkinDateUTC: string; + status: string | null; + customerId: number; + transactionId: number; + transactionReferenceNumber: string | null; + terminalName: string | null; + customerType: string | null; + phone: string | null; + cellPhone: string | null; + preOrderSource: string | null; +}; + +export type Harvest = { + harvestId: number; + harvestName: string | null; + harvestDate: string; + harvestRoom: string | null; + plantCount: number; + plantWeight: number | null; + wetWeight: number | null; + wetWaste: number | null; + dryBudWeight: number | null; + dryShakeWeight: number | null; + dryWaste: number | null; + packageCount: number; + packagedWeight: number | null; + lastModifiedDateUTC: string; + strainName: string | null; +}; + +/** + * Request model for moving cannabis plants from cultivation to harvest status with optional weight tracking. + * + * **Request Behavior:** + * - Moves specified plants from cultivation status to harvesting status + * - Supports bulk processing of multiple plants in single operation + * - Optional weight tracking for harvest yield management + * - Integrates with external cultivation systems when configured + * + * **Validation:** + * - All plant IDs must exist and be accessible to the authenticated location + * - Plants must be in valid status for harvesting (typically Active status) + * - Harvest ID must correspond to existing harvest record + */ +export type HarvestPlantRequest = { + /** + * Collection of plants to be harvested with optional weight measurements + */ + plants: Array | null; + /** + * Target harvest record ID for associating harvested plants + */ + harvestId: number; + /** + * Date and time when harvest occurred (optional, defaults to current UTC time if not specified) + */ + harvestedOn: string | null; +}; + +/** + * Harvest waste detail model for tracking waste generated from specific harvest operations. + */ +export type HarvestWasteDetail = { + /** + * Identifier for the harvest batch generating this waste. + */ + harvestId: number; + /** + * Type or category of waste material from the harvest. + */ + wasteType: string | null; + /** + * Quantity of waste material generated from the harvest. + */ + wasteAmount: number; + /** + * Unit of measurement identifier for the waste amount. + */ + unitId: number; +}; + +/** + * Generic waste record model containing waste disposal information and associated detail records for cannabis compliance and waste tracking. + */ +export type HarvestWasteDetailWaste = { + /** + * Unique identifier for the waste record (null for new waste creation). + */ + wasteId: number | null; + /** + * Reference number for waste tracking and documentation. + */ + referenceNo: string | null; + /** + * Additional comments or notes about the waste disposal. + */ + comments: string | null; + /** + * Date when the waste disposal occurred. + */ + wasteDate: string | null; + /** + * Collection of waste detail records containing specific item information. + */ + wasteDetail: Array | null; + /** + * Licensed Service Provider identifier (internal use only). + */ + lspId: number | null; + /** + * Location identifier (internal use only). + */ + locId: number | null; + /** + * Indicates if room identification is required for this waste type (internal use only). + */ + roomRequired: boolean | null; + /** + * Indicates if this waste integrates with BioTrack system (internal use only). + */ + isBioTrack: boolean | null; +}; + +/** + * Individual plant harvest information with optional weight tracking for yield management. + * + * **Weight Tracking:** + * - Weight is optional but recommended for harvest yield analysis + * - Typically represents wet weight at time of harvest + * - Used for compliance reporting and operational analytics + */ +export type HarvestedPlant = { + /** + * Unique LeafLogix plant identifier for the plant being harvested + */ + plantId: number; + /** + * Optional harvest weight measurement (typically wet weight in grams) + */ + weight: number | null; +}; + +export type IRestrictionApiResponse = { + isExclusion: boolean; +}; + +export type Int32iEnumerableOptional = Array; + +export type Int32NullableOptional = number; + +/** + * Integrated payment processing information for cannabis transactions processed through connected payment systems. + */ +export type IntegratedPayment = { + /** + * Type of integrated payment processor used for the transaction (e.g., "CreditCard", "CanPay", "ACH"). + */ + integrationType: string | null; + /** + * Amount paid through the integrated payment system (in USD). + */ + integratedPaid: number; + /** + * External payment identifier from the integrated payment processor for transaction tracking. + */ + externalPaymentId: string | null; +}; + +export type InventoryDiscrepancy = { + inventoryId: number | null; + packageId: string | null; + quantity: number; + roomId: number; + unitId: number; + externalQuantity: number; + externalUnitId: number; + equivalentExternalQuantity: number | null; + readonly difference: number; + productName: string | null; + room: string | null; + externalRoom: string | null; + batchModeQuantity: number | null; + bioTrackCategoryName: string | null; + externalBioTrackCategoryName: string | null; + sku: string | null; + unitErrorMsg: string | null; + rooms: Array | null; + serialNumber: string | null; +}; + +export type InventoryIntegrationReconResponse = { + lastUpdated: string | null; + discrepancies: Array | null; +}; + +/** + * Inventory item model representing current stock and product details for available inventory. + */ +export type InventoryItem = { + /** + * Unit of measurement for unit weight, always "g" (grams). + */ + unitWeightUnit: string | null; + /** + * Unique inventory record identifier for this specific inventory item. + */ + inventoryId: number; + /** + * Product identifier linking this inventory to the product catalog. + */ + productId: number; + /** + * Stock Keeping Unit (SKU) code for inventory tracking and identification. + */ + sku: string | null; + /** + * Display name of the product for customer-facing applications. + */ + productName: string | null; + /** + * Detailed product description including effects, characteristics, and usage information. + */ + description: string | null; + /** + * Category identifier for product classification (optional). + */ + categoryId: number | null; + /** + * Category name for product classification and filtering. + */ + category: string | null; + /** + * URL path to product image for display purposes. + */ + imageUrl: string | null; + /** + * Current available quantity for sale or transfer. + */ + quantityAvailable: number; + /** + * Unit of measurement for the available quantity (e.g., "g", "mg", "ea"). + */ + quantityUnits: string | null; + /** + * Weight per unit in grams for dosing and compliance calculations. + */ + unitWeight: number; + /** + * Flower equivalent amount in grams for compliance tracking. + */ + flowerEquivalent: number; + /** + * Recreational flower equivalent amount in grams (optional). + */ + recFlowerEquivalent: number | null; + /** + * Unit of measurement for flower equivalent, always "g" (grams). + */ + readonly flowerEquivalentUnits: string | null; + /** + * Batch identifier for lot tracking and quality control. + */ + batchId: number; + /** + * Human-readable batch name or lot number for tracking. + */ + batchName: string | null; + /** + * Package identifier for compliance tracking and traceability. + */ + packageId: string | null; + /** + * Current status of the package (e.g., "Active", "Testing", "Quarantine"). + */ + packageStatus: string | null; + /** + * Base unit price for retail sales. + */ + unitPrice: number; + /** + * Medical program pricing (optional, different from retail). + */ + medUnitPrice: number | null; + /** + * Recreational program pricing (optional, different from medical). + */ + recUnitPrice: number | null; + /** + * Strain identifier for cannabis products (optional). + */ + strainId: number | null; + /** + * Strain name for cannabis products. + */ + strain: string | null; + /** + * Cannabis strain classification (Hybrid, Indica, Sativa, CBD). + */ + strainType: string | null; + /** + * Product size designation for packaging and dosing information. + */ + size: string | null; + /** + * Collection of laboratory test results for this batch (included when includeLabResults=true). + */ + labResults: Array | null; + /** + * Date when laboratory testing was completed (optional). + */ + testedDate: string | null; + /** + * Date when sample was collected for laboratory testing (optional). + */ + sampleDate: string | null; + /** + * Date when product was packaged for distribution (optional). + */ + packagedDate: string | null; + /** + * Date when product was manufactured or produced (optional). + */ + manufacturingDate: string | null; + /** + * Last modification timestamp in UTC for data synchronization. + */ + lastModifiedDateUtc: string | null; + /** + * Current status of laboratory testing (e.g., "Passed", "Failed", "Pending"). + */ + labTestStatus: string | null; + /** + * Vendor identifier for the supplier of this inventory (optional). + */ + vendorId: number | null; + /** + * Vendor name for the supplier of this inventory. + */ + vendor: string | null; + /** + * Product expiration date for compliance and quality control (optional). + */ + expirationDate: string | null; + /** + * Quantity breakdown by storage room/location (included when includeRoomQuantities=true). + */ + roomQuantities: Array | null; + /** + * Pricing tier classification for bulk pricing strategies. + */ + pricingTierName: string | null; + /** + * Alternative product name for display purposes. + */ + alternateName: string | null; + /** + * Collection of compliance tags associated with this inventory package. + */ + tags: Array | null; + /** + * Brand identifier for branded products (optional). + */ + brandId: number | null; + /** + * Brand name for branded products. + */ + brandName: string | null; + /** + * Indicates if product is restricted to medical program only. + */ + medicalOnly: boolean; + /** + * External compliance system ID (METRC or BioTrack) for regulatory tracking. + */ + externalPackageId: string | null; + /** + * Producer name for cultivation and manufacturing tracking. + */ + producer: string | null; + /** + * Producer identifier for cultivation and manufacturing tracking (optional). + */ + producerId: number | null; + /** + * Package lineage information for traceability and compliance tracking. + */ + lineage: Array | null; + /** + * Potency classification indicator for dosing guidance. + */ + potencyIndicator: string | null; + /** + * Master category classification for product grouping. + */ + masterCategory: string | null; + /** + * Effective potency in milligrams for dosing calculations (optional). + */ + effectivePotencyMg: number | null; + /** + * Indicates if product contains cannabis or is cannabis-related. + */ + isCannabis: boolean; + /** + * National Drug Code for pharmaceutical tracking (optional). + */ + packageNDC: string | null; + /** + * URL to certificate of analysis or lab testing document. + */ + labResultUrl: string | null; +}; + +/** + * Cannabis inventory quantity tracking model by room location for facility management and compliance. + */ +export type InventoryRoomQuantity = { + /** + * Room identifier for the storage location. + */ + roomId: number; + /** + * Room name or description for the storage location. + */ + room: string | null; + /** + * Quantity of cannabis product available in this specific room location. + */ + quantityAvailable: number; +}; + +/** + * Historical inventory snapshot model representing inventory levels at a specific point in time. + */ +export type InventorySnapshot = { + /** + * Stock Keeping Unit (SKU) code for product identification. + */ + sku: string; + /** + * Product name as it existed at the snapshot date. + */ + product: string; + /** + * Product identifier linking to the product catalog. + */ + productId: number; + /** + * Storage room name where inventory was located at snapshot time. + */ + room: string; + /** + * Storage room identifier for location tracking. + */ + roomId: number; + /** + * Vendor name for the supplier of this inventory (optional). + */ + vendor?: string | null; + /** + * Package identifier for compliance tracking and traceability. + */ + packageId: string; + /** + * Batch name or lot number for quality tracking (optional). + */ + batchName?: string | null; + /** + * Batch identifier for lot tracking (optional). + */ + batchId?: number | null; + /** + * Inventory quantity as it existed at the snapshot date. + */ + quantity: number; + /** + * Total cost value of the inventory quantity (optional). + */ + totalCost?: number | null; + /** + * Unit of measurement for the quantity. + */ + unit: string; + /** + * Unit identifier for the measurement type. + */ + unitId: number; + /** + * Inventory status at the time of snapshot (e.g., "Active", "Quarantine"). + */ + status?: string | null; + /** + * Date and time when this inventory snapshot was captured. + */ + snapshotDate: string; + /** + * Inventory record identifier linking to the specific inventory item. + */ + inventoryId: number; +}; + +export type InventoryTag = { + tagId: number; + tagName: string | null; + packageId: string | null; +}; + +/** + * Inventory transaction record model representing historical inventory movement and modification operations. + */ +export type InventoryTransaction = { + /** + * Unique identifier for the inventory transaction record. + */ + inventoryTransactionId: number; + /** + * Type of inventory transaction performed. + * **Options**: Move, Convert, Adjust, Combine, Receive, Change Product, Discontinue, Detail Update, Reconciliation, Create Package + */ + transactionType?: string | null; + /** + * Product name at the time of transaction. + */ + product?: string | null; + /** + * Stock Keeping Unit (SKU) code for the product. + */ + sku?: string | null; + /** + * Product identifier linking to the product catalog. + */ + productId?: number; + /** + * Unit of measurement for the transaction quantities. + */ + unit?: string | null; + /** + * Package identifier for compliance tracking and traceability. + */ + packageId?: string | null; + /** + * External package identifier from integrated compliance systems. + */ + externalPackageId?: string | null; + /** + * Batch identifier for lot tracking (optional). + */ + batchId?: number | null; + /** + * Batch name or lot number for quality tracking (optional). + */ + batchName?: string | null; + /** + * Transaction quantity for non-adjustment operations (Move, Convert, Receive, etc.). + */ + quantity?: number | null; + /** + * Original quantity before adjustment (used for Adjust transaction type). + */ + fromQuantity?: number | null; + /** + * New quantity after adjustment (used for Adjust transaction type). + */ + toQuantity?: number | null; + /** + * Reason for adjustment (used for Adjust transaction type). + */ + reason?: string | null; + /** + * Receive inventory history identifier for received inventory linkage (optional). + */ + receiveInventoryHistoryId?: number | null; + /** + * Source location name for Move transactions. + */ + fromLocation?: string | null; + /** + * Source room name for Move transactions. + */ + fromRoom?: string | null; + /** + * Destination location name for Move transactions. + */ + toLocation?: string | null; + /** + * Destination room name for Move transactions. + */ + toRoom?: string | null; + /** + * Conversion transaction identifier for Convert operations (optional). + */ + conversionTransactionID?: number | null; + /** + * Username or identifier of the person who performed the transaction. + */ + transactionBy?: string | null; + /** + * Date and time when the transaction was performed. + */ + transactionDate?: string; + /** + * Unit cost of the package at the time of transaction (optional). + */ + unitCost?: number | null; + /** + * Purchase order identifier for received inventory linkage (optional). + */ + purchaseOrderId?: number | null; + /** + * Unique inventory item identifier affected by this transaction. + */ + inventoryId?: number; +}; + +/** + * Represents a customer journal entry containing notes and interaction history for customer service tracking. + */ +export type JournalEntry = { + /** + * Unique identifier for the journal entry. + */ + journalEntryId: number; + /** + * Brief title or summary of the journal entry. + */ + subject: string | null; + /** + * Detailed content and notes for the journal entry. + */ + body: string | null; + /** + * Date and time when the journal entry was created or should be dated. + */ + date: string; +}; + +/** + * Laboratory testing result model for cannabis and cannabis product analysis. + */ +export type LabResult = { + /** + * Name of the laboratory test performed (e.g., "THC", "CBD", "Myrcene", "Total Aerobic Count"). + */ + labTest: string | null; + /** + * Numeric test result value (null if not detected or not applicable). + */ + value: number | null; + labResultUnitId: LabResultUnit; + /** + * Human-readable unit name corresponding to the LabResultUnitId. + */ + readonly labResultUnit: string | null; +}; + +export type LabResultUnit = 1 | 2 | 3 | 4 | 5 | 6; + +/** + * Laboratory result unit data model for cannabis testing measurements and reporting. + */ +export type LabResultUnitData = { + /** + * Unique identifier for the lab result unit type. + */ + labResultUnitId: number; + /** + * Display name of the lab result unit (e.g., "mg", "%", "mg/g", "ND", "LOQ", "Pass/Fail"). + */ + labResultUnit: string | null; +}; + +/** + * Tax information applied to individual transaction line items in cannabis retail operations. + */ +export type LineItemTaxInfo = { + /** + * Name of the tax rate applied (e.g., "State Excise Tax", "City Cannabis Tax", "Sales Tax"). + */ + rateName: string | null; + /** + * Tax rate as a decimal percentage (e.g., 0.0875 for 8.75% tax rate). + */ + rate: number; + /** + * Calculated tax amount applied to the line item (in USD). + */ + amount: number; + /** + * Reference identifier linking this tax information back to the specific transaction line item. + * Not guaranteed to be unique outside of a single transaction. + */ + readonly transactionItemId: number; +}; + +/** + * Cannabis genetic lineage model containing hereditary classification information for product categorization and genetic tracking. + */ +export type Lineage = { + /** + * Unique identifier for the genetic lineage. + */ + lineageId: number; + /** + * Display name for the genetic lineage (e.g., "Indica", "Sativa", "Hybrid"). + */ + lineageName: string | null; +}; + +/** + * Location identity model containing complete location and parent company information for API key verification and context identification. + */ +export type LocationIdentity = { + /** + * Unique identifier for the cannabis dispensary location. + */ + locationId: number; + /** + * Unique identifier for the parent company (LSP - Licensed Service Provider). + */ + lspId: number; + /** + * Business name of the cannabis dispensary location. + */ + locationName: string | null; + /** + * Company name of the parent organization (Licensed Service Provider). + */ + lspName: string | null; + /** + * Primary street address of the dispensary location. + */ + address: string | null; + /** + * Secondary address line (suite, unit, etc.) if applicable. + */ + address2: string | null; + /** + * City where the dispensary is located. + */ + city: string | null; + /** + * State or province where the dispensary is licensed to operate. + */ + state: string | null; + /** + * Postal code (ZIP code) for the dispensary location. + */ + postalCode: string | null; + /** + * State-issued cannabis business license number for regulatory compliance. + */ + licenseNumber: string | null; + /** + * "Doing Business As" name if different from the legal business name. + */ + doingBusinessAs: string | null; + /** + * Indicates whether customer profiles are shared across locations within the organization. + */ + shareCustomerProfiles: boolean; + /** + * Legacy global unique identifier for the location (deprecated). + * @deprecated + */ + globalId: string | null; + /** + * Global unique identifier for the location across all systems and integrations. + */ + locationGlobalId: string | null; + /** + * Global unique identifier for the parent company (LSP) across all systems. + */ + lspGlobalId: string | null; + /** + * Regional identifier for compliance and API routing (internal use only). + */ + region: string | null; + /** + * Base64-encoded SHA256 hash of the region identifier for secure regional routing. + */ + readonly regionId: string | null; +}; + +/** + * Location mapping model for associating discounts with specific business locations. + */ +export type LocationMapping = { + /** + * Name of the location where the discount applies. + */ + locationName: string | null; +}; + +export type LocationProductOverride = { + productId: number; + price: number | null; + recPrice: number | null; + cost: number | null; + onlineAvailable: boolean | null; + posAvailable: boolean | null; + maxPurchasable: number | null; + lowInventoryThreshold: number | null; + customMetadata: string | null; +}; + +export type LocationProductOverrideRequest = { + /** + * Product identifier for the product being configured with location-specific overrides. + */ + productId: number; + price: DecimalNullableOptional; + recPrice: DecimalNullableOptional; + cost: DecimalNullableOptional; + onlineAvailable: BooleanNullableOptional; + posAvailable: BooleanNullableOptional; + maxPurchasable: DecimalNullableOptional; + lowInventoryThreshold: DecimalNullableOptional; + customMetadata: StringOptional; +}; + +export type LocationResponse = { + locationName: string | null; + locId: number; + licenseNumber: string | null; + readonly outcome: string | null; + readonly outcomeId: number; + broadcastedTo: string | null; + errorDetail: string | null; +}; + +/** + * Represents a customer's loyalty program balance and activity snapshot for reporting purposes. + * + * Contains current point balances and historical activity for individual customers within the + * loyalty program. Used for daily balance reporting, customer service inquiries, and loyalty + * program analytics. Data reflects nightly batch processing and may not include real-time changes. + */ +export type LoyaltySnapshot = { + /** + * Unique identifier for the customer in the loyalty program. + * Links this loyalty snapshot to the specific customer account. + */ + customerId: number; + /** + * Current available loyalty points balance for the customer. + * Represents points that can be redeemed for rewards or discounts. + */ + loyaltyBalance: number; + /** + * Total loyalty points redeemed/spent by the customer over their lifetime. + * Historical record of all point redemptions and rewards claimed. + */ + loyaltySpent: number; + /** + * Total loyalty points earned by the customer over their lifetime. + * Historical record of all points awarded through purchases and activities. + */ + loyaltyEarned: number; +}; + +/** + * Manual payment information for cannabis transactions processed outside integrated payment systems. + */ +export type ManualPayment = { + /** + * Name of the manual payment processor or handling method (e.g., "Cash", "Check", "Money Order"). + */ + manualPaymentProcessorName: string | null; + /** + * Amount paid through the manual payment method (in USD). + */ + manualPaid: number; +}; + +/** + * Detailed specification for creating individual mature plant batches with compliance tracking information. + */ +export type MatureBatchDetails = { + /** + * Batch identifier for the mature plant batch being created. + */ + batchId: number; + /** + * Collection of individual plant serial numbers within the mature batch for state tracking compliance. + */ + serialNumbers: Array | null; + /** + * Growth stage designation for the mature batch (e.g., "Vegetative", "Flowering"). + */ + batchStage: string | null; + /** + * Room identifier for the mature batch location assignment. + */ + roomId: number; + /** + * Table identifier within the room for precise location tracking (optional). + */ + tableId: number | null; + /** + * Date when the mature batch was created for cultivation timeline documentation. + */ + dateCreated: string | null; +}; + +/** + * Request model for moving cannabis plants to a different cultivation room or table within the same facility. + * + * **Movement Behavior:** + * - Moves specified plants to target room within same facility + * - Optional table assignment for precise cultivation area management + * - Validates target room belongs to same facility for security + * - Automatically updates plant cultivation stage if room has associated stage + * + * **Facility Restrictions:** + * - Target room must belong to same facility as requesting user + * - Cross-facility plant movements are prohibited for security and compliance + * - All plant IDs must be accessible to the authenticated location + * + * **Integration:** + * - Movement synchronized with external cultivation systems when configured + * - Supports cultivation workflow automation and environmental optimization + */ +export type MovePlantRequest = { + /** + * Collection of LeafLogix plant IDs to move to the target room + */ + plantIds: Array | null; + /** + * Target cultivation room ID within the same facility where plants will be moved + */ + roomId: number; + /** + * Optional table ID within the target room for precise plant positioning (optional) + */ + tableId: number | null; +}; + +/** + * Generic waste record model containing waste disposal information and associated detail records for cannabis compliance and waste tracking. + */ +export type ObjectWaste = { + /** + * Unique identifier for the waste record (null for new waste creation). + */ + wasteId: number | null; + /** + * Reference number for waste tracking and documentation. + */ + referenceNo: string | null; + /** + * Additional comments or notes about the waste disposal. + */ + comments: string | null; + /** + * Date when the waste disposal occurred. + */ + wasteDate: string | null; + /** + * Collection of waste detail records containing specific item information. + */ + wasteDetail: Array<{ + [key: string]: unknown; + }> | null; + /** + * Licensed Service Provider identifier (internal use only). + */ + lspId: number | null; + /** + * Location identifier (internal use only). + */ + locId: number | null; + /** + * Indicates if room identification is required for this waste type (internal use only). + */ + roomRequired: boolean | null; + /** + * Indicates if this waste integrates with BioTrack system (internal use only). + */ + isBioTrack: boolean | null; +}; + +/** + * Package lineage tracking model for cannabis product traceability and regulatory compliance. + */ +export type PackageLineage = { + /** + * Package identifier for the current package in the lineage chain. + */ + packageId: string | null; + /** + * Number of generations between current package and antecedent package in the lineage chain. + */ + antecedentPackageDistance: number; + /** + * Flag indicating whether the antecedent package originated from a harvest operation. + */ + antecedentIsHarvest: boolean; + /** + * Batch name for the current package for lot tracking and quality control. + */ + batchName: string | null; + /** + * Batch name of the antecedent package for lineage and quality tracking. + */ + antecedentBatchName: string | null; +}; + +export type Plant = { + plantId: number; + serialNumber: string | null; + growthPhase: string | null; + type: string | null; + harvestedWeight: number | null; + status: string | null; + plantCount: number | null; + isMother: boolean; + motherPlantId: number | null; + plantedOn: string | null; + addedToHarvestOn: string | null; + harvestDate: string | null; + destroyedDate: string | null; + plantGroupName: string | null; + strain: string | null; + room: string | null; + table: string | null; + vegetationStartedOn: string | null; + vegetationEndedOn: string | null; + floweringStartedOn: string | null; + floweringEndedOn: string | null; + currentPhaseStartDate: string | null; + lastModifiedDate: string | null; + daysInCurrentPhase: number | null; + floweringRoom: string | null; + floweringTable: string | null; + vegetationRoom: string | null; + vegetationTable: string | null; + daysInFlowering: number | null; + daysInVegetation: number | null; + batchId: number; + readonly harvestId: number; +}; + +/** + * Plant waste detail model for tracking waste generated from specific plant disposal operations. + */ +export type PlantWasteDetail = { + /** + * Identifier for the plant generating this waste. + */ + plantId: number; + /** + * Type or category of waste material from the plant. + */ + wasteType: string | null; + /** + * Quantity of waste material generated from the plant. + */ + wasteAmount: number; + /** + * Unit of measurement identifier for the waste amount. + */ + unitId: number; +}; + +/** + * Generic waste record model containing waste disposal information and associated detail records for cannabis compliance and waste tracking. + */ +export type PlantWasteDetailWaste = { + /** + * Unique identifier for the waste record (null for new waste creation). + */ + wasteId: number | null; + /** + * Reference number for waste tracking and documentation. + */ + referenceNo: string | null; + /** + * Additional comments or notes about the waste disposal. + */ + comments: string | null; + /** + * Date when the waste disposal occurred. + */ + wasteDate: string | null; + /** + * Collection of waste detail records containing specific item information. + */ + wasteDetail: Array | null; + /** + * Licensed Service Provider identifier (internal use only). + */ + lspId: number | null; + /** + * Location identifier (internal use only). + */ + locId: number | null; + /** + * Indicates if room identification is required for this waste type (internal use only). + */ + roomRequired: boolean | null; + /** + * Indicates if this waste integrates with BioTrack system (internal use only). + */ + isBioTrack: boolean | null; +}; + +/** + * Request model for creating immature plant batches in cannabis cultivation operations. + */ +export type PostImmatureBatchRequest = { + /** + * Collection of immature plant batch specifications for bulk batch creation operations. + */ + batches: Array | null; +}; + +export type PreOrderItem = { + productId: number; + quantity: number; +}; + +export type PreOrderRedemption = { + productId?: number | null; + redemptionType: string; + redemptionId: string; + redemptionDescription?: string | null; + redemptionCallbackUrl?: string | null; +}; + +export type PreOrderRedemptionIEnumerableOptional = Array; + +export type PreOrderStatus = { + preOrderId: number; + status: string | null; + transactionId: number | null; + orderDate: string; + customerFirstName: string | null; + customerLastName: string | null; + customerId: number; + orderType: string | null; + orderSource: string | null; + rejectedReason: string | null; + isCancellable: boolean; + isUpdateable: boolean; + total: number | null; + subTotal: number | null; + totalTax: number | null; + sourceSystem: string | null; + items: Array | null; +}; + +export type PrecartItem = { + productId: number; + quantity: number; +}; + +/** + * Request model for calculating pricing, taxes, and discounts for a customer's shopping cart before creating a pre-order. + */ +export type PriceCartRequest = { + /** + * Collection of products in the customer's shopping cart with quantities and specifications. + */ + cart: Array | null; + /** + * Customer type identifier for pricing tier and discount eligibility (e.g., medical, recreational). + */ + customerTypeId: number | null; + /** + * Unique customer identifier for personalized pricing and loyalty program benefits. + */ + customerId: number | null; + /** + * Primary street address for delivery orders (used for tax calculation and delivery fee estimation). + */ + deliveryStreet: string | null; + /** + * Secondary address information (apartment, suite, unit number) for delivery orders. + */ + deliveryStreet2: string | null; + /** + * City name for delivery address (used for tax jurisdiction determination). + */ + deliveryCity: string | null; + /** + * State or province for delivery address (used for tax calculation and compliance verification). + */ + deliveryState: string | null; + /** + * Postal or ZIP code for delivery address (used for precise tax calculation and delivery zones). + */ + deliveryPostalCode: string | null; + /** + * Indicates whether this is a delivery order (true) or pickup order (false) for tax and fee calculation. + */ + isDelivery: boolean; +}; + +export type PriceEstimates = { + discountAmount: number; + taxAmount: number; + feeAmount: number; + subtotal: number; + grandTotal: number; +}; + +/** + * Pricing detail information for cannabis products with medical and recreational pricing tiers. + */ +export type PricingDetail = { + /** + * Medical cannabis patient pricing (typically lower due to tax benefits and patient programs). + */ + medPrice: number | null; + /** + * Recreational adult-use cannabis pricing (standard retail pricing with full taxes). + */ + recPrice: number | null; + /** + * Pricing tier name for customer segmentation (e.g., "Standard", "VIP", "Bulk", "Employee"). + */ + pricingTierName: string | null; +}; + +export type PricingTier = { + pricingTierId: number; + pricingTierName: string | null; +}; + +export type PricingTierData = { + startWeight: number | null; + endWeight: number | null; + price: number; + medicalPrice: number; +}; + +/** + * Producer identification model containing basic producer information for product attribution and reference data needs. + */ +export type Producer = { + /** + * Unique identifier for the producer. + */ + producerId: number; + /** + * Display name of the producer for product attribution and branding. + */ + producerName: string | null; +}; + +/** + * Product category model containing cannabis product classification information for menu organization and product management. + */ +export type ProductCategory = { + /** + * Unique identifier for the product category. + */ + productCategoryId: number; + /** + * Display name of the product category (e.g., "Flower", "Edibles", "Concentrates"). + */ + productCategoryName: string | null; + /** + * Higher-level master category classification for broader product grouping. + */ + masterCategory: string | null; +}; + +export type ProductDetail = { + productId: number; + sku: string | null; + internalName: string | null; + productName: string | null; + description: string | null; + masterCategory: string | null; + categoryId: number | null; + category: string | null; + imageUrl: string | null; + imageUrls: Array | null; + strainId: number | null; + strain: string | null; + strainType: string | null; + size: string | null; + netWeight: number | null; + netWeightUnitId: number | null; + readonly netWeightUnit: string | null; + brandId: number | null; + brandName: string | null; + vendorId: number | null; + vendorName: string | null; + isCannabis: boolean; + isActive: boolean; + isCoupon: boolean; + thcContent: number | null; + thcContentUnit: string | null; + cbdContent: number | null; + cbdContentUnit: string | null; + productGrams: number | null; + flowerEquivalent: number | null; + recFlowerEquivalent: number | null; + price: number | null; + medPrice: number | null; + recPrice: number | null; + unitCost: number | null; + unitType: string | null; + onlineTitle: string | null; + onlineDescription: string | null; + readonly onlineProduct: boolean | null; + posProducts: boolean | null; + pricingTier: number | null; + onlineAvailable: boolean | null; + lowInventoryThreshold: number | null; + pricingTierName: string | null; + pricingTierDescription: string | null; + pricingTierData: Array | null; + flavor: string | null; + alternateName: string | null; + lineageName: string | null; + distillationName: string | null; + maxPurchaseablePerTransaction: number | null; + tags: Array | null; + effects: Array | null; + dosage: string | null; + instructions: string | null; + allergens: string | null; + standardAllergens: StandardAllergensDetails; + defaultUnit: string | null; + producerId: number | null; + producerName: string | null; + createdDate: string | null; + isMedicalOnly: boolean; + lastModifiedDateUTC: string | null; + grossWeight: number | null; + isTaxable: boolean | null; + taxCategories: Array | null; + upc: string | null; + regulatoryCategory: string | null; + ndc: string | null; + daysSupply: number | null; + readonly illinoisTaxCategory: string | null; + externalCategory: string | null; + externalId: string | null; + syncExternally: boolean; + regulatoryName: string | null; + broadcastedResponses: BroadcastedResponses; + administrationMethod: string | null; + unitCBDContentDose: number | null; + unitTHCContentDose: number | null; + oilVolume: number | null; + ingredientList: string | null; + expirationDays: number | null; + abbreviation: string | null; + isTestProduct: boolean; + isFinished: boolean; + allowAutomaticDiscounts: boolean; + servingSize: string | null; + servingSizePerUnit: number | null; + isNutrient: boolean; + approvalDateUTC: string | null; + ecomCategory: string | null; + ecomSubcategory: string | null; + customMetadata: string | null; +}; + +/** + * Product upload model for creating and updating products. + * + * ⚠️ **DATA LOSS WARNING**: Most fields will be overwritten with null/zero if not provided. + * **RECOMMENDED**: Use GET /products first, modify needed fields, then POST the complete object. + */ +export type ProductDetailUpload = { + /** + * The unique identifier for a product in the system. + * + * **IMPORTANT**: This field determines whether a product is created or updated: + * - To CREATE a new product: Omit this field or set to null + * - To UPDATE an existing product: You MUST provide the ProductId of the existing product + */ + productId?: number | null; + /** + * Product SKU - REQUIRED for CREATE operations + */ + sku: string; + /** + * Product Name - REQUIRED for CREATE operations + */ + productName: string; + /** + * Deprecated in favor of AlternateName + */ + description?: string | null; + alternateName?: string | null; + masterCategory?: string | null; + category?: string | null; + strain?: string | null; + /** + * Strain type of the specified strain. + * Used to disambiguate strains, if duplicates exist. + * If no duplicates exist in the location's strain list, this field is not useful. + * If duplicates DO exist and this field is not specified, the strain will be chosen by the first one created. + */ + strainType?: string | null; + size?: string | null; + netWeight?: number | null; + /** + * Optional. Abbreviation of the unit of the product's net weight. + */ + netWeightUnit?: string | null; + grossWeight?: number | null; + brandName?: string | null; + vendorName?: string | null; + isCannabis?: boolean; + isActive?: boolean; + thcContent?: number | null; + /** + * mg; %; mg/g; n.d. + */ + thcContentUnit?: string | null; + cbdContent?: number | null; + /** + * mg; %; mg/g; n.d. + */ + cbdContentUnit?: string | null; + productGrams?: number | null; + flowerEquivalent?: number | null; + recFlowerEquivalent?: number | null; + price?: number | null; + unitCost?: number | null; + unitType?: string | null; + onlineTitle?: string | null; + onlineDescription?: string | null; + onlineProduct?: boolean | null; + posProducts?: boolean | null; + tags?: Array | null; + defaultUnit?: string | null; + isMedicalOnly?: boolean | null; + isTaxable?: boolean | null; + regulatoryCategory?: string | null; + ndc?: string | null; + daysSupply?: number | null; + illinoisTaxCategory?: string | null; + externalCategory?: string | null; + externalId?: StringOptional; + syncExternally?: boolean | null; + bypassExternalUpdate?: boolean | null; + administrationMethod?: StringOptional; + unitCBDContentDose?: DecimalNullableOptional; + unitTHCContentDose?: DecimalNullableOptional; + oilVolume?: DecimalNullableOptional; + ingredientList?: StringOptional; + expirationDays?: Int32NullableOptional; + abbreviation?: StringOptional; + isTestProduct?: BooleanOptional; + isFinished?: BooleanOptional; + allowAutomaticDiscounts?: BooleanOptional; + servingSize?: StringOptional; + servingSizePerUnit?: Int32NullableOptional; + isNutrient?: BooleanOptional; + approvalDateUTC?: DateTimeNullableOptional; + customMetadata?: StringOptional; + /** + * List of strings of tax categories that the product belongs to. + */ + taxCategories?: Array | null; + pricingDetails?: PricingDetail; + /** + * UserName of the user making the product change + * This will be used when authorizing with traceability systems (METRC/BioTrack) - if not included or NULL is specified, the traceability integration's "master key" will be used, if possible. + * This field is only relevant if the request is setting SyncExternally to true + */ + userName?: string | null; + instructions?: string | null; + upc?: string | null; + regulatoryName?: StringOptional; + broadcast?: BooleanOptional; +}; + +export type ProductEffect = { + effectId: number; + effectName: string | null; + productId: number; +}; + +export type ProductTag = { + tagId: number; + tagName: string | null; + productId: number; +}; + +/** + * Published discount model containing complete discount configuration and constraint information for customer-facing applications. + */ +export type PublishedDiscount = { + /** + * Unique identifier for the discount. + */ + discountId: number; + /** + * Display name of the discount for customer-facing applications. + */ + discountName: string | null; + /** + * Monetary discount amount or percentage value. + */ + discountAmount: number; + /** + * Promotional code required to apply the discount (optional). + */ + discountCode: string | null; + /** + * Type classification of the discount (e.g., percentage, fixed amount). + */ + discountType: string | null; + /** + * Method used to apply the discount (e.g., automatic, code required). + */ + discountMethod: string | null; + /** + * Indicates if the discount is currently active and available. + */ + isActive: boolean; + /** + * Start date and time when discount becomes valid (UTC converted from Eastern Time). + */ + validFrom: string | null; + /** + * End date and time when discount expires (UTC converted from Eastern Time). + */ + validUntil: string | null; + /** + * Type of threshold requirement for discount eligibility (optional). + */ + thresholdType: string | null; + /** + * Minimum number of qualifying items required for discount application (optional). + */ + minimumItemsRequired: number | null; + /** + * Maximum number of items that can receive the discount (optional). + */ + maximumItemsAllowed: number | null; + /** + * Maximum number of times this discount can be used (optional). + */ + maximumUsageCount: number | null; + /** + * Indicates if discount applies to non-cannabis products. + */ + includeNonCannabis: boolean; + /** + * Indicates if discount is restricted to first-time customers only. + */ + firstTimeCustomerOnly: boolean; + /** + * Indicates if discount can be combined with other discounts. + */ + stackOnOtherDiscounts: boolean; + weeklyRecurrenceInfo: WeeklyRecurrenceInfo; + products: DiscountRestriction; + productCategories: DiscountRestriction; + brands: DiscountRestriction; + vendors: DiscountRestriction; + strains: DiscountRestriction; + tiers: DiscountRestriction; + tags: DiscountRestriction; + inventoryTags: DiscountRestriction; + customerTypes: DiscountRestriction; + /** + * Associated discount groups for bundling and organization (loaded conditionally). + */ + discountGroups: Array | null; +}; + +export type PurchaseOrderData = { + purchaseOrderId: number; + expectedArrivalDate: string | null; + title: string | null; + dateReceived: string | null; + dateSubmitted: string | null; + shippingInformation: string | null; + vendorId: number; + vendorName: string | null; + vendorContact: string | null; + status: string | null; + purchaseOrderNumber: number; + createdByUser: string | null; + dateCreated: string | null; + purchaseOrderItems: Array | null; +}; + +export type PurchaseOrderItemDetail = { + purchaseOrderId: number; + purchaseOrderItemId: number; + productId: number; + productName: string | null; + quantity: number; + unitId: number; + unitName: string | null; + unitNameAbbreviation: string | null; + subtotal: number; + tax: number; +}; + +/** + * Request model for receiving and recording new cannabis inventory items into the facility management system. + */ +export type ReceiveInventoryItemSave = { + /** + * Product identifier for the cannabis product being received into inventory (required). + */ + productId: number; + /** + * Quantity of the product being received into inventory (required). + */ + quantity: number; + /** + * Unit type for the received quantity (qty; ml; g; Gal; L; lb; mg; oz; fl oz; kg). + */ + unitType?: string | null; + /** + * Flower equivalent weight for regulatory compliance and limit calculations. + */ + flowerEquivalent?: number | null; + /** + * Recreational flower equivalent weight for regulatory compliance tracking. + */ + recFlowerEquivalent?: number | null; + /** + * Vendor identifier for supply chain tracking and vendor management. + */ + vendorId?: number | null; + /** + * Room identifier for facility location assignment and space management. + */ + roomId?: number | null; + /** + * Package identifier from state tracking system for compliance documentation. + */ + packageId?: string | null; + /** + * Lot number for batch tracking and quality control management. + */ + lot?: string | null; + /** + * Unit cost for inventory valuation and cost accounting. + */ + cost?: number | null; + /** + * General retail price for the received inventory item. + */ + price?: number | null; + /** + * Recreational market price for dual-license operations. + */ + recPrice?: number | null; + /** + * Tax amount for financial compliance and tax reporting. + */ + tax?: number | null; + /** + * Product expiration date for inventory rotation and compliance management. + */ + expirationDate?: string | null; + /** + * Collection of tag identifiers for product categorization and organization. + */ + tags?: Array | null; + /** + * Cultivation tax amount for cannabis-specific tax compliance. + */ + cultivationTax?: number | null; + /** + * Table identifier within the room for precise location tracking. + */ + tableId?: number | null; + /** + * Source allocated inventory identifier for traceability and audit trails. + */ + sourceAllocatedInventoryId?: number | null; + /** + * Total package cost for comprehensive cost allocation and accounting. + */ + totalPackageCost?: number | null; + /** + * Flag to retrieve lab results from Metrc for compliance integration. + */ + getMetrcLabResults?: boolean | null; + /** + * Product name for inventory identification and display purposes. + */ + productName?: string | null; + /** + * Date when the product was packaged for shelf life tracking. + */ + packagingDate?: string | null; + /** + * Date when the product was manufactured for quality control tracking. + */ + manufacturingDate?: string | null; + /** + * Producer identifier for supply chain tracking and compliance documentation. + */ + producerId?: number | null; + /** + * External package identifier for cross-system integration and tracking. + */ + externalPackageId?: string | null; + /** + * Potency indicator for product strength classification and customer information. + */ + potencyIndicator?: string | null; +}; + +/** + * Request model for creating inventory receive orders for incoming transfers, purchase orders, or direct inventory additions. + */ +export type ReceiveInventorySave = { + /** + * Vendor identifier for the supplier (optional, can be resolved from VendorLicense). + */ + vendorId?: number | null; + /** + * Name of the person who delivered the inventory shipment. + */ + deliveredBy?: string | null; + /** + * Date and time when the inventory was delivered (required). + */ + deliveredOn: string; + /** + * Vendor license code for compliance tracking and vendor identification. + */ + vendorLicense?: string | null; + /** + * External transaction reference ID for tracking and reconciliation. + */ + transactionId?: string | null; + /** + * Descriptive title for the receive order for identification purposes. + */ + orderTitle?: string | null; + /** + * External system ID for preventing duplicate receives (must be unique). + */ + externalId?: string | null; + /** + * Additional notes or comments about the receive transaction. + */ + note?: string | null; + /** + * Collection of inventory items being received in this transaction. + */ + items?: Array | null; + /** + * Indicates whether to immediately process items into inventory (true) or save as draft (false). + */ + receiveIntoInventory?: boolean | null; + /** + * User ID for processing the receive (required when ReceiveIntoInventory=true). + */ + userId?: number | null; + /** + * Username for processing the receive (alternative to UserId, required when ReceiveIntoInventory=true). + */ + userName?: string | null; +}; + +/** + * Received inventory record model representing completed or pending inventory receive orders and their processing status. + */ +export type ReceivedInventory = { + /** + * Unique identifier for the receive inventory transaction. + */ + receiveInventoryHistoryId: number; + /** + * Descriptive title for the receive order for identification purposes. + */ + title: string | null; + /** + * Current processing status of the receive order (e.g., "Pending", "Completed", "Failed"). + */ + status: string | null; + /** + * Error message if the receive order failed processing (optional). + */ + failureMessage: string | null; + /** + * Date and time when the inventory was delivered by the vendor (optional). + */ + deliveredOn: string | null; + /** + * Date and time when the receive order was created in the system (optional). + */ + addedOn: string | null; + /** + * Name of the vendor who supplied the inventory. + */ + vendor: string | null; + /** + * Vendor license code for compliance tracking and verification. + */ + vendorLicense: string | null; + /** + * Collection of inventory items included in this receive order. + */ + items: Array | null; +}; + +/** + * Response model representing received cannabis inventory items with complete tracking and financial information. + */ +export type ReceivedInventoryItem = { + /** + * Product name for inventory item identification and display. + */ + product: string | null; + /** + * Stock Keeping Unit (SKU) for product identification and retail operations. + */ + sku: string | null; + /** + * Product identifier for database references and system integration. + */ + productId: number | null; + /** + * Product type classification for cannabis product categorization. + */ + type: string | null; + /** + * Quantity of the received inventory item for stock tracking. + */ + quantity: number; + /** + * Unit abbreviation for quantity measurement display (e.g., "g", "oz", "ml"). + */ + unitAbbreviation: string | null; + /** + * Full unit name for quantity measurement (e.g., "grams", "ounces", "milliliters"). + */ + unit: string | null; + /** + * Cost per unit for inventory valuation and financial accounting. + */ + unitCost: number; + /** + * Tax amount per unit for cannabis tax compliance and reporting. + */ + unitTax: number; + /** + * Total cost for the received inventory item including all taxes and fees. + */ + totalCost: number; + /** + * Package identifier from state tracking system for compliance documentation. + */ + packageId: string | null; + /** + * External package identifier for cross-system tracking and integration. + */ + externalPackageId: string | null; + /** + * Batch name for lot tracking and quality control management. + */ + batchName: string | null; + /** + * Batch identifier for database references and batch tracking. + */ + batchId: number | null; + /** + * Room name for facility location identification and display. + */ + room: string | null; + /** + * Room identifier for database references and location tracking. + */ + roomId: number | null; +}; + +/** + * Represents a register cash adjustment transaction record for financial reconciliation and audit trails. + * + * Register adjustments include manual cash corrections, deposits, withdrawals, close-outs, and other + * cash management activities that affect register balances. Each adjustment maintains a complete + * audit trail with employee accountability and reason tracking. + */ +export type RegisterAdjustment = { + /** + * Unique identifier for the register adjustment transaction. + * Primary key for tracking and referencing specific adjustment records. + */ + adjustmentId: number; + /** + * Type of register adjustment being performed. + * Common values include "Adjustment", "Close Out", "Deposit", "Withdrawal", "Cash Drop". + */ + adjustmentType: string | null; + /** + * Dollar amount of the register adjustment (positive or negative). + * Positive values indicate cash added to register, negative values indicate cash removed. + */ + adjustmentAmount: number; + /** + * Name of the employee who performed the register adjustment. + * Used for accountability and audit trail purposes. + */ + adjustedBy: string | null; + /** + * Date and time when the register adjustment was performed (optional). + * Timestamp for audit trail and reconciliation purposes. + */ + adjustedOn: string | null; + /** + * Name of the register/terminal where the adjustment occurred. + * Identifies which physical register or point-of-sale terminal was adjusted. + */ + terminalName: string | null; + /** + * Unique identifier for the register/terminal where the adjustment occurred. + * Numeric identifier for the specific point-of-sale terminal. + */ + terminalId: number; + /** + * Employee ID of the staff member who performed the adjustment. + * Numeric identifier linking to the employee record for accountability. + */ + adjustedByEmployeeId: number; + /** + * Reason code or description for why the adjustment was made. + * Provides business justification for the cash adjustment. + */ + adjustmentReason: string | null; + /** + * Additional comments or notes about the register adjustment (optional). + * Free-text field for additional details or explanations. + */ + comment: string | null; +}; + +/** + * Represents a comprehensive cash flow summary for a specific register terminal. + * + * This model provides real-time cash reconciliation data including starting balances, + * transaction activity, and variance calculations for cash management and balancing + * purposes. Used for end-of-shift reconciliation and cash discrepancy identification. + */ +export type RegisterCashSummary = { + /** + * Name of the register/terminal for which this cash summary applies. + * Identifies the specific point-of-sale terminal or register location. + */ + terminalName: string | null; + /** + * Starting cash balance for the register at the beginning of the period. + * Base amount of cash in the register before any transactions occurred. + */ + startingBalance: number; + /** + * Ending cash balance for the register at the end of the period. + * Final amount of cash in the register after all transactions and adjustments. + */ + endingBalance: number; + /** + * Total cash sales processed through the register during the period. + * Includes all cash payments received for customer transactions. + */ + sales: number; + /** + * Total cash refunds and returns processed during the period. + * Represents cash paid out to customers for returned merchandise. + */ + returns: number; + /** + * Total cash deposits added to the register during the period. + * Includes cash added to the register for operational purposes. + */ + deposits: number; + /** + * Total register adjustments (positive or negative) made during the period. + * Includes manual cash corrections, withdrawals, and balancing entries. + */ + adjustments: number; + /** + * Cash variance (over or short) compared to expected register balance. + * Positive values indicate cash overage, negative values indicate shortage. + */ + overShort: number; +}; + +/** + * Represents a comprehensive register transaction record including sales, adjustments, and cash management activities. + * + * This model encompasses all types of register activity including customer sales transactions, cash adjustments, + * payment processing, register maintenance, and operational activities. Each transaction maintains complete + * audit trails with employee accountability and detailed financial information. + */ +export type RegisterTransaction = { + /** + * Unique identifier for the register transaction record. + * Primary key for tracking and referencing specific transaction activities. + */ + registerTransactionId: number; + /** + * Type of register transaction being recorded. + * Examples include "Sale", "Adjustment", "Close Out", "Deposit", "Withdrawal", "Return", "Payment". + */ + transactionType: string | null; + /** + * Dollar amount of the register transaction (positive or negative). + * Represents the financial impact of the transaction on register balances. + */ + transactionAmount: number; + /** + * Name of the employee who processed the register transaction. + * Used for accountability and performance tracking. + */ + transactionBy: string | null; + /** + * Date and time when the register transaction occurred in UTC (optional). + * Timestamp for audit trail and financial reconciliation purposes. + */ + transactionDateUTC: string | null; + /** + * Reference to the associated business transaction ID (optional). + * Links register activity to customer sales transactions when applicable. + */ + transactionId: number | null; + /** + * Name of the register/terminal where the transaction was processed. + * Identifies which physical register or point-of-sale terminal handled the transaction. + */ + terminalName: string | null; + /** + * Unique identifier for the register/terminal where the transaction occurred. + * Numeric identifier for the specific point-of-sale terminal. + */ + terminalId: number; + /** + * Employee ID of the staff member who processed the transaction. + * Numeric identifier linking to the employee record for accountability tracking. + */ + transactionByEmployeeId: number; + /** + * Reason code or description for adjustment transactions (optional). + * Provides business justification when the transaction is an adjustment or correction. + */ + adjustmentReason: string | null; + /** + * Additional comments or notes about the register transaction (optional). + * Free-text field for additional context or explanations. + */ + comment: string | null; +}; + +/** + * Regulatory category model containing state-mandated product classification information for cannabis compliance and reporting. + */ +export type RegulatoryCategory = { + /** + * Unique identifier for the regulatory category. + */ + regulatoryCategoryId: number; + /** + * Display name of the regulatory category as defined by state cannabis regulations. + */ + regulatoryCategoryName: string | null; +}; + +/** + * Extended discount model with additional reporting and administrative properties for internal operations. + */ +export type ReportingDiscountDetail = { + /** + * Indicates if discount is available for online/e-commerce ordering. + */ + isAvailableOnline: boolean; + /** + * Method used to apply the discount in the system. + */ + applicationMethod: string | null; + /** + * External system identifier for integration mapping. + */ + externalId: string | null; + /** + * Indicates if discount application requires manager approval. + */ + requireManagerApproval: boolean; + /** + * Indicates if discount has been marked as deleted. + */ + isDeleted: boolean; + /** + * Collection of location mappings where this discount applies. + */ + appliesToLocations: Array | null; + /** + * Unique identifier for the discount. + */ + discountId: number; + /** + * Display name of the discount for customer-facing applications. + */ + discountName: string | null; + /** + * Monetary discount amount or percentage value. + */ + discountAmount: number; + /** + * Promotional code required to apply the discount (optional). + */ + discountCode: string | null; + /** + * Type classification of the discount (e.g., percentage, fixed amount). + */ + discountType: string | null; + /** + * Method used to apply the discount (e.g., automatic, code required). + */ + discountMethod: string | null; + /** + * Indicates if the discount is currently active and available. + */ + isActive: boolean; + /** + * Start date and time when discount becomes valid (UTC converted from Eastern Time). + */ + validFrom: string | null; + /** + * End date and time when discount expires (UTC converted from Eastern Time). + */ + validUntil: string | null; + /** + * Type of threshold requirement for discount eligibility (optional). + */ + thresholdType: string | null; + /** + * Minimum number of qualifying items required for discount application (optional). + */ + minimumItemsRequired: number | null; + /** + * Maximum number of items that can receive the discount (optional). + */ + maximumItemsAllowed: number | null; + /** + * Maximum number of times this discount can be used (optional). + */ + maximumUsageCount: number | null; + /** + * Indicates if discount applies to non-cannabis products. + */ + includeNonCannabis: boolean; + /** + * Indicates if discount is restricted to first-time customers only. + */ + firstTimeCustomerOnly: boolean; + /** + * Indicates if discount can be combined with other discounts. + */ + stackOnOtherDiscounts: boolean; + weeklyRecurrenceInfo: WeeklyRecurrenceInfo; + products: DiscountRestriction; + productCategories: DiscountRestriction; + brands: DiscountRestriction; + vendors: DiscountRestriction; + strains: DiscountRestriction; + tiers: DiscountRestriction; + tags: DiscountRestriction; + inventoryTags: DiscountRestriction; + customerTypes: DiscountRestriction; + /** + * Associated discount groups for bundling and organization (loaded conditionally). + */ + discountGroups: Array | null; +}; + +/** + * Extended inventory item model for financial reporting with cost and allocation data. + */ +export type ReportingInventoryItem = { + /** + * Unit of measurement for unit weight, always "g" (grams). + */ + unitWeightUnit: string | null; + /** + * Unit cost of the inventory item for cost of goods sold calculations (in USD). + */ + unitCost: number | null; + /** + * Quantity of inventory allocated to orders or transfers but not yet fulfilled. + */ + allocatedQuantity: number | null; + /** + * Unique inventory record identifier for this specific inventory item. + */ + inventoryId: number; + /** + * Product identifier linking this inventory to the product catalog. + */ + productId: number; + /** + * Stock Keeping Unit (SKU) code for inventory tracking and identification. + */ + sku: string | null; + /** + * Display name of the product for customer-facing applications. + */ + productName: string | null; + /** + * Detailed product description including effects, characteristics, and usage information. + */ + description: string | null; + /** + * Category identifier for product classification (optional). + */ + categoryId: number | null; + /** + * Category name for product classification and filtering. + */ + category: string | null; + /** + * URL path to product image for display purposes. + */ + imageUrl: string | null; + /** + * Current available quantity for sale or transfer. + */ + quantityAvailable: number; + /** + * Unit of measurement for the available quantity (e.g., "g", "mg", "ea"). + */ + quantityUnits: string | null; + /** + * Weight per unit in grams for dosing and compliance calculations. + */ + unitWeight: number; + /** + * Flower equivalent amount in grams for compliance tracking. + */ + flowerEquivalent: number; + /** + * Recreational flower equivalent amount in grams (optional). + */ + recFlowerEquivalent: number | null; + /** + * Unit of measurement for flower equivalent, always "g" (grams). + */ + readonly flowerEquivalentUnits: string | null; + /** + * Batch identifier for lot tracking and quality control. + */ + batchId: number; + /** + * Human-readable batch name or lot number for tracking. + */ + batchName: string | null; + /** + * Package identifier for compliance tracking and traceability. + */ + packageId: string | null; + /** + * Current status of the package (e.g., "Active", "Testing", "Quarantine"). + */ + packageStatus: string | null; + /** + * Base unit price for retail sales. + */ + unitPrice: number; + /** + * Medical program pricing (optional, different from retail). + */ + medUnitPrice: number | null; + /** + * Recreational program pricing (optional, different from medical). + */ + recUnitPrice: number | null; + /** + * Strain identifier for cannabis products (optional). + */ + strainId: number | null; + /** + * Strain name for cannabis products. + */ + strain: string | null; + /** + * Cannabis strain classification (Hybrid, Indica, Sativa, CBD). + */ + strainType: string | null; + /** + * Product size designation for packaging and dosing information. + */ + size: string | null; + /** + * Collection of laboratory test results for this batch (included when includeLabResults=true). + */ + labResults: Array | null; + /** + * Date when laboratory testing was completed (optional). + */ + testedDate: string | null; + /** + * Date when sample was collected for laboratory testing (optional). + */ + sampleDate: string | null; + /** + * Date when product was packaged for distribution (optional). + */ + packagedDate: string | null; + /** + * Date when product was manufactured or produced (optional). + */ + manufacturingDate: string | null; + /** + * Last modification timestamp in UTC for data synchronization. + */ + lastModifiedDateUtc: string | null; + /** + * Current status of laboratory testing (e.g., "Passed", "Failed", "Pending"). + */ + labTestStatus: string | null; + /** + * Vendor identifier for the supplier of this inventory (optional). + */ + vendorId: number | null; + /** + * Vendor name for the supplier of this inventory. + */ + vendor: string | null; + /** + * Product expiration date for compliance and quality control (optional). + */ + expirationDate: string | null; + /** + * Quantity breakdown by storage room/location (included when includeRoomQuantities=true). + */ + roomQuantities: Array | null; + /** + * Pricing tier classification for bulk pricing strategies. + */ + pricingTierName: string | null; + /** + * Alternative product name for display purposes. + */ + alternateName: string | null; + /** + * Collection of compliance tags associated with this inventory package. + */ + tags: Array | null; + /** + * Brand identifier for branded products (optional). + */ + brandId: number | null; + /** + * Brand name for branded products. + */ + brandName: string | null; + /** + * Indicates if product is restricted to medical program only. + */ + medicalOnly: boolean; + /** + * External compliance system ID (METRC or BioTrack) for regulatory tracking. + */ + externalPackageId: string | null; + /** + * Producer name for cultivation and manufacturing tracking. + */ + producer: string | null; + /** + * Producer identifier for cultivation and manufacturing tracking (optional). + */ + producerId: number | null; + /** + * Package lineage information for traceability and compliance tracking. + */ + lineage: Array | null; + /** + * Potency classification indicator for dosing guidance. + */ + potencyIndicator: string | null; + /** + * Master category classification for product grouping. + */ + masterCategory: string | null; + /** + * Effective potency in milligrams for dosing calculations (optional). + */ + effectivePotencyMg: number | null; + /** + * Indicates if product contains cannabis or is cannabis-related. + */ + isCannabis: boolean; + /** + * National Drug Code for pharmaceutical tracking (optional). + */ + packageNDC: string | null; + /** + * URL to certificate of analysis or lab testing document. + */ + labResultUrl: string | null; +}; + +/** + * Request model for retagging cannabis plants with new serial numbers for compliance and tracking updates. + */ +export type RetagPlantRequest = { + /** + * Plant identifier for the cannabis plant being retagged with a new serial number. + */ + plantId: number; + /** + * New serial number for the plant identification tag replacement. + */ + serialNumber: string | null; +}; + +/** + * Detailed specification for retiring immature plants from cultivation batches with compliance documentation. + */ +export type RetireImmaturePlantsDetails = { + /** + * Batch identifier for the plant batch containing plants to be retired. + */ + batchId: number; + /** + * Number of plants to retire from the specified batch. + */ + countToRetire: number; + /** + * Standardized reason code for the plant retirement (e.g., "DISEASE", "PEST", "POOR_HEALTH", "CONTAMINATION"). + */ + reasonCode: string | null; + /** + * Date when the plants were retired for cultivation timeline documentation. + */ + retireDate: string | null; +}; + +/** + * Request model for retiring immature cannabis plants due to loss, contamination, or quality issues. + */ +export type RetireImmaturePlantsRequest = { + /** + * Collection of plant retirement specifications for batch processing of plant removals. + */ + plants: Array | null; +}; + +export type RetirePlantRequest = { + plantIds: Array | null; + reasonId: number | null; + reasonCode: string | null; + wasteType: string | null; + roomId: number; + wasteWeight: number | null; + comment: string | null; + wastePackageId: string | null; + wasteDate: string | null; + plantWeight: number | null; + plantWeightUnitId: number | null; + wasteMaterial: string | null; + wasteReason: string | null; + wasteMethod: string | null; + reasonNote: string | null; + emptyCloneGroup: boolean; +}; + +/** + * Cultivation room model containing facility area configuration information for cannabis operations and facility management. + */ +export type Room = { + /** + * Unique identifier for the cultivation room or facility area. + * **Required for updates, null/0 for new room creation.** + */ + roomId: number | null; + /** + * Human-readable name for room identification and cultivation tracking. + * **Required for both create and update operations.** + */ + roomName: string | null; + /** + * Indicates if this room is designated for quarantine operations and compliance isolation. + */ + isQuarantineRoom: boolean; + /** + * Indicates if this room is designated as a secure vault for valuable inventory storage. + */ + isVaultRoom: boolean; + /** + * Indicates if this room is designated as a customer waiting area. + */ + isWaitingRoom: boolean; + /** + * Indicates if this room is designated as the main sales floor for customer transactions. + */ + isSalesFloor: boolean; + /** + * Indicates if this room is designated for point-of-sale operations and transactions. + */ + isPOSRoom: boolean; + /** + * Indicates if this room is designated for inventory storage and management. + */ + isInventoryRoom: boolean; + /** + * Indicates if this room is designated for pre-order fulfillment operations. + */ + isPreOrderRoom: boolean; + /** + * Indicates if this room is designated for e-commerce order processing and fulfillment. + */ + isEcommerceRoom: boolean; +}; + +/** + * Room-based waste record model for facility waste disposal tracking and compliance documentation. + */ +export type RoomWaste = { + /** + * Unique identifier for the waste record. + */ + wasteId: number | null; + /** + * Reference number for waste tracking and documentation. + */ + referenceNo: string | null; + /** + * Additional comments or notes about the waste disposal. + */ + comments: string | null; + /** + * Date when the waste disposal occurred. + */ + wasteDate: string | null; + /** + * Type or category of waste material being disposed. + */ + wasteType: string | null; + /** + * Identifier for the room or facility area where waste originated. + */ + roomId: number; + /** + * Quantity of waste material being disposed. + */ + wasteAmount: number; + /** + * Unit of measurement identifier for the waste amount. + */ + unitId: number; +}; + +/** + * Response model for successful inventory receive order creation operations. + */ +export type SavedReceive = { + /** + * Unique identifier for the created receive inventory transaction. + */ + receiveInventoryHistoryId: number; +}; + +/** + * Request model for setting a product image through the product image management API. + */ +export type SetImageRequest = { + /** + * The unique identifier of the product to associate the image with. + */ + productId: number; + /** + * Base64-encoded string representation of the image file data. + */ + base64Image: string; + /** + * Original filename of the image including file extension for proper handling. + */ + fileName: string; + /** + * Computed property that converts the Base64Image string to byte array for processing. + */ + readonly image?: string | null; + fileType?: UploadFileType; +}; + +/** + * Response model for successful product image upload operations. + */ +export type SetImageResponse = { + /** + * Unique identifier assigned to the uploaded image for tracking and reference. + */ + imageId: number; + /** + * Public URL where the uploaded image can be accessed and displayed. + */ + imageUrl: string | null; +}; + +export type Severity = 0 | 1 | 2; + +/** + * Represents a product size configuration for cannabis products within an organization. + */ +export type Size = { + /** + * Unique identifier for the product size configuration. + */ + sizeId: number; + /** + * Display name for the product size. + */ + sizeName: string | null; + /** + * Detailed description of the product size and its usage. + */ + description: string | null; +}; + +export type SplitBatchDetails = { + newBatchName: string | null; + batchId: number; + location: string | null; + strain: string | null; + quantity: number; + splitDate: string | null; +}; + +export type SplitImmaturePlantResult = { + batch: Array | null; + plant: Array | null; +}; + +export type SplitImmaturePlantResultApiResult = { + result: boolean; + message: string | null; + data: SplitImmaturePlantResult; +}; + +export type SplitImmaturePlantResultDetail = { + batchId: number; + batchPlantCount: number; + newBatchId: number; + newBatchPlantCount: number; +}; + +/** + * Request model for splitting immature cannabis plant batches and individual plants for cultivation optimization. + */ +export type SplitImmaturePlantsRequest = { + /** + * Collection of batch split specifications for dividing immature plant batches into smaller groups. + */ + batch: Array | null; + /** + * Collection of individual plant split specifications for precise cultivation management. + */ + plant: Array | null; +}; + +export type SplitPlantDetails = { + batchId: number; + location: string | null; + strain: string | null; + quantity: number; + splitDate: string | null; +}; + +export type StandardAllergensDetails = { + milk: boolean; + eggs: boolean; + fish: boolean; + peanuts: boolean; + treeNuts: boolean; + sesame: boolean; + shellfish: boolean; + soybeans: boolean; + wheat: boolean; +}; + +/** + * Cannabis strain information with genetic and classification details for product categorization and cultivation tracking. + */ +export type StrainDetail = { + /** + * Unique identifier for the strain + */ + strainId: number; + /** + * Name of the cannabis strain + */ + strainName: string | null; + /** + * Detailed description of the strain's characteristics and effects + */ + strainDescription: string | null; + /** + * Short name or code for the strain + */ + strainAbbreviation: string | null; + /** + * Classification type of the strain. Valid values: `Indica`, `Sativa`, `Hybrid`, `CBD` + */ + strainType: string | null; + /** + * External system identifier for third-party integration + */ + externalId: string | null; +}; + +export type StringIEnumerableOptional = Array; + +export type StringOptional = string; + +export type SuccessResult = { + result: boolean; + message: string | null; + data: { + [key: string]: unknown; + } | null; +}; + +export type Table = { + tableId: number | null; + tableName: string | null; +}; + +export type Tag = { + tagName: string | null; + tagId: number; +}; + +/** + * Summary tax information aggregated across transaction items for reporting and receipt generation. + */ +export type TaxSummaryInfo = { + /** + * Name of the tax type being summarized (e.g., "State Excise Tax", "Sales Tax"). + */ + rateName: string | null; + /** + * Total tax amount for this tax type across all transaction items (in USD). + */ + amount: number; +}; + +/** + * Point-of-sale terminal model containing terminal identification information for retail operations and transaction processing. + */ +export type Terminal = { + /** + * Unique identifier for the point-of-sale terminal. + */ + terminalId: number; + /** + * Human-readable name for terminal identification and assignment. + */ + terminalName: string | null; +}; + +/** + * Complete cannabis retail transaction model representing all aspects of cannabis sales operations. + */ +export type Transaction = { + transactionId: number; + customerId: number; + employeeId: number; + transactionDate: string; + voidDate: string | null; + isVoid: boolean; + subtotal: number; + totalDiscount: number; + readonly totalBeforeTax: number; + tax: number; + tipAmount: number | null; + total: number; + paid: number; + changeDue: number; + totalItems: number; + terminalName: string | null; + checkInDate: string | null; + invoiceNumber: string | null; + isTaxInclusive: boolean; + /** + * Will have one of the following values: Retail, Transfer, WholesaleOrder + */ + transactionType: string | null; + /** + * Loyalty points earned on this transaction (can be negative if it's a return) + */ + loyaltyEarned: number | null; + /** + * Loyalty points spent on this transaction (can be negative if it's a return) + */ + loyaltySpent: number | null; + items: Array | null; + readonly discounts: Array | null; + lastModifiedDateUTC: string; + cashPaid: number | null; + debitPaid: number | null; + electronicPaid: number | null; + electronicPaymentMethod: string | null; + checkPaid: number | null; + creditPaid: number | null; + giftPaid: number | null; + mmapPaid: number | null; + prePaymentAmount: number | null; + revenueFeesAndDonations: number | null; + nonRevenueFeesAndDonations: number | null; + feesAndDonations: Array | null; + readonly taxSummary: Array | null; + returnOnTransactionId: number | null; + adjustmentForTransactionId: number | null; + orderType: string | null; + wasPreOrdered: boolean; + orderSource: string | null; + orderMethod: string | null; + invoiceName: string | null; + readonly isReturn: boolean; + authCode: string | null; + customerTypeId: number; + isMedical: boolean; + orderIds: Array | null; + totalCredit: number; + completedByUser: string | null; + responsibleForSaleUserId: number; + transactionDateLocalTime: string; + estTimeArrivalLocal: string | null; + readonly estDeliveryDateLocal: string | null; + referenceId: string | null; + manualPayments: Array | null; + manualPaid: number | null; + integratedPayments: Array | null; + integratedPaid: number | null; +}; + +/** + * Individual line item within a cannabis retail transaction containing product, pricing, and compliance information. + */ +export type TransactionItem = { + /** + * Parent transaction identifier linking this item to the overall transaction. + */ + transactionId: number; + /** + * Product identifier for the purchased cannabis product. + */ + productId: number; + /** + * Total price for this line item including all taxes and discounts (in USD). + */ + totalPrice: number; + /** + * Quantity of the product purchased (units based on product type - grams, pieces, etc.). + */ + quantity: number; + /** + * Unit price per individual item before taxes and discounts (in USD). + */ + unitPrice: number; + /** + * Cost basis of the product for internal accounting and margin calculations (in USD). + */ + unitCost: number | null; + /** + * State tracking system package identifier for regulatory compliance (seed-to-sale tracking). + */ + packageId: string | null; + /** + * Original source package identifier for product lineage tracking in state systems. + */ + sourcePackageId: string | null; + /** + * Total discount amount applied to this line item (in USD). + */ + totalDiscount: number; + /** + * Inventory record identifier for the specific product inventory being sold. + */ + inventoryId: number; + /** + * Unit type identifier defining how the product is measured and sold. + */ + unitId: number; + /** + * Weight of the product unit in grams (calculated for flower products with UnitId = 1). + */ + readonly unitWeight: number | null; + /** + * Unit of measurement for product weight (always "g" for grams). + */ + readonly unitWeightUnit: string | null; + /** + * Flower equivalent weight for concentrate products in grams (for regulatory compliance). + */ + flowerEquivalent: number | null; + /** + * Unit of measurement for flower equivalent (always "g" for grams). + */ + readonly flowerEquivalentUnit: string | null; + /** + * Collection of discounts applied to this transaction item. + */ + discounts: Array | null; + /** + * Collection of taxes applied to this transaction item. + */ + taxes: Array | null; + /** + * Date when this item was returned (null if not returned). + */ + returnDate: string | null; + /** + * Indicates whether this transaction item has been returned. + */ + readonly isReturned: boolean; + /** + * Transaction identifier of the return transaction that processed this item's return. + */ + returnedByTransactionId: number | null; + /** + * Reason provided for returning this item (e.g., "Defective", "Customer Dissatisfaction"). + */ + returnReason: string | null; + /** + * Cultivation batch name for product traceability and regulatory compliance. + */ + batchName: string | null; + /** + * Reference identifier to tie child items to parent items within a transaction. + * Not guaranteed to be unique outside of a single transaction. + */ + readonly transactionItemId: number; + /** + * Vendor or supplier name for the product. + */ + vendor: string | null; + /** + * Indicates whether this item represents a coupon or promotional discount rather than a physical product. + */ + isCoupon: boolean; +}; + +/** + * Measurement unit model for cannabis product tracking and inventory management. + */ +export type Unit = { + /** + * Unique identifier for the measurement unit. + */ + unitId: number; + /** + * Full name of the measurement unit (e.g., "Grams", "Ounces", "Pounds"). + */ + unitName: string | null; + /** + * Short abbreviation for the unit (e.g., "g", "oz", "lb"). + */ + abbreviation: string | null; + /** + * Unit type classification identifier linking to measurement category. + */ + unitTypeId: number; +}; + +/** + * Unit type classification model for organizing measurement units by category. + */ +export type UnitType = { + /** + * Unique identifier for the unit type category. + */ + unitTypeId: number; + /** + * Display name of the unit type category (e.g., "Weight", "Volume", "Quantity"). + */ + unitTypeName: string | null; + /** + * Short abbreviation for the unit type (e.g., "Wgt", "Vol", "Qty"). + */ + unitTypeAbbreivation: string | null; +}; + +/** + * Request model for updating laboratory test results for a specific batch by batch name. + */ +export type UpdateBatchLabResultsRequest = { + /** + * Name of the batch to update with laboratory test results (required). + */ + batchName: string; + /** + * Weight of the laboratory sample used for testing (in grams). + */ + sampleWeight?: number | null; + /** + * Collection of laboratory test results including cannabinoids and terpenes. + */ + labResults?: Array | null; +}; + +export type UpdateBatchRequest = { + batchName: string | null; + roomId: number | null; + strainId: number | null; +}; + +/** + * Request model for updating delivery route details including vehicle assignments, driver assignments, and delivery status. + */ +export type UpdateDeliveryRouteDetailRequest = { + /** + * Delivery transaction identifier to update (required). + */ + transactionId: number; + /** + * Primary driver identifier for delivery assignment (optional). + */ + driverId: number | null; + /** + * Secondary driver identifier for delivery assignment (optional). + */ + driverId2: number | null; + /** + * Vehicle identifier for delivery assignment (optional). + */ + vehicleId: number | null; + /** + * Route information or delivery notes (optional). + */ + route: string | null; + /** + * Delivery status update (optional). + */ + status: string | null; +}; + +/** + * Request model for updating existing customer journal entries with modified content and details. + */ +export type UpdateJournalEntryRequest = { + /** + * The ID of the existing journal entry to update. + */ + journalEntryId: number; + /** + * Updated title or summary for the journal entry. + */ + subject: string; + /** + * Updated detailed content and notes for the journal entry. + */ + body: string; + /** + * Updated date and time when the journal entry should be dated. + */ + date: string; +}; + +export type UpdatePackageTagsRequest = { + packageIds?: StringIEnumerableOptional; + inventoryIds?: Int32iEnumerableOptional; + /** + * Required collection of tags to apply to the specified packages (required). + */ + tags: Array; +}; + +export type UpdatePlantDetails = { + plantId: number; + serialNumber: StringOptional; + dateCreated: DateTimeNullableOptional; + bornDate: DateTimeNullableOptional; + isMother: BooleanNullableOptional; + strainId: Int32NullableOptional; + roomId: Int32NullableOptional; + tableId: Int32NullableOptional; + batchId: Int32NullableOptional; +}; + +export type UpdatePlantsRequest = { + plants: Array | null; +}; + +export type UpdatePreOrderRequest = { + orderId: number; + items: Array | null; + isDelivery: boolean; + /** + * @deprecated + */ + orderSource: string | null; + deliveryStreet: string | null; + deliveryCity: string | null; + deliveryState: string | null; + deliveryPostalCode: string | null; + deliveryScheduleId: DeliveryScheduleType; + notes: string | null; + redemptions: PreOrderRedemptionIEnumerableOptional; + customerId: number; + deliveryStreet2: string | null; + timeWindowStartDateUtc: string | null; + timeWindowEndDateUtc: string | null; +}; + +/** + * Request model for creating or updating cannabis strain information. + * + * **Create vs Update Behavior:** + * - **CREATE**: When `StrainId` is null, 0, or omitted, a new strain record will be created + * - **UPDATE**: When `StrainId` is provided with a valid strain ID, the existing strain will be updated + * + * **Sparse Update Behavior:** + * - **Provided fields**: Will overwrite existing values with provided data + * - **Omitted fields**: Will preserve existing values (no data loss for updates) + * - **Special handling**: `StrainDescription` is always required and cannot be null + */ +export type UpdateStrain = { + /** + * Unique identifier for strain updates. + * - **For CREATE**: Omit this field, set to null, or set to 0 + * - **For UPDATE**: Provide the existing strain's ID + */ + strainId?: number | null; + /** + * Name of the cannabis strain (required for creation) + */ + strainName: string; + /** + * Detailed description of the strain's characteristics and effects. + * **REQUIRED** - Cannot be null or empty for both create and update operations. + */ + strainDescription: string; + /** + * Short name or code for the strain (optional) + */ + abbreviation?: string | null; + /** + * Classification type of the strain (optional). + * **Must be one of**: `Indica`, `Sativa`, `Hybrid`, `CBD` + * If provided, value will be validated against allowed strain types. + */ + strainType?: string | null; + /** + * External system identifier for third-party integration (optional). + * Useful for synchronizing with cultivation management systems. + */ + externalId?: string | null; + broadcast?: BooleanOptional; +}; + +export type UploadFileType = 0 | 1 | 2 | 3 | 4 | 5; + +export type ValidationFailure = { + propertyName: string | null; + errorMessage: string | null; + attemptedValue: { + [key: string]: unknown; + } | null; + customState: { + [key: string]: unknown; + } | null; + severity: Severity; + errorCode: string | null; + formattedMessagePlaceholderValues: { + [key: string]: { + [key: string]: unknown; + } | null; + } | null; +}; + +export type ValidationResult = { + readonly isValid: boolean; + errors: Array | null; + ruleSetsExecuted: Array | null; +}; + +export type VehicleDetail = { + vehicleId: number; + make: string | null; + model: string | null; + modelYear: string | null; + color: string | null; + licensePlate: string | null; + vin: string | null; +}; + +/** + * Vendor information model for cannabis supply chain and compliance management. + */ +export type Vendor = { + /** + * Unique identifier for the vendor in the system (null for new vendor creation). + */ + vendorId: number | null; + /** + * Official business name of the vendor as registered with regulatory authorities. + */ + vendorName: string | null; + /** + * Street address of the vendor's business location. + */ + address: string | null; + /** + * City where the vendor's business is located. + */ + city: string | null; + /** + * State or province where the vendor's business is located. + */ + state: string | null; + /** + * Postal or ZIP code for the vendor's business address. + */ + postalCode: string | null; + /** + * Cannabis business license number issued by state regulatory authorities. + */ + licenseNumber: string | null; + /** + * Name of the primary business contact for this vendor. + */ + contactName: string | null; + /** + * Email address for business communications with the vendor. + */ + contactEmail: string | null; + /** + * Phone number for business communications with the vendor. + */ + contactPhone: string | null; +}; + +/** + * Comprehensive waste summary model containing all waste types for facility waste management and regulatory reporting. + */ +export type WasteSummary = { + /** + * Collection of room-based waste disposal records. + */ + roomWaste: Array | null; + /** + * Collection of harvest-based waste disposal records. + */ + harvestWaste: Array | null; + /** + * Collection of plant-based waste disposal records. + */ + plantWaste: Array | null; +}; + +/** + * Weekly recurring schedule model defining time-based availability patterns for discount application. + */ +export type WeeklyRecurrenceInfo = { + /** + * Daily start time when discount becomes available (optional). + */ + startTime: string | null; + /** + * Daily end time when discount expires (optional). + */ + endTime: string | null; + /** + * Indicates if discount is available on Mondays. + */ + appliesOnMonday: boolean; + /** + * Indicates if discount is available on Tuesdays. + */ + appliesOnTuesday: boolean; + /** + * Indicates if discount is available on Wednesdays. + */ + appliesOnWednesday: boolean; + /** + * Indicates if discount is available on Thursdays. + */ + appliesOnThursday: boolean; + /** + * Indicates if discount is available on Fridays. + */ + appliesOnFriday: boolean; + /** + * Indicates if discount is available on Saturdays. + */ + appliesOnSaturday: boolean; + /** + * Indicates if discount is available on Sundays. + */ + appliesOnSunday: boolean; +}; + +/** + * Anonymous transaction response model containing transaction identifiers for guest checkout operations. + */ +export type AnonymousTransactionWritable = { + /** + * Unique identifier for the customer record associated with this anonymous transaction. + */ + customerId: number; + /** + * Unique identifier for the transaction record. + */ + transactionId: number; +}; + +/** + * Discount information applied to a specific transaction item in cannabis retail operations. + */ +export type AppliedDiscountWritable = { + /** + * Unique identifier for the discount program or campaign applied. + */ + discountId: number; + /** + * Display name of the discount for customer receipts and reporting. + */ + discountName: string | null; + /** + * Reason or justification for the discount application (e.g., "Loyalty Reward", "Medical Patient"). + */ + discountReason: string | null; + /** + * Discount amount applied to the transaction item (in USD, positive value represents savings). + */ + amount: number; +}; + +/** + * Product category sales summary for cannabis retail closing reports and financial analysis. + */ +export type ClosingReportCategorySummaryWritable = { + /** + * Product category name (e.g., "Flower", "Edibles", "Concentrates"). + */ + category: string | null; + /** + * Gross sales total for the category before discounts (in USD). + */ + categoryGrossTotal: number; + /** + * Total discount amount applied to products in this category (in USD). + */ + categoryDiscountTotal: number; + /** + * Net sales total for the category after discounts (in USD). + */ + categoryNetTotal: number; + /** + * Total cost of goods sold for products in this category (in USD). + */ + categoryCost: number; +}; + +/** + * Customer type sales summary for cannabis retail closing reports and customer segment analysis. + */ +export type ClosingReportCustomerTypeSummaryWritable = { + /** + * Customer type classification (e.g., "Recreational", "Medical", "Industry"). + */ + customerType: string | null; + /** + * Gross sales total for this customer type before discounts (in USD). + */ + grossTotal: number; + /** + * Net sales total for this customer type after discounts (in USD). + */ + netTotal: number; + /** + * Total discount amount applied to this customer type (in USD). + */ + discountTotal: number; + /** + * Total cost of goods sold for this customer type (in USD). + */ + customerTypeCost: number; + /** + * Cannabis product sales total for this customer type (in USD). + */ + cannabisSales: number; + /** + * Non-cannabis product sales total for this customer type (accessories, etc.) (in USD). + */ + nonCannabisSales: number; +}; + +/** + * Order source sales summary for cannabis retail closing reports and marketing channel analysis. + */ +export type ClosingReportOrderSourceSummaryWritable = { + /** + * Order origination source (e.g., "Website", "Mobile App", "Weedmaps", "Walk-In"). + */ + orderSource: string | null; + /** + * Gross sales total for this order source before discounts (in USD). + */ + grossTotal: number; + /** + * Net sales total for this order source after discounts (in USD). + */ + netTotal: number; + /** + * Total discount amount applied to this order source (in USD). + */ + discountTotal: number; + orderSourceCost: number; +}; + +/** + * Order type sales summary for cannabis retail closing reports and fulfillment channel analysis. + */ +export type ClosingReportOrderTypeSummaryWritable = { + /** + * Order fulfillment type (e.g., "In-Store", "Pickup", "Delivery", "Curbside"). + */ + orderType: string | null; + /** + * Gross sales total for this order type before discounts (in USD). + */ + grossTotal: number; + /** + * Net sales total for this order type after discounts (in USD). + */ + netTotal: number; + /** + * Total discount amount applied to this order type (in USD). + */ + discountTotal: number; + /** + * Total cost of goods sold for this order type (in USD). + */ + orderTypeCost: number; +}; + +/** + * Enhanced closing report model for cannabis dispensary daily financial operations with payment processing integration. + */ +export type ClosingReportV2Writable = { + /** + * Tips processed through Pay-by-Bank system for electronic tip distribution. + */ + payByBankTips: number; + /** + * Transaction fees charged by Pay-by-Bank system for cost accounting. + */ + payByBankTransactionFees: number; + /** + * Batch file summaries for Pay-by-Bank transaction reconciliation. + */ + payByBankBatchFile: Array | null; + /** + * Fees and donations collected during the closing period for compliance reporting. + */ + feesDonations: Array | null; + grossSales: number | null; + discount: number | null; + loyalty: number | null; + totalTax: number | null; + cost: number | null; + coupons: number | null; + itemTotal: number | null; + transactionCount: number; + itemCount: number; + customerCount: number; + newCustomerCount: number; + voidCount: number; + voidTotal: number | null; + returnTotal: number | null; + startingBalance: number | null; + endingBalance: number | null; + deposits: number | null; + adjustments: number | null; + totalPayments: number | null; + invoiceTotal: number | null; + cannabisSales: number | null; + nonCannabisSales: number | null; + netSales: number | null; + revenueFeesDonations: number | null; + nonRevenueFeesDonations: number | null; + rounding: number | null; + totalIncome: number | null; + averageCartNetSales: number | null; + categorySummary: Array | null; + paymentSummary: Array | null; + taxSummary: Array | null; + customerTypeSummary: Array | null; + orderTypeSummary: Array | null; + orderSourceSummary: Array | null; +}; + +/** + * Represents a customer profile with personal information, contact details, and cannabis compliance data. + */ +export type CustomerWritable = { + /** + * Unique internal identifier for the customer record. + */ + customerId: number; + /** + * Deprecated name field (use FirstName and LastName instead). + * @deprecated + */ + name: string | null; + /** + * Customer's first name. + */ + firstName: string | null; + /** + * Customer's last name. + */ + lastName: string | null; + /** + * Customer's middle name. + */ + middleName: string | null; + /** + * Name suffix (Jr., Sr., III, etc.). + */ + nameSuffix: string | null; + /** + * Name prefix (Mr., Mrs., Dr., etc.). + */ + namePrefix: string | null; + /** + * Primary street address line. + */ + address1: string | null; + /** + * Secondary address line (apartment, suite, etc.). + */ + address2: string | null; + /** + * City name. + */ + city: string | null; + /** + * State or province. + */ + state: string | null; + /** + * Postal or ZIP code. + */ + postalCode: string | null; + /** + * Primary phone number. + */ + phone: string | null; + /** + * Cell phone number. + */ + cellPhone: string | null; + /** + * Email address. + */ + emailAddress: string | null; + /** + * Customer account status. + */ + status: string | null; + /** + * Medical marijuana identification number. + */ + mmjidNumber: string | null; + /** + * Medical marijuana ID expiration date. + */ + mmjidExpirationDate: string | null; + /** + * Last modification timestamp in UTC format. + */ + lastModifiedDateUTC: string | null; + /** + * Customer record creation date. + */ + creationDate: string | null; + /** + * Customer type classification. + */ + customerType: string | null; + /** + * Customer's gender. + */ + gender: string | null; + /** + * SHA2_256 hash of the Driver License ID + */ + driversLicenseHash: string | null; + /** + * Customer's date of birth. + */ + dateOfBirth: string | null; + /** + * External system customer identifier. + */ + externalCustomerId: string | null; + /** + * Name of the integration system that created this customer. + */ + createdByIntegrator: string | null; + /** + * Indicates if this is an anonymous customer record. + */ + isAnonymous: boolean; + /** + * How the customer heard about the dispensary. + */ + referralSource: string | null; + /** + * Additional details about referral source when "Other" is selected. + */ + otherReferralSource: string | null; + /** + * SpringBig loyalty system member identifier. + */ + springBigMemberId: number; + /** + * Custom identifier for external system integration. + */ + customIdentifier: string | null; + /** + * Location where this customer record was created. + */ + createdAtLocation: string | null; + /** + * Additional notes about the customer. + */ + notes: string | null; + /** + * Indicates if customer is enrolled in loyalty program. + */ + isLoyaltyMember: boolean | null; + /** + * Primary medical condition for medical marijuana patients. + */ + primaryQualifyingCondition: string | null; + /** + * Additional medical conditions for medical marijuana patients. + */ + secondaryQualifyingConditions: Array | null; + /** + * Customer ID this record was merged into (if applicable). + */ + mergedIntoCustomerId: number | null; + /** + * Customer's marketing communication preference. + */ + optedIntoMarketing: boolean | null; + /** + * Customer's current loyalty program tier. + */ + loyaltyTier: string | null; +}; + +/** + * Extended customer model that includes search match type information for customer lookup operations. + */ +export type CustomerSearchResultWritable = { + /** + * Indicates how the customer record was matched during the search operation. + */ + matchType: string | null; + /** + * Unique internal identifier for the customer record. + */ + customerId: number; + /** + * Deprecated name field (use FirstName and LastName instead). + * @deprecated + */ + name: string | null; + /** + * Customer's first name. + */ + firstName: string | null; + /** + * Customer's last name. + */ + lastName: string | null; + /** + * Customer's middle name. + */ + middleName: string | null; + /** + * Name suffix (Jr., Sr., III, etc.). + */ + nameSuffix: string | null; + /** + * Name prefix (Mr., Mrs., Dr., etc.). + */ + namePrefix: string | null; + /** + * Primary street address line. + */ + address1: string | null; + /** + * Secondary address line (apartment, suite, etc.). + */ + address2: string | null; + /** + * City name. + */ + city: string | null; + /** + * State or province. + */ + state: string | null; + /** + * Postal or ZIP code. + */ + postalCode: string | null; + /** + * Primary phone number. + */ + phone: string | null; + /** + * Cell phone number. + */ + cellPhone: string | null; + /** + * Email address. + */ + emailAddress: string | null; + /** + * Customer account status. + */ + status: string | null; + /** + * Medical marijuana identification number. + */ + mmjidNumber: string | null; + /** + * Medical marijuana ID expiration date. + */ + mmjidExpirationDate: string | null; + /** + * Last modification timestamp in UTC format. + */ + lastModifiedDateUTC: string | null; + /** + * Customer record creation date. + */ + creationDate: string | null; + /** + * Customer type classification. + */ + customerType: string | null; + /** + * Customer's gender. + */ + gender: string | null; + /** + * SHA2_256 hash of the Driver License ID + */ + driversLicenseHash: string | null; + /** + * Customer's date of birth. + */ + dateOfBirth: string | null; + /** + * External system customer identifier. + */ + externalCustomerId: string | null; + /** + * Name of the integration system that created this customer. + */ + createdByIntegrator: string | null; + /** + * Indicates if this is an anonymous customer record. + */ + isAnonymous: boolean; + /** + * How the customer heard about the dispensary. + */ + referralSource: string | null; + /** + * Additional details about referral source when "Other" is selected. + */ + otherReferralSource: string | null; + /** + * SpringBig loyalty system member identifier. + */ + springBigMemberId: number; + /** + * Custom identifier for external system integration. + */ + customIdentifier: string | null; + /** + * Location where this customer record was created. + */ + createdAtLocation: string | null; + /** + * Additional notes about the customer. + */ + notes: string | null; + /** + * Indicates if customer is enrolled in loyalty program. + */ + isLoyaltyMember: boolean | null; + /** + * Primary medical condition for medical marijuana patients. + */ + primaryQualifyingCondition: string | null; + /** + * Additional medical conditions for medical marijuana patients. + */ + secondaryQualifyingConditions: Array | null; + /** + * Customer ID this record was merged into (if applicable). + */ + mergedIntoCustomerId: number | null; + /** + * Customer's marketing communication preference. + */ + optedIntoMarketing: boolean | null; + /** + * Customer's current loyalty program tier. + */ + loyaltyTier: string | null; +}; + +export type DiscountApiResponseWritable = { + id: number | null; + externalId: string | null; + validDateFrom: string | null; + validDateTo: string | null; + maxRedemptions: number | null; + redemptionLimit: number | null; + firstTimeCustomerOnly: DiscountFirstTimeCustomer; + discountDescription: string | null; + discountCode: string | null; + applicationMethodId: DiscountApplicationMethod; + canStackAutomatically: boolean; + onlineName: string | null; + locationRestrictions: Array | null; + restrictToGroupIds: Array | null; + monday: boolean | null; + tuesday: boolean | null; + wednesday: boolean | null; + thursday: boolean | null; + friday: boolean | null; + saturday: boolean | null; + sunday: boolean | null; + isActive: boolean; + isBundledDiscount: boolean; + constraints: Array | null; + reward: DiscountRewardApiResponseWritable; + menuDisplay: DiscountMenuDisplayApiResponse; + paymentRestrictions: DiscountPaymentRestrictionApiResponse; +}; + +export type DiscountConstraintApiResponseWritable = { + discountConstraintId: number | null; + discountId: number; + thresholdMin: number | null; + includeNonCannabis: boolean; + thresholdTypeId: DiscountThresholdType; + discountItemGroupTypeId: DiscountItemGroupType; + restrictions: { + [key: string]: IRestrictionApiResponse; + } | null; +}; + +export type DiscountRewardApiResponseWritable = { + discountRewardId: number | null; + discountId: number; + calculationMethodId: CalculationMethod; + discountValue: number; + includeNonCannabis: boolean; + highestOrLowest: string | null; + thresholdTypeId: DiscountThresholdType; + itemGroupTypeId: DiscountItemGroupType; + thresholdMin: number | null; + thresholdMax: number | null; + applyToOnlyOneItem: boolean; + restrictions: { + [key: string]: IRestrictionApiResponse; + } | null; +}; + +export type InventoryDiscrepancyWritable = { + inventoryId: number | null; + packageId: string | null; + quantity: number; + roomId: number; + unitId: number; + externalQuantity: number; + externalUnitId: number; + equivalentExternalQuantity: number | null; + productName: string | null; + room: string | null; + externalRoom: string | null; + batchModeQuantity: number | null; + bioTrackCategoryName: string | null; + externalBioTrackCategoryName: string | null; + sku: string | null; + unitErrorMsg: string | null; + rooms: Array | null; + serialNumber: string | null; +}; + +/** + * Inventory item model representing current stock and product details for available inventory. + */ +export type InventoryItemWritable = { + /** + * Unit of measurement for unit weight, always "g" (grams). + */ + unitWeightUnit: string | null; + /** + * Unique inventory record identifier for this specific inventory item. + */ + inventoryId: number; + /** + * Product identifier linking this inventory to the product catalog. + */ + productId: number; + /** + * Stock Keeping Unit (SKU) code for inventory tracking and identification. + */ + sku: string | null; + /** + * Display name of the product for customer-facing applications. + */ + productName: string | null; + /** + * Detailed product description including effects, characteristics, and usage information. + */ + description: string | null; + /** + * Category identifier for product classification (optional). + */ + categoryId: number | null; + /** + * Category name for product classification and filtering. + */ + category: string | null; + /** + * URL path to product image for display purposes. + */ + imageUrl: string | null; + /** + * Current available quantity for sale or transfer. + */ + quantityAvailable: number; + /** + * Unit of measurement for the available quantity (e.g., "g", "mg", "ea"). + */ + quantityUnits: string | null; + /** + * Weight per unit in grams for dosing and compliance calculations. + */ + unitWeight: number; + /** + * Flower equivalent amount in grams for compliance tracking. + */ + flowerEquivalent: number; + /** + * Recreational flower equivalent amount in grams (optional). + */ + recFlowerEquivalent: number | null; + /** + * Batch identifier for lot tracking and quality control. + */ + batchId: number; + /** + * Human-readable batch name or lot number for tracking. + */ + batchName: string | null; + /** + * Package identifier for compliance tracking and traceability. + */ + packageId: string | null; + /** + * Current status of the package (e.g., "Active", "Testing", "Quarantine"). + */ + packageStatus: string | null; + /** + * Base unit price for retail sales. + */ + unitPrice: number; + /** + * Medical program pricing (optional, different from retail). + */ + medUnitPrice: number | null; + /** + * Recreational program pricing (optional, different from medical). + */ + recUnitPrice: number | null; + /** + * Strain identifier for cannabis products (optional). + */ + strainId: number | null; + /** + * Strain name for cannabis products. + */ + strain: string | null; + /** + * Cannabis strain classification (Hybrid, Indica, Sativa, CBD). + */ + strainType: string | null; + /** + * Product size designation for packaging and dosing information. + */ + size: string | null; + /** + * Collection of laboratory test results for this batch (included when includeLabResults=true). + */ + labResults: Array | null; + /** + * Date when laboratory testing was completed (optional). + */ + testedDate: string | null; + /** + * Date when sample was collected for laboratory testing (optional). + */ + sampleDate: string | null; + /** + * Date when product was packaged for distribution (optional). + */ + packagedDate: string | null; + /** + * Date when product was manufactured or produced (optional). + */ + manufacturingDate: string | null; + /** + * Last modification timestamp in UTC for data synchronization. + */ + lastModifiedDateUtc: string | null; + /** + * Current status of laboratory testing (e.g., "Passed", "Failed", "Pending"). + */ + labTestStatus: string | null; + /** + * Vendor identifier for the supplier of this inventory (optional). + */ + vendorId: number | null; + /** + * Vendor name for the supplier of this inventory. + */ + vendor: string | null; + /** + * Product expiration date for compliance and quality control (optional). + */ + expirationDate: string | null; + /** + * Quantity breakdown by storage room/location (included when includeRoomQuantities=true). + */ + roomQuantities: Array | null; + /** + * Pricing tier classification for bulk pricing strategies. + */ + pricingTierName: string | null; + /** + * Alternative product name for display purposes. + */ + alternateName: string | null; + /** + * Collection of compliance tags associated with this inventory package. + */ + tags: Array | null; + /** + * Brand identifier for branded products (optional). + */ + brandId: number | null; + /** + * Brand name for branded products. + */ + brandName: string | null; + /** + * Indicates if product is restricted to medical program only. + */ + medicalOnly: boolean; + /** + * External compliance system ID (METRC or BioTrack) for regulatory tracking. + */ + externalPackageId: string | null; + /** + * Producer name for cultivation and manufacturing tracking. + */ + producer: string | null; + /** + * Producer identifier for cultivation and manufacturing tracking (optional). + */ + producerId: number | null; + /** + * Package lineage information for traceability and compliance tracking. + */ + lineage: Array | null; + /** + * Potency classification indicator for dosing guidance. + */ + potencyIndicator: string | null; + /** + * Master category classification for product grouping. + */ + masterCategory: string | null; + /** + * Effective potency in milligrams for dosing calculations (optional). + */ + effectivePotencyMg: number | null; + /** + * Indicates if product contains cannabis or is cannabis-related. + */ + isCannabis: boolean; + /** + * National Drug Code for pharmaceutical tracking (optional). + */ + packageNDC: string | null; + /** + * URL to certificate of analysis or lab testing document. + */ + labResultUrl: string | null; +}; + +/** + * Laboratory testing result model for cannabis and cannabis product analysis. + */ +export type LabResultWritable = { + /** + * Name of the laboratory test performed (e.g., "THC", "CBD", "Myrcene", "Total Aerobic Count"). + */ + labTest: string | null; + /** + * Numeric test result value (null if not detected or not applicable). + */ + value: number | null; + labResultUnitId: LabResultUnit; +}; + +/** + * Tax information applied to individual transaction line items in cannabis retail operations. + */ +export type LineItemTaxInfoWritable = { + /** + * Name of the tax rate applied (e.g., "State Excise Tax", "City Cannabis Tax", "Sales Tax"). + */ + rateName: string | null; + /** + * Tax rate as a decimal percentage (e.g., 0.0875 for 8.75% tax rate). + */ + rate: number; + /** + * Calculated tax amount applied to the line item (in USD). + */ + amount: number; +}; + +/** + * Location identity model containing complete location and parent company information for API key verification and context identification. + */ +export type LocationIdentityWritable = { + /** + * Unique identifier for the cannabis dispensary location. + */ + locationId: number; + /** + * Unique identifier for the parent company (LSP - Licensed Service Provider). + */ + lspId: number; + /** + * Business name of the cannabis dispensary location. + */ + locationName: string | null; + /** + * Company name of the parent organization (Licensed Service Provider). + */ + lspName: string | null; + /** + * Primary street address of the dispensary location. + */ + address: string | null; + /** + * Secondary address line (suite, unit, etc.) if applicable. + */ + address2: string | null; + /** + * City where the dispensary is located. + */ + city: string | null; + /** + * State or province where the dispensary is licensed to operate. + */ + state: string | null; + /** + * Postal code (ZIP code) for the dispensary location. + */ + postalCode: string | null; + /** + * State-issued cannabis business license number for regulatory compliance. + */ + licenseNumber: string | null; + /** + * "Doing Business As" name if different from the legal business name. + */ + doingBusinessAs: string | null; + /** + * Indicates whether customer profiles are shared across locations within the organization. + */ + shareCustomerProfiles: boolean; + /** + * Legacy global unique identifier for the location (deprecated). + * @deprecated + */ + globalId: string | null; + /** + * Global unique identifier for the location across all systems and integrations. + */ + locationGlobalId: string | null; + /** + * Global unique identifier for the parent company (LSP) across all systems. + */ + lspGlobalId: string | null; + /** + * Regional identifier for compliance and API routing (internal use only). + */ + region: string | null; +}; + +export type LocationResponseWritable = { + locationName: string | null; + locId: number; + licenseNumber: string | null; + broadcastedTo: string | null; + errorDetail: string | null; +}; + +export type PlantWritable = { + plantId: number; + serialNumber: string | null; + growthPhase: string | null; + type: string | null; + harvestedWeight: number | null; + status: string | null; + plantCount: number | null; + isMother: boolean; + motherPlantId: number | null; + plantedOn: string | null; + addedToHarvestOn: string | null; + harvestDate: string | null; + destroyedDate: string | null; + plantGroupName: string | null; + strain: string | null; + room: string | null; + table: string | null; + vegetationStartedOn: string | null; + vegetationEndedOn: string | null; + floweringStartedOn: string | null; + floweringEndedOn: string | null; + currentPhaseStartDate: string | null; + lastModifiedDate: string | null; + daysInCurrentPhase: number | null; + floweringRoom: string | null; + floweringTable: string | null; + vegetationRoom: string | null; + vegetationTable: string | null; + daysInFlowering: number | null; + daysInVegetation: number | null; + batchId: number; +}; + +export type ProductDetailWritable = { + productId: number; + sku: string | null; + internalName: string | null; + productName: string | null; + description: string | null; + masterCategory: string | null; + categoryId: number | null; + category: string | null; + imageUrl: string | null; + imageUrls: Array | null; + strainId: number | null; + strain: string | null; + strainType: string | null; + size: string | null; + netWeight: number | null; + netWeightUnitId: number | null; + brandId: number | null; + brandName: string | null; + vendorId: number | null; + vendorName: string | null; + isCannabis: boolean; + isActive: boolean; + isCoupon: boolean; + thcContent: number | null; + thcContentUnit: string | null; + cbdContent: number | null; + cbdContentUnit: string | null; + productGrams: number | null; + flowerEquivalent: number | null; + recFlowerEquivalent: number | null; + price: number | null; + medPrice: number | null; + recPrice: number | null; + unitCost: number | null; + unitType: string | null; + onlineTitle: string | null; + onlineDescription: string | null; + posProducts: boolean | null; + pricingTier: number | null; + onlineAvailable: boolean | null; + lowInventoryThreshold: number | null; + pricingTierName: string | null; + pricingTierDescription: string | null; + pricingTierData: Array | null; + flavor: string | null; + alternateName: string | null; + lineageName: string | null; + distillationName: string | null; + maxPurchaseablePerTransaction: number | null; + tags: Array | null; + effects: Array | null; + dosage: string | null; + instructions: string | null; + allergens: string | null; + standardAllergens: StandardAllergensDetails; + defaultUnit: string | null; + producerId: number | null; + producerName: string | null; + createdDate: string | null; + isMedicalOnly: boolean; + lastModifiedDateUTC: string | null; + grossWeight: number | null; + isTaxable: boolean | null; + taxCategories: Array | null; + upc: string | null; + regulatoryCategory: string | null; + ndc: string | null; + daysSupply: number | null; + externalCategory: string | null; + externalId: string | null; + syncExternally: boolean; + regulatoryName: string | null; + broadcastedResponses: BroadcastedResponses; + administrationMethod: string | null; + unitCBDContentDose: number | null; + unitTHCContentDose: number | null; + oilVolume: number | null; + ingredientList: string | null; + expirationDays: number | null; + abbreviation: string | null; + isTestProduct: boolean; + isFinished: boolean; + allowAutomaticDiscounts: boolean; + servingSize: string | null; + servingSizePerUnit: number | null; + isNutrient: boolean; + approvalDateUTC: string | null; + ecomCategory: string | null; + ecomSubcategory: string | null; + customMetadata: string | null; +}; + +/** + * Extended inventory item model for financial reporting with cost and allocation data. + */ +export type ReportingInventoryItemWritable = { + /** + * Unit of measurement for unit weight, always "g" (grams). + */ + unitWeightUnit: string | null; + /** + * Unit cost of the inventory item for cost of goods sold calculations (in USD). + */ + unitCost: number | null; + /** + * Quantity of inventory allocated to orders or transfers but not yet fulfilled. + */ + allocatedQuantity: number | null; + /** + * Unique inventory record identifier for this specific inventory item. + */ + inventoryId: number; + /** + * Product identifier linking this inventory to the product catalog. + */ + productId: number; + /** + * Stock Keeping Unit (SKU) code for inventory tracking and identification. + */ + sku: string | null; + /** + * Display name of the product for customer-facing applications. + */ + productName: string | null; + /** + * Detailed product description including effects, characteristics, and usage information. + */ + description: string | null; + /** + * Category identifier for product classification (optional). + */ + categoryId: number | null; + /** + * Category name for product classification and filtering. + */ + category: string | null; + /** + * URL path to product image for display purposes. + */ + imageUrl: string | null; + /** + * Current available quantity for sale or transfer. + */ + quantityAvailable: number; + /** + * Unit of measurement for the available quantity (e.g., "g", "mg", "ea"). + */ + quantityUnits: string | null; + /** + * Weight per unit in grams for dosing and compliance calculations. + */ + unitWeight: number; + /** + * Flower equivalent amount in grams for compliance tracking. + */ + flowerEquivalent: number; + /** + * Recreational flower equivalent amount in grams (optional). + */ + recFlowerEquivalent: number | null; + /** + * Batch identifier for lot tracking and quality control. + */ + batchId: number; + /** + * Human-readable batch name or lot number for tracking. + */ + batchName: string | null; + /** + * Package identifier for compliance tracking and traceability. + */ + packageId: string | null; + /** + * Current status of the package (e.g., "Active", "Testing", "Quarantine"). + */ + packageStatus: string | null; + /** + * Base unit price for retail sales. + */ + unitPrice: number; + /** + * Medical program pricing (optional, different from retail). + */ + medUnitPrice: number | null; + /** + * Recreational program pricing (optional, different from medical). + */ + recUnitPrice: number | null; + /** + * Strain identifier for cannabis products (optional). + */ + strainId: number | null; + /** + * Strain name for cannabis products. + */ + strain: string | null; + /** + * Cannabis strain classification (Hybrid, Indica, Sativa, CBD). + */ + strainType: string | null; + /** + * Product size designation for packaging and dosing information. + */ + size: string | null; + /** + * Collection of laboratory test results for this batch (included when includeLabResults=true). + */ + labResults: Array | null; + /** + * Date when laboratory testing was completed (optional). + */ + testedDate: string | null; + /** + * Date when sample was collected for laboratory testing (optional). + */ + sampleDate: string | null; + /** + * Date when product was packaged for distribution (optional). + */ + packagedDate: string | null; + /** + * Date when product was manufactured or produced (optional). + */ + manufacturingDate: string | null; + /** + * Last modification timestamp in UTC for data synchronization. + */ + lastModifiedDateUtc: string | null; + /** + * Current status of laboratory testing (e.g., "Passed", "Failed", "Pending"). + */ + labTestStatus: string | null; + /** + * Vendor identifier for the supplier of this inventory (optional). + */ + vendorId: number | null; + /** + * Vendor name for the supplier of this inventory. + */ + vendor: string | null; + /** + * Product expiration date for compliance and quality control (optional). + */ + expirationDate: string | null; + /** + * Quantity breakdown by storage room/location (included when includeRoomQuantities=true). + */ + roomQuantities: Array | null; + /** + * Pricing tier classification for bulk pricing strategies. + */ + pricingTierName: string | null; + /** + * Alternative product name for display purposes. + */ + alternateName: string | null; + /** + * Collection of compliance tags associated with this inventory package. + */ + tags: Array | null; + /** + * Brand identifier for branded products (optional). + */ + brandId: number | null; + /** + * Brand name for branded products. + */ + brandName: string | null; + /** + * Indicates if product is restricted to medical program only. + */ + medicalOnly: boolean; + /** + * External compliance system ID (METRC or BioTrack) for regulatory tracking. + */ + externalPackageId: string | null; + /** + * Producer name for cultivation and manufacturing tracking. + */ + producer: string | null; + /** + * Producer identifier for cultivation and manufacturing tracking (optional). + */ + producerId: number | null; + /** + * Package lineage information for traceability and compliance tracking. + */ + lineage: Array | null; + /** + * Potency classification indicator for dosing guidance. + */ + potencyIndicator: string | null; + /** + * Master category classification for product grouping. + */ + masterCategory: string | null; + /** + * Effective potency in milligrams for dosing calculations (optional). + */ + effectivePotencyMg: number | null; + /** + * Indicates if product contains cannabis or is cannabis-related. + */ + isCannabis: boolean; + /** + * National Drug Code for pharmaceutical tracking (optional). + */ + packageNDC: string | null; + /** + * URL to certificate of analysis or lab testing document. + */ + labResultUrl: string | null; +}; + +/** + * Request model for setting a product image through the product image management API. + */ +export type SetImageRequestWritable = { + /** + * The unique identifier of the product to associate the image with. + */ + productId: number; + /** + * Base64-encoded string representation of the image file data. + */ + base64Image: string; + /** + * Original filename of the image including file extension for proper handling. + */ + fileName: string; + fileType?: UploadFileType; +}; + +/** + * Complete cannabis retail transaction model representing all aspects of cannabis sales operations. + */ +export type TransactionWritable = { + transactionId: number; + customerId: number; + employeeId: number; + transactionDate: string; + voidDate: string | null; + isVoid: boolean; + subtotal: number; + totalDiscount: number; + tax: number; + tipAmount: number | null; + total: number; + paid: number; + changeDue: number; + totalItems: number; + terminalName: string | null; + checkInDate: string | null; + invoiceNumber: string | null; + isTaxInclusive: boolean; + /** + * Will have one of the following values: Retail, Transfer, WholesaleOrder + */ + transactionType: string | null; + /** + * Loyalty points earned on this transaction (can be negative if it's a return) + */ + loyaltyEarned: number | null; + /** + * Loyalty points spent on this transaction (can be negative if it's a return) + */ + loyaltySpent: number | null; + items: Array | null; + lastModifiedDateUTC: string; + cashPaid: number | null; + debitPaid: number | null; + electronicPaid: number | null; + electronicPaymentMethod: string | null; + checkPaid: number | null; + creditPaid: number | null; + giftPaid: number | null; + mmapPaid: number | null; + prePaymentAmount: number | null; + revenueFeesAndDonations: number | null; + nonRevenueFeesAndDonations: number | null; + feesAndDonations: Array | null; + returnOnTransactionId: number | null; + adjustmentForTransactionId: number | null; + orderType: string | null; + wasPreOrdered: boolean; + orderSource: string | null; + orderMethod: string | null; + invoiceName: string | null; + authCode: string | null; + customerTypeId: number; + isMedical: boolean; + orderIds: Array | null; + totalCredit: number; + completedByUser: string | null; + responsibleForSaleUserId: number; + transactionDateLocalTime: string; + estTimeArrivalLocal: string | null; + referenceId: string | null; + manualPayments: Array | null; + manualPaid: number | null; + integratedPayments: Array | null; + integratedPaid: number | null; +}; + +/** + * Individual line item within a cannabis retail transaction containing product, pricing, and compliance information. + */ +export type TransactionItemWritable = { + /** + * Parent transaction identifier linking this item to the overall transaction. + */ + transactionId: number; + /** + * Product identifier for the purchased cannabis product. + */ + productId: number; + /** + * Total price for this line item including all taxes and discounts (in USD). + */ + totalPrice: number; + /** + * Quantity of the product purchased (units based on product type - grams, pieces, etc.). + */ + quantity: number; + /** + * Unit price per individual item before taxes and discounts (in USD). + */ + unitPrice: number; + /** + * Cost basis of the product for internal accounting and margin calculations (in USD). + */ + unitCost: number | null; + /** + * State tracking system package identifier for regulatory compliance (seed-to-sale tracking). + */ + packageId: string | null; + /** + * Original source package identifier for product lineage tracking in state systems. + */ + sourcePackageId: string | null; + /** + * Total discount amount applied to this line item (in USD). + */ + totalDiscount: number; + /** + * Inventory record identifier for the specific product inventory being sold. + */ + inventoryId: number; + /** + * Unit type identifier defining how the product is measured and sold. + */ + unitId: number; + /** + * Flower equivalent weight for concentrate products in grams (for regulatory compliance). + */ + flowerEquivalent: number | null; + /** + * Collection of discounts applied to this transaction item. + */ + discounts: Array | null; + /** + * Collection of taxes applied to this transaction item. + */ + taxes: Array | null; + /** + * Date when this item was returned (null if not returned). + */ + returnDate: string | null; + /** + * Transaction identifier of the return transaction that processed this item's return. + */ + returnedByTransactionId: number | null; + /** + * Reason provided for returning this item (e.g., "Defective", "Customer Dissatisfaction"). + */ + returnReason: string | null; + /** + * Cultivation batch name for product traceability and regulatory compliance. + */ + batchName: string | null; + /** + * Vendor or supplier name for the product. + */ + vendor: string | null; + /** + * Indicates whether this item represents a coupon or promotional discount rather than a physical product. + */ + isCoupon: boolean; +}; + +export type ValidationResultWritable = { + errors: Array | null; + ruleSetsExecuted: Array | null; +}; + +export type BatchLabResultsPostData = { + /** + * Batch lab results update request with batch name and lab data - UpdateBatchLabResultsRequest object + */ + body?: UpdateBatchLabResultsRequest; + path?: never; + query?: never; + url: '/batch/lab-results'; +}; + +export type BatchLabResultsPostErrors = { + /** + * Bad Request - String error message (parse response body as plain text) OR `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: ValidationResult; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Not Found - Batch with specified name does not exist + */ + 404: string; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type BatchLabResultsPostError = BatchLabResultsPostErrors[keyof BatchLabResultsPostErrors]; + +export type BatchLabResultsPostResponses = { + /** + * Success - Lab results successfully created or updated + */ + 200: unknown; +}; + +export type BrandGetData = { + body?: never; + path?: never; + query?: never; + url: '/brand'; +}; + +export type BrandGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for brand access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type BrandGetResponses = { + /** + * Success - Returns array of brand objects: `[{ Brand }, ...]` + */ + 200: Array; +}; + +export type BrandGetResponse = BrandGetResponses[keyof BrandGetResponses]; + +export type BrandPostData = { + /** + * Brand information to create or update - BrandEditRequest object with brand details + */ + body?: BrandEditRequest; + path?: never; + query?: never; + url: '/brand'; +}; + +export type BrandPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Internal server error + */ + 500: unknown; +}; + +export type BrandPostError = BrandPostErrors[keyof BrandPostErrors]; + +export type BrandPostResponses = { + /** + * Success - Returns brand object: `{ Brand }` + */ + 200: Brand; +}; + +export type BrandPostResponse = BrandPostResponses[keyof BrandPostResponses]; + +export type CustomerCustomersGetData = { + body?: never; + path?: never; + query?: { + /** + * Optional date filter to return customers modified after this timestamp - Used for incremental sync + */ + fromLastModifiedDateUTC?: string; + /** + * Optional date filter to return customers modified before this timestamp - Used for date range filtering + */ + toLastModifiedDateUTC?: string; + /** + * Optional customer ID to return a specific customer by internal ID + */ + customerID?: number; + /** + * Include/exclude anonymous customers in results - Default: true + */ + includeAnonymous?: boolean; + /** + * Optional unique ID to return a specific customer by unique identifier - Must be valid long integer when provided + */ + uniqueId?: string; + }; + url: '/customer/customers'; +}; + +export type CustomerCustomersGetErrors = { + /** + * Bad Request - Invalid date range or uniqueId format + */ + 400: BadRequestResponse; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for customer data operations + */ + 403: unknown; + /** + * Not Found - Customer not found when searching by customerID or uniqueId + */ + 404: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type CustomerCustomersGetError = CustomerCustomersGetErrors[keyof CustomerCustomersGetErrors]; + +export type CustomerCustomersGetResponses = { + /** + * Success - Returns array of customer objects: `[{ Customer }, ...]` + */ + 200: Array; +}; + +export type CustomerCustomersGetResponse = CustomerCustomersGetResponses[keyof CustomerCustomersGetResponses]; + +export type CustomerCustomersPaginatedGetData = { + body?: never; + path?: never; + query?: { + /** + * Optional date filter to return customers modified after this timestamp + */ + fromLastModifiedDateUTC?: string; + /** + * Optional date filter to return customers modified before this timestamp + */ + toLastModifiedDateUTC?: string; + /** + * Page number for sequential pagination (integer, starts at 0) - Default: 0 + */ + PageNumber?: number; + /** + * Number of items per page (integer) - Default: 1000, Maximum: 10000 + */ + PageSize?: number; + /** + * Include/exclude anonymous customers in results - Default: true + */ + includeAnonymous?: boolean; + }; + url: '/customer/customers-paginated'; +}; + +export type CustomerCustomersPaginatedGetErrors = { + /** + * Bad Request - PageSize exceeds maximum limit of 10,000 + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type CustomerCustomersPaginatedGetError = CustomerCustomersPaginatedGetErrors[keyof CustomerCustomersPaginatedGetErrors]; + +export type CustomerCustomersPaginatedGetResponses = { + /** + * Success + */ + 200: Array; +}; + +export type CustomerCustomersPaginatedGetResponse = CustomerCustomersPaginatedGetResponses[keyof CustomerCustomersPaginatedGetResponses]; + +export type CustomerCustomerTypesGetData = { + body?: never; + path?: never; + query?: never; + url: '/customer/customer-types'; +}; + +export type CustomerCustomerTypesGetErrors = { + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type CustomerCustomerTypesGetResponses = { + /** + * Success + */ + 200: Array; +}; + +export type CustomerCustomerTypesGetResponse = CustomerCustomerTypesGetResponses[keyof CustomerCustomerTypesGetResponses]; + +export type CustomerReferralSourcesGetData = { + body?: never; + path?: never; + query?: never; + url: '/customer/referral-sources'; +}; + +export type CustomerReferralSourcesGetErrors = { + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type CustomerReferralSourcesGetResponses = { + /** + * Success + */ + 200: Array; +}; + +export type CustomerReferralSourcesGetResponse = CustomerReferralSourcesGetResponses[keyof CustomerReferralSourcesGetResponses]; + +export type CustomerCustomerPostData = { + /** + * Customer information to create or update - EcomCustomerEdit object with customer details + */ + body?: EcomCustomerEdit; + headers?: { + /** + * Optional GUID for idempotency checks. When provided with IdempotencyKey in request body, prevents duplicate customer creation + */ + ConsumerKey?: string; + }; + path?: never; + query?: { + /** + * Skip duplicate detection and force creation of new customer record - Default: false + */ + bypassDeduplication?: boolean; + }; + url: '/customer/customer'; +}; + +export type CustomerCustomerPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for customer management + */ + 403: unknown; + /** + * Not Found - Customer ID provided for update but customer does not exist + */ + 404: string; + /** + * Internal Server Error - Server error occurred during customer processing + */ + 500: unknown; +}; + +export type CustomerCustomerPostError = CustomerCustomerPostErrors[keyof CustomerCustomerPostErrors]; + +export type CustomerCustomerPostResponses = { + /** + * Success - Returns complete Customer object with assigned ID and loyalty status + */ + 200: Customer; +}; + +export type CustomerCustomerPostResponse = CustomerCustomerPostResponses[keyof CustomerCustomerPostResponses]; + +export type CustomerCustomerLookupPostData = { + body?: EcomCustomerEdit; + path?: never; + query?: never; + url: '/customer/customerLookup'; +}; + +export type CustomerCustomerLookupPostErrors = { + /** + * Bad Request + */ + 400: BadRequestResponse; + /** + * Unauthorized + */ + 401: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Not Found + */ + 404: string; + /** + * Internal Server Error + */ + 500: unknown; +}; + +export type CustomerCustomerLookupPostError = CustomerCustomerLookupPostErrors[keyof CustomerCustomerLookupPostErrors]; + +export type CustomerCustomerLookupPostResponses = { + /** + * OK + */ + 200: Customer; +}; + +export type CustomerCustomerLookupPostResponse = CustomerCustomerLookupPostResponses[keyof CustomerCustomerLookupPostResponses]; + +export type CustomerSearchPostData = { + /** + * Customer search request with search criteria - CustomerSearchRequest object + */ + body?: CustomerSearchRequest; + path?: never; + query?: never; + url: '/customer/search'; +}; + +export type CustomerSearchPostErrors = { + /** + * Bad Request - Validation errors or no search criteria provided + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type CustomerSearchPostError = CustomerSearchPostErrors[keyof CustomerSearchPostErrors]; + +export type CustomerSearchPostResponses = { + /** + * Success + */ + 200: Array; +}; + +export type CustomerSearchPostResponse = CustomerSearchPostResponses[keyof CustomerSearchPostResponses]; + +export type CustomerByExternalIdGetData = { + body?: never; + path?: never; + query?: { + externalId?: string; + }; + url: '/customer/by-external-id'; +}; + +export type CustomerByExternalIdGetErrors = { + /** + * Bad Request + */ + 400: BadRequestResponse; + /** + * Unauthorized + */ + 401: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Not Found + */ + 404: unknown; + /** + * Internal Server Error + */ + 500: unknown; +}; + +export type CustomerByExternalIdGetError = CustomerByExternalIdGetErrors[keyof CustomerByExternalIdGetErrors]; + +export type CustomerByExternalIdGetResponses = { + /** + * OK + */ + 200: Array; +}; + +export type CustomerByExternalIdGetResponse = CustomerByExternalIdGetResponses[keyof CustomerByExternalIdGetResponses]; + +export type CustomerJournalGetData = { + body?: never; + path?: never; + query?: { + /** + * Internal customer ID to retrieve journal entries for - Must exist and be accessible to your location + */ + customerId?: number; + }; + url: '/customer-journal'; +}; + +export type CustomerJournalGetErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for customer access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type CustomerJournalGetError = CustomerJournalGetErrors[keyof CustomerJournalGetErrors]; + +export type CustomerJournalGetResponses = { + /** + * Success - Returns array of journal entry objects: `[{ JournalEntry }, ...]` + */ + 200: Array; +}; + +export type CustomerJournalGetResponse = CustomerJournalGetResponses[keyof CustomerJournalGetResponses]; + +export type CustomerJournalUpdatePostData = { + /** + * Journal entry update request with required fields to update - UpdateJournalEntryRequest object + */ + body?: UpdateJournalEntryRequest; + path?: never; + query?: never; + url: '/customer-journal/update'; +}; + +export type CustomerJournalUpdatePostErrors = { + /** + * Bad Request - Validation errors or invalid journal entry ID + */ + 400: BadRequestResponse; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for customer access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type CustomerJournalUpdatePostError = CustomerJournalUpdatePostErrors[keyof CustomerJournalUpdatePostErrors]; + +export type CustomerJournalUpdatePostResponses = { + /** + * Success - Returns journal entry object: `{ JournalEntry }` + */ + 200: JournalEntry; +}; + +export type CustomerJournalUpdatePostResponse = CustomerJournalUpdatePostResponses[keyof CustomerJournalUpdatePostResponses]; + +export type CustomerJournalCreatePostData = { + /** + * Journal entry creation request with customer ID and entry details - CreateJournalEntryRequest object + */ + body?: CreateJournalEntryRequest; + path?: never; + query?: never; + url: '/customer-journal/create'; +}; + +export type CustomerJournalCreatePostErrors = { + /** + * Bad Request - Validation errors or invalid customer ID + */ + 400: BadRequestResponse; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for customer access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type CustomerJournalCreatePostError = CustomerJournalCreatePostErrors[keyof CustomerJournalCreatePostErrors]; + +export type CustomerJournalCreatePostResponses = { + /** + * Success - Returns journal entry object: `{ JournalEntry }` + */ + 200: JournalEntry; +}; + +export type CustomerJournalCreatePostResponse = CustomerJournalCreatePostResponses[keyof CustomerJournalCreatePostResponses]; + +export type DeliveriesGetData = { + body?: never; + path?: never; + query?: { + /** + * Pre-order ID to get delivery status for - Optional, mutually exclusive with other filters + */ + PreOrderId?: number; + /** + * Transaction ID to get delivery status for - Optional, mutually exclusive with other filters + */ + TransactionId?: number; + /** + * Array of transaction IDs to get delivery status for - Optional, mutually exclusive with other filters + */ + transactionIds?: Array; + /** + * Include detailed line item data in response - Default: false + */ + includeLineItems?: boolean; + /** + * Filter deliveries by status - Optional, mutually exclusive with other filters + */ + deliveryStatus?: string; + }; + url: '/Deliveries'; +}; + +export type DeliveriesGetErrors = { + /** + * Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: ValidationResult; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for delivery access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type DeliveriesGetError = DeliveriesGetErrors[keyof DeliveriesGetErrors]; + +export type DeliveriesGetResponses = { + /** + * Success - Returns array of delivery objects: `[{ DeliveryOrderStatus }, ...]` + */ + 200: Array; +}; + +export type DeliveriesGetResponse = DeliveriesGetResponses[keyof DeliveriesGetResponses]; + +export type DeliveriesSetRouteDetailPostData = { + /** + * Delivery route detail update request with transaction ID and delivery information - UpdateDeliveryRouteDetailRequest object + */ + body?: UpdateDeliveryRouteDetailRequest; + path?: never; + query?: never; + url: '/Deliveries/set-route-detail'; +}; + +export type DeliveriesSetRouteDetailPostErrors = { + /** + * Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: ValidationResult; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for delivery access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type DeliveriesSetRouteDetailPostError = DeliveriesSetRouteDetailPostErrors[keyof DeliveriesSetRouteDetailPostErrors]; + +export type DeliveriesSetRouteDetailPostResponses = { + /** + * Success - Route details successfully updated + */ + 200: unknown; +}; + +export type DiscountsGetData = { + body?: never; + path?: never; + query?: { + /** + * Include deleted or inactive discounts in results - Default: false + */ + includeInactive?: boolean; + /** + * Include detailed product/category restriction data - Default: false + */ + includeInclusionExclusionData?: boolean; + }; + url: '/discounts'; +}; + +export type DiscountsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type DiscountsGetResponses = { + /** + * Success - Returns array of basic discount information + */ + 200: Array; +}; + +export type DiscountsGetResponse = DiscountsGetResponses[keyof DiscountsGetResponses]; + +export type DiscountsV2ListGetData = { + body?: never; + path?: never; + query?: { + /** + * Include deleted or inactive discounts in results - Default: false + */ + includeInactive?: boolean; + /** + * Include detailed product/category restriction data - Default: false + */ + includeInclusionExclusionData?: boolean; + /** + * Include credit card and payment method restrictions - Default: false + */ + includePaymentRestrictions?: boolean; + }; + url: '/discounts/v2/list'; +}; + +export type DiscountsV2ListGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type DiscountsV2ListGetResponses = { + /** + * Success - Returns array of comprehensive discount configuration objects + */ + 200: Array; +}; + +export type DiscountsV2ListGetResponse = DiscountsV2ListGetResponses[keyof DiscountsV2ListGetResponses]; + +export type DriversGetData = { + body?: never; + path?: never; + query?: never; + url: '/drivers'; +}; + +export type DriversGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for driver access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type DriversGetResponses = { + /** + * Success - Returns array of driver objects: `[{ DriverDetail }, ...]` + */ + 200: Array; +}; + +export type DriversGetResponse = DriversGetResponses[keyof DriversGetResponses]; + +export type DriversPostData = { + /** + * Driver information to create or update - DriverDetail object with driver details + */ + body?: DriverDetail; + path?: never; + query?: never; + url: '/drivers'; +}; + +export type DriversPostErrors = { + /** + * Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: ValidationResult; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for driver access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type DriversPostError = DriversPostErrors[keyof DriversPostErrors]; + +export type DriversPostResponses = { + /** + * Success - Driver successfully created or updated + */ + 200: unknown; +}; + +export type EmployeesGetData = { + body?: never; + path?: never; + query?: never; + url: '/employees'; +}; + +export type EmployeesGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for employee access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type EmployeesGetResponses = { + /** + * Success - Returns array of Employee objects: `[{ Employee }, ...]` + */ + 200: Array; +}; + +export type EmployeesGetResponse = EmployeesGetResponses[keyof EmployeesGetResponses]; + +export type GuestlistGetData = { + body?: never; + path?: never; + query?: never; + url: '/guestlist'; +}; + +export type GuestlistGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for customer access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type GuestlistGetResponses = { + /** + * Success - Returns array of guest objects: `[{ GuestListEntry }, ...]` + */ + 200: Array; +}; + +export type GuestlistGetResponse = GuestlistGetResponses[keyof GuestlistGetResponses]; + +export type HarvestGetData = { + body?: never; + path?: never; + query?: { + /** + * Filter harvests modified after this date for incremental sync - Optional + */ + fromLastModifiedDateUTC?: string; + /** + * Filter harvests modified before this date for date range filtering - Optional + */ + toLastModifiedDateUTC?: string; + /** + * Filter by harvest status: true=active, false=completed, null=completed only - Default: null (completed only) + */ + activeHarvests?: boolean; + }; + url: '/harvest'; +}; + +export type HarvestGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for cultivation or inventory access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type HarvestGetResponses = { + /** + * Success - Returns array of harvest objects: `[{ Harvest }, ...]` + */ + 200: Array; +}; + +export type HarvestGetResponse = HarvestGetResponses[keyof HarvestGetResponses]; + +export type HarvestPostData = { + /** + * Harvest information to create or update - CreateOrUpdateHarvest object with harvest details + */ + body?: CreateOrUpdateHarvest; + path?: never; + query?: never; + url: '/harvest'; +}; + +export type HarvestPostErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for cultivation write access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type HarvestPostResponses = { + /** + * Success - Returns harvest ID for created or updated harvest: `integer` + */ + 200: number; +}; + +export type HarvestPostResponse = HarvestPostResponses[keyof HarvestPostResponses]; + +export type HarvestBulkPostData = { + /** + * Bulk harvest request with array of harvest operations - BulkCreateOrUpdateHarvest object + */ + body?: BulkCreateOrUpdateHarvest; + path?: never; + query?: never; + url: '/harvest/bulk'; +}; + +export type HarvestBulkPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for cultivation write access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type HarvestBulkPostError = HarvestBulkPostErrors[keyof HarvestBulkPostErrors]; + +export type HarvestBulkPostResponses = { + /** + * Success - Returns bulk harvest response object: `{ BulkCreateOrUpdateHarvestResponse }` + */ + 200: BulkCreateOrUpdateHarvestResponse; +}; + +export type HarvestBulkPostResponse = HarvestBulkPostResponses[keyof HarvestBulkPostResponses]; + +export type OkcomputerGetData = { + body?: never; + path?: never; + query?: never; + url: '/okcomputer'; +}; + +export type OkcomputerGetErrors = { + /** + * Internal Server Error - Service is experiencing issues + */ + 500: unknown; +}; + +export type OkcomputerGetResponses = { + /** + * Success - Service is healthy and responsive + */ + 200: SuccessResult; +}; + +export type OkcomputerGetResponse = OkcomputerGetResponses[keyof OkcomputerGetResponses]; + +export type IntegrationIntegrationReconGetData = { + body?: never; + path?: never; + query?: never; + url: '/integration/integration-recon'; +}; + +export type IntegrationIntegrationReconGetErrors = { + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type IntegrationIntegrationReconGetResponses = { + /** + * Success + */ + 200: InventoryIntegrationReconResponse; +}; + +export type IntegrationIntegrationReconGetResponse = IntegrationIntegrationReconGetResponses[keyof IntegrationIntegrationReconGetResponses]; + +export type InventoryGetData = { + body?: never; + path?: never; + query?: { + /** + * Include detailed lab testing data and cannabinoid profiles - Default: false + */ + includeLabResults?: boolean; + /** + * Include quantity breakdown by storage room/location - Default: false + */ + includeRoomQuantities?: boolean; + }; + url: '/inventory'; +}; + +export type InventoryGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for inventory access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type InventoryGetResponses = { + /** + * Success - Returns array of inventory items with product and stock details + */ + 200: Array; +}; + +export type InventoryGetResponse = InventoryGetResponses[keyof InventoryGetResponses]; + +export type InventoryLabresultsGetData = { + body?: never; + path?: never; + query?: { + BatchName?: string; + }; + url: '/inventory/labresults'; +}; + +export type InventoryLabresultsGetErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Internal Server Error + */ + 500: unknown; +}; + +export type InventoryLabresultsGetResponses = { + /** + * OK + */ + 200: Array; +}; + +export type InventoryLabresultsGetResponse = InventoryLabresultsGetResponses[keyof InventoryLabresultsGetResponses]; + +export type InventorySnapshotGetData = { + body?: never; + path?: never; + query?: { + fromDate?: string; + }; + url: '/inventory/snapshot'; +}; + +export type InventorySnapshotGetErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Internal Server Error + */ + 500: unknown; +}; + +export type InventorySnapshotGetResponses = { + /** + * OK + */ + 200: Array; +}; + +export type InventorySnapshotGetResponse = InventorySnapshotGetResponses[keyof InventorySnapshotGetResponses]; + +export type InventoryReceivedinventoryGetData = { + body?: never; + path?: never; + query?: { + receiveInventoryHistoryId?: number; + startDate?: string; + endDate?: string; + }; + url: '/inventory/receivedinventory'; +}; + +export type InventoryReceivedinventoryGetErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Internal Server Error + */ + 500: unknown; +}; + +export type InventoryReceivedinventoryGetResponses = { + /** + * OK + */ + 200: Array; +}; + +export type InventoryReceivedinventoryGetResponse = InventoryReceivedinventoryGetResponses[keyof InventoryReceivedinventoryGetResponses]; + +export type InventoryInventorytransactionGetData = { + body?: never; + path?: never; + query?: { + startDate?: string; + endDate?: string; + transactionType?: string; + }; + url: '/inventory/inventorytransaction'; +}; + +export type InventoryInventorytransactionGetErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Internal Server Error + */ + 500: unknown; +}; + +export type InventoryInventorytransactionGetResponses = { + /** + * OK + */ + 200: Array; +}; + +export type InventoryInventorytransactionGetResponse = InventoryInventorytransactionGetResponses[keyof InventoryInventorytransactionGetResponses]; + +export type InventoryReceiveinventoryPostData = { + /** + * Receive inventory order details including vendor, delivery, and item information + */ + body?: ReceiveInventorySave; + path?: never; + query?: never; + url: '/inventory/receiveinventory'; +}; + +export type InventoryReceiveinventoryPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) OR String error message (parse response body as plain text) + */ + 400: string; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for inventory access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type InventoryReceiveinventoryPostError = InventoryReceiveinventoryPostErrors[keyof InventoryReceiveinventoryPostErrors]; + +export type InventoryReceiveinventoryPostResponses = { + /** + * Success - Returns SavedReceive object with transaction details + */ + 200: SavedReceive; +}; + +export type InventoryReceiveinventoryPostResponse = InventoryReceiveinventoryPostResponses[keyof InventoryReceiveinventoryPostResponses]; + +export type LineagesGetData = { + body?: never; + path?: never; + query?: never; + url: '/lineages'; +}; + +export type LineagesGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type LineagesGetResponses = { + /** + * Success - Returns array of lineage objects: `[{ Lineage }, ...]` + */ + 200: Array; +}; + +export type LineagesGetResponse = LineagesGetResponses[keyof LineagesGetResponses]; + +export type PackageSetTagsPostData = { + /** + * Package tag update request with package identifiers and replacement tags - UpdatePackageTagsRequest object + */ + body?: UpdatePackageTagsRequest; + path?: never; + query?: never; + url: '/package/set-tags'; +}; + +export type PackageSetTagsPostErrors = { + /** + * Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: ValidationResult; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PackageSetTagsPostError = PackageSetTagsPostErrors[keyof PackageSetTagsPostErrors]; + +export type PackageSetTagsPostResponses = { + /** + * Success - Tags successfully set on specified packages + */ + 200: unknown; +}; + +export type PackageAddTagsPostData = { + /** + * Package tag update request with package identifiers and additional tags - UpdatePackageTagsRequest object + */ + body?: UpdatePackageTagsRequest; + path?: never; + query?: never; + url: '/package/add-tags'; +}; + +export type PackageAddTagsPostErrors = { + /** + * Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: unknown; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PackageAddTagsPostResponses = { + /** + * Success - Tags successfully added to specified packages + */ + 200: unknown; +}; + +export type PackageRemoveTagsPostData = { + /** + * Package tag update request with package identifiers and tags to remove - UpdatePackageTagsRequest object + */ + body?: UpdatePackageTagsRequest; + path?: never; + query?: never; + url: '/package/remove-tags'; +}; + +export type PackageRemoveTagsPostErrors = { + /** + * Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: unknown; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PackageRemoveTagsPostResponses = { + /** + * Success - Tags successfully removed from specified packages + */ + 200: unknown; +}; + +export type PlantGetData = { + body?: never; + path?: never; + query?: { + /** + * Dutchie internal plant ID for specific plant lookup - Optional + */ + plantId?: number; + /** + * Plant serial number for tracking system integration - Optional + */ + serialNumber?: string; + /** + * Plant status filter: Active, Harvesting, Harvested, Retired - Optional + */ + status?: string; + /** + * Filter plants modified after this date for incremental sync - Optional + */ + lastModifiedDateStart?: string; + /** + * Filter plants modified before this date for date range filtering - Optional + */ + lastModifiedDateEnd?: string; + }; + url: '/plant'; +}; + +export type PlantGetErrors = { + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantGetResponses = { + /** + * Success + */ + 200: Array; +}; + +export type PlantGetResponse = PlantGetResponses[keyof PlantGetResponses]; + +export type PlantPostData = { + /** + * Plant creation request with identification and group details - see `CreatePlantRequest` model for complete field documentation + */ + body?: CreatePlantRequest; + path?: never; + query?: never; + url: '/plant'; +}; + +export type PlantPostErrors = { + /** + * Bad Request - Validation errors or duplicate serial number + */ + 400: { + [key: string]: unknown; + }; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantPostError = PlantPostErrors[keyof PlantPostErrors]; + +export type PlantPostResponses = { + /** + * Success - Returns newly created plant ID as integer + */ + 200: number; +}; + +export type PlantPostResponse = PlantPostResponses[keyof PlantPostResponses]; + +export type PlantHarvestPostData = { + /** + * Plant harvest request with plant identifiers and optional weight data - HarvestPlantRequest object + */ + body?: HarvestPlantRequest; + path?: never; + query?: never; + url: '/plant/harvest'; +}; + +export type PlantHarvestPostErrors = { + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantHarvestPostResponses = { + /** + * Success - Plants successfully moved to harvest status + */ + 200: unknown; +}; + +export type PlantMovePostData = { + /** + * Plant movement request with plant IDs and target room information - see `MovePlantRequest` model for complete field documentation + */ + body?: MovePlantRequest; + path?: never; + query?: never; + url: '/plant/move'; +}; + +export type PlantMovePostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: unknown; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantMovePostResponses = { + /** + * Success - Plants successfully moved to target room + */ + 200: unknown; +}; + +export type PlantChangePhasePostData = { + /** + * Growth phase change request with plant IDs and target phase information - see `ChangeGrowthPhaseRequest` model for complete field documentation + */ + body?: ChangeGrowthPhaseRequest; + path?: never; + query?: never; + url: '/plant/change-phase'; +}; + +export type PlantChangePhasePostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: unknown; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantChangePhasePostResponses = { + /** + * Success - Plants successfully updated to new growth phase + */ + 200: unknown; +}; + +export type PlantRetirePostData = { + /** + * Plant retirement request with plant IDs, reason codes, and waste tracking details - see `RetirePlantRequest` model for complete field documentation + */ + body?: RetirePlantRequest; + path?: never; + query?: never; + url: '/plant/retire'; +}; + +export type PlantRetirePostErrors = { + /** + * Bad Request - Invalid reason ID/code or validation errors + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantRetirePostError = PlantRetirePostErrors[keyof PlantRetirePostErrors]; + +export type PlantRetirePostResponses = { + /** + * Success - Plants successfully retired from cultivation + */ + 200: unknown; +}; + +export type PlantGetReasonCodesGetData = { + body?: never; + path?: never; + query?: never; + url: '/plant/get-reason-codes'; +}; + +export type PlantGetReasonCodesGetErrors = { + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantGetReasonCodesGetResponses = { + /** + * Success - Returns array of reason code strings: `[string, ...]` + */ + 200: Array; +}; + +export type PlantGetReasonCodesGetResponse = PlantGetReasonCodesGetResponses[keyof PlantGetReasonCodesGetResponses]; + +export type PlantAssignPlantsToGroupPostData = { + /** + * Plant group assignment request with group name and plant serial numbers - see `AssignPlantsToGroupRequest` model for complete field documentation + */ + body?: AssignPlantsToGroupRequest; + path?: never; + query?: never; + url: '/plant/assign-plants-to-group'; +}; + +export type PlantAssignPlantsToGroupPostErrors = { + /** + * Bad Request - Validation errors or invalid plant serial numbers + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantAssignPlantsToGroupPostError = PlantAssignPlantsToGroupPostErrors[keyof PlantAssignPlantsToGroupPostErrors]; + +export type PlantAssignPlantsToGroupPostResponses = { + /** + * Success - Plants successfully assigned to target group + */ + 200: unknown; +}; + +export type PlantNonstsUpdatePostData = { + /** + * Plant update request with PlantId and field updates - UpdatePlantsRequest object + */ + body?: UpdatePlantsRequest; + path?: never; + query?: never; + url: '/plant/nonsts/update'; +}; + +export type PlantNonstsUpdatePostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantNonstsUpdatePostError = PlantNonstsUpdatePostErrors[keyof PlantNonstsUpdatePostErrors]; + +export type PlantNonstsUpdatePostResponses = { + /** + * Success + */ + 200: SuccessResult; +}; + +export type PlantNonstsUpdatePostResponse = PlantNonstsUpdatePostResponses[keyof PlantNonstsUpdatePostResponses]; + +export type PlantNonstsBatchImmatureplantsPostData = { + /** + * Immature plant batch request with plant details - PostImmatureBatchRequest object + */ + body?: PostImmatureBatchRequest; + path?: never; + query?: never; + url: '/plant/nonsts/batch/immatureplants'; +}; + +export type PlantNonstsBatchImmatureplantsPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantNonstsBatchImmatureplantsPostError = PlantNonstsBatchImmatureplantsPostErrors[keyof PlantNonstsBatchImmatureplantsPostErrors]; + +export type PlantNonstsBatchImmatureplantsPostResponses = { + /** + * Success + */ + 200: CreateImmaturePlantBatchResponseApiResult; +}; + +export type PlantNonstsBatchImmatureplantsPostResponse = PlantNonstsBatchImmatureplantsPostResponses[keyof PlantNonstsBatchImmatureplantsPostResponses]; + +export type PlantNonstsBatchConvertImmatureplantsPostData = { + /** + * Immature batch conversion request with conversion details - ConvertImmatureBatchRequest object + */ + body?: ConvertImmatureBatchRequest; + path?: never; + query?: never; + url: '/plant/nonsts/batch/convert/immatureplants'; +}; + +export type PlantNonstsBatchConvertImmatureplantsPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantNonstsBatchConvertImmatureplantsPostError = PlantNonstsBatchConvertImmatureplantsPostErrors[keyof PlantNonstsBatchConvertImmatureplantsPostErrors]; + +export type PlantNonstsBatchConvertImmatureplantsPostResponses = { + /** + * Success + */ + 200: ConvertImmaturePlantResponseApiResult; +}; + +export type PlantNonstsBatchConvertImmatureplantsPostResponse = PlantNonstsBatchConvertImmatureplantsPostResponses[keyof PlantNonstsBatchConvertImmatureplantsPostResponses]; + +export type PlantNonstsBatchMatureplantsPostData = { + /** + * Mature plant batch request with plant details - CreateMatureBatchRequest object + */ + body?: CreateMatureBatchRequest; + path?: never; + query?: never; + url: '/plant/nonsts/batch/matureplants'; +}; + +export type PlantNonstsBatchMatureplantsPostErrors = { + /** + * Bad Request - Validation failed or invalid request data + */ + 400: BadRequestResponse; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for mature plant creation or feature flag disabled + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type PlantNonstsBatchMatureplantsPostError = PlantNonstsBatchMatureplantsPostErrors[keyof PlantNonstsBatchMatureplantsPostErrors]; + +export type PlantNonstsBatchMatureplantsPostResponses = { + /** + * Success - Returns ApiResult with created plant IDs: `{ "data": { "createdPlants": [plantId1, plantId2, ...] }, "message": "Successfully created mature plants from batches.", "success": true }` + */ + 200: CreateMaturePlantsResponseApiResult; +}; + +export type PlantNonstsBatchMatureplantsPostResponse = PlantNonstsBatchMatureplantsPostResponses[keyof PlantNonstsBatchMatureplantsPostResponses]; + +export type PlantNonstsRetagPostData = { + /** + * Plant retagging request with plant and new tag details - RetagPlantRequest object + */ + body?: RetagPlantRequest; + path?: never; + query?: never; + url: '/plant/nonsts/retag'; +}; + +export type PlantNonstsRetagPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantNonstsRetagPostError = PlantNonstsRetagPostErrors[keyof PlantNonstsRetagPostErrors]; + +export type PlantNonstsRetagPostResponses = { + /** + * Success + */ + 200: unknown; +}; + +export type PlantNonstsBatchRetirePostData = { + /** + * Immature plant retirement request with plant details - RetireImmaturePlantsRequest object + */ + body?: RetireImmaturePlantsRequest; + path?: never; + query?: never; + url: '/plant/nonsts/batch/retire'; +}; + +export type PlantNonstsBatchRetirePostErrors = { + /** + * Bad Request - Validation failed or invalid plant data + */ + 400: BadRequestResponse; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for plant retirement + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type PlantNonstsBatchRetirePostError = PlantNonstsBatchRetirePostErrors[keyof PlantNonstsBatchRetirePostErrors]; + +export type PlantNonstsBatchRetirePostResponses = { + /** + * Success - No response body, operation completed successfully + */ + 200: unknown; +}; + +export type PlantNonstsBatchFinishHarvestPostData = { + /** + * Harvest batch finish/unfinish request with batch details - FinishHarvestBatchRequest object + */ + body?: Array; + path?: never; + query?: never; + url: '/plant/nonsts/batch/finish-harvest'; +}; + +export type PlantNonstsBatchFinishHarvestPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantNonstsBatchFinishHarvestPostError = PlantNonstsBatchFinishHarvestPostErrors[keyof PlantNonstsBatchFinishHarvestPostErrors]; + +export type PlantNonstsBatchFinishHarvestPostResponses = { + /** + * Success + */ + 200: unknown; +}; + +export type PlantNonstsSplitPostData = { + /** + * Immature plant batch split request with batch and split details - SplitImmaturePlantsRequest object + */ + body?: SplitImmaturePlantsRequest; + path?: never; + query?: never; + url: '/plant/nonsts/split'; +}; + +export type PlantNonstsSplitPostErrors = { + /** + * Bad Request - Validation failed or invalid batch data + */ + 400: BadRequestResponse; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for batch splitting + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type PlantNonstsSplitPostError = PlantNonstsSplitPostErrors[keyof PlantNonstsSplitPostErrors]; + +export type PlantNonstsSplitPostResponses = { + /** + * Success - Returns ApiResult with split batch details: `{ "data": { "originalBatch": {...}, "newBatch": {...} }, "message": "Successfully split immature batches of plants.", "success": true }` + */ + 200: SplitImmaturePlantResultApiResult; +}; + +export type PlantNonstsSplitPostResponse = PlantNonstsSplitPostResponses[keyof PlantNonstsSplitPostResponses]; + +export type PlantNonstsBatchPostData = { + /** + * Batch update request with batch identification and field updates - UpdateBatchRequest object + */ + body?: UpdateBatchRequest; + path?: never; + query?: never; + url: '/plant/nonsts/batch'; +}; + +export type PlantNonstsBatchPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PlantNonstsBatchPostError = PlantNonstsBatchPostErrors[keyof PlantNonstsBatchPostErrors]; + +export type PlantNonstsBatchPostResponses = { + /** + * Success + */ + 200: unknown; +}; + +export type PreorderSubmitPostData = { + /** + * Pre-order details including customer, cart items, and fulfillment information - CreatePreOrderRequest object + */ + body?: CreatePreOrderRequest; + path?: never; + query?: never; + url: '/preorder/submit'; +}; + +export type PreorderSubmitPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type PreorderSubmitPostError = PreorderSubmitPostErrors[keyof PreorderSubmitPostErrors]; + +export type PreorderSubmitPostResponses = { + /** + * Success - Returns orderId and transactionId for the created pre-order + */ + 200: number; +}; + +export type PreorderSubmitPostResponse = PreorderSubmitPostResponses[keyof PreorderSubmitPostResponses]; + +export type PreorderUpdatePostData = { + /** + * Update details including OrderId and fields to be modified + */ + body?: UpdatePreOrderRequest; + path?: never; + query?: never; + url: '/preorder/update'; +}; + +export type PreorderUpdatePostErrors = { + /** + * Bad Request - Empty response body (handle via HTTP status code only) + */ + 400: unknown; + /** + * Not Found - Order ID does not exist + */ + 404: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type PreorderUpdatePostResponses = { + /** + * Success - Order updated successfully + */ + 200: unknown; +}; + +export type PreorderCancelPostData = { + /** + * Cancellation request containing the OrderId to cancel + */ + body?: CancelPreorderRequest; + path?: never; + query?: never; + url: '/preorder/cancel'; +}; + +export type PreorderCancelPostErrors = { + /** + * Bad Request - Empty response body (handle via HTTP status code only) + */ + 400: unknown; + /** + * Not Found - Order ID does not exist + */ + 404: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: string; +}; + +export type PreorderCancelPostError = PreorderCancelPostErrors[keyof PreorderCancelPostErrors]; + +export type PreorderCancelPostResponses = { + /** + * Success - Order cancelled successfully + */ + 200: number; +}; + +export type PreorderCancelPostResponse = PreorderCancelPostResponses[keyof PreorderCancelPostResponses]; + +export type PreorderStatusGetData = { + body?: never; + path?: never; + query?: { + /** + * Specific order ID to retrieve status for (optional - omit for all open orders) + */ + PreOrderId?: number; + /** + * Include detailed product line item information (requires PreOrderId) + */ + includeLineItems?: boolean; + }; + url: '/preorder/Status'; +}; + +export type PreorderStatusGetErrors = { + /** + * Bad Request - Empty response body (handle via HTTP status code only) + */ + 400: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type PreorderStatusGetResponses = { + /** + * Success - Returns PreOrderStatus object(s) with current order information + */ + 200: PreOrderStatus; +}; + +export type PreorderStatusGetResponse = PreorderStatusGetResponses[keyof PreorderStatusGetResponses]; + +export type PreorderPriceCartPostData = { + /** + * Pricing request containing customer information, cart items, and delivery preferences + */ + body?: PriceCartRequest; + path?: never; + query?: never; + url: '/preorder/price-cart'; +}; + +export type PreorderPriceCartPostErrors = { + /** + * Bad Request - String error message (parse response body as plain text) + */ + 400: string; + /** + * Internal Server Error - Server error occurred during pricing calculation + */ + 500: unknown; +}; + +export type PreorderPriceCartPostError = PreorderPriceCartPostErrors[keyof PreorderPriceCartPostErrors]; + +export type PreorderPriceCartPostResponses = { + /** + * Success - Returns detailed pricing breakdown for the cart + */ + 200: CartPrice; +}; + +export type PreorderPriceCartPostResponse = PreorderPriceCartPostResponses[keyof PreorderPriceCartPostResponses]; + +export type PricingTiersGetData = { + body?: never; + path?: never; + query?: never; + url: '/pricing-tiers'; +}; + +export type PricingTiersGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type PricingTiersGetResponses = { + /** + * Success - Returns array of pricing tier objects: `[{ PricingTier }, ...]` + */ + 200: Array; +}; + +export type PricingTiersGetResponse = PricingTiersGetResponses[keyof PricingTiersGetResponses]; + +export type ProducersGetData = { + body?: never; + path?: never; + query?: never; + url: '/producers'; +}; + +export type ProducersGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ProducersGetResponses = { + /** + * Success - Returns array of producer objects: `[{ Producer }, ...]` + */ + 200: Array; +}; + +export type ProducersGetResponse = ProducersGetResponses[keyof ProducersGetResponses]; + +export type ProductsLocationOverridesGetData = { + body?: never; + path?: never; + query?: never; + url: '/products/location-overrides'; +}; + +export type ProductsLocationOverridesGetErrors = { + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type ProductsLocationOverridesGetResponses = { + /** + * Success + */ + 200: Array; +}; + +export type ProductsLocationOverridesGetResponse = ProductsLocationOverridesGetResponses[keyof ProductsLocationOverridesGetResponses]; + +export type ProductsLocationOverridesPostData = { + /** + * Array of location product override requests with ProductId and override values - LocationProductOverrideRequest objects + */ + body?: Array; + path?: never; + query?: never; + url: '/products/location-overrides'; +}; + +export type ProductsLocationOverridesPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: unknown; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. One or more overrides may have been saved + */ + 500: unknown; +}; + +export type ProductsLocationOverridesPostResponses = { + /** + * Success + */ + 200: unknown; +}; + +export type ProductsGetData = { + body?: never; + path?: never; + query?: { + /** + * Optional date filter to return only products modified after this timestamp - Used for incremental sync + */ + fromLastModifiedDateUTC?: string; + /** + * Optional status filter - true for active products only, false for inactive only, null for all products + */ + isActive?: boolean; + }; + url: '/products'; +}; + +export type ProductsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for inventory access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ProductsGetResponses = { + /** + * Success - Returns array of product objects: `[{ ProductDetail }, ...]` + */ + 200: Array; +}; + +export type ProductsGetResponse = ProductsGetResponses[keyof ProductsGetResponses]; + +export type ProductsProductPostData = { + /** + * Product information to create or update - ProductDetailUpload object with product details + */ + body?: ProductDetailUpload; + path?: never; + query?: never; + url: '/products/product'; +}; + +export type ProductsProductPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type ProductsProductPostError = ProductsProductPostErrors[keyof ProductsProductPostErrors]; + +export type ProductsProductPostResponses = { + /** + * Success + */ + 200: ProductDetail; +}; + +export type ProductsProductPostResponse = ProductsProductPostResponses[keyof ProductsProductPostResponses]; + +export type ProductsProductsPostData = { + /** + * Array of product information to create or update - IEnumerable objects + */ + body?: Array; + path?: never; + query?: never; + url: '/products/products'; +}; + +export type ProductsProductsPostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) OR `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: ValidationResult; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type ProductsProductsPostError = ProductsProductsPostErrors[keyof ProductsProductsPostErrors]; + +export type ProductsProductsPostResponses = { + /** + * Success - Products processed with individual success/error results + */ + 200: Array<{ + [key: string]: unknown; + }>; +}; + +export type ProductsProductsPostResponse = ProductsProductsPostResponses[keyof ProductsProductsPostResponses]; + +export type ProductsSetImagePostData = { + /** + * Image upload request with ProductId and base64 image data - SetImageRequest object + */ + body?: SetImageRequestWritable; + path?: never; + query?: never; + url: '/products/set-image'; +}; + +export type ProductsSetImagePostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type ProductsSetImagePostError = ProductsSetImagePostErrors[keyof ProductsSetImagePostErrors]; + +export type ProductsSetImagePostResponses = { + /** + * Success + */ + 200: SetImageResponse; +}; + +export type ProductsSetImagePostResponse = ProductsSetImagePostResponses[keyof ProductsSetImagePostResponses]; + +export type ProductsRemoveImagePostData = { + /** + * Image deletion request with ProductId and ImageId - DeleteImageRequest object + */ + body?: DeleteImageRequest; + path?: never; + query?: never; + url: '/products/remove-image'; +}; + +export type ProductsRemoveImagePostErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type ProductsRemoveImagePostError = ProductsRemoveImagePostErrors[keyof ProductsRemoveImagePostErrors]; + +export type ProductsRemoveImagePostResponses = { + /** + * Success + */ + 200: SuccessResult; +}; + +export type ProductsRemoveImagePostResponse = ProductsRemoveImagePostResponses[keyof ProductsRemoveImagePostResponses]; + +export type ProductsStrainsGetData = { + body?: never; + path?: never; + query?: never; + url: '/products/strains'; +}; + +export type ProductsStrainsGetErrors = { + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type ProductsStrainsGetResponses = { + /** + * Success + */ + 200: Array; +}; + +export type ProductsStrainsGetResponse = ProductsStrainsGetResponses[keyof ProductsStrainsGetResponses]; + +export type ProductsExternalCategoriesGetData = { + body?: never; + path?: never; + query?: { + /** + * User ID for traceability system access context (highly recommended) - Optional but prevents system failures + */ + userId?: number; + }; + url: '/products/external-categories'; +}; + +export type ProductsExternalCategoriesGetErrors = { + /** + * Bad Request - String error message (parse response body as plain text) + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type ProductsExternalCategoriesGetError = ProductsExternalCategoriesGetErrors[keyof ProductsExternalCategoriesGetErrors]; + +export type ProductsExternalCategoriesGetResponses = { + /** + * Success + */ + 200: Array; +}; + +export type ProductsExternalCategoriesGetResponse = ProductsExternalCategoriesGetResponses[keyof ProductsExternalCategoriesGetResponses]; + +export type ProductCategoryGetData = { + body?: never; + path?: never; + query?: never; + url: '/product-category'; +}; + +export type ProductCategoryGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ProductCategoryGetResponses = { + /** + * Success - Returns array of product category objects: `[{ ProductCategory }, ...]` + */ + 200: Array; +}; + +export type ProductCategoryGetResponse = ProductCategoryGetResponses[keyof ProductCategoryGetResponses]; + +export type PurchaseOrderGetData = { + body?: never; + path?: never; + query?: { + /** + * Start date filter for purchase orders created after this date (optional). + */ + FromDateCreated?: string; + /** + * End date filter for purchase orders created before this date (optional). + */ + ToDateCreated?: string; + /** + * Specific purchase order identifier for single order retrieval (optional). + */ + PurchaseOrderId?: number; + /** + * Whether to include detailed line item information in the response (default: false). + */ + IncludeItemDetails?: boolean; + /** + * Page number for pagination control (default: 0). + */ + PageNumber?: number; + /** + * Number of results per page for pagination (default: 1000). + */ + PageSize?: number; + }; + url: '/purchase-order'; +}; + +export type PurchaseOrderGetErrors = { + /** + * Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PurchaseOrderGetError = PurchaseOrderGetErrors[keyof PurchaseOrderGetErrors]; + +export type PurchaseOrderGetResponses = { + /** + * Success + */ + 200: Array; +}; + +export type PurchaseOrderGetResponse = PurchaseOrderGetResponses[keyof PurchaseOrderGetResponses]; + +export type PurchaseOrderPostData = { + /** + * Purchase order creation/update request with order details - CreateUpdatePurchaseOrdersRequest object + */ + body?: CreateUpdatePurchaseOrdersRequest; + path?: never; + query?: never; + url: '/purchase-order'; +}; + +export type PurchaseOrderPostErrors = { + /** + * Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: BadRequestResponse; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type PurchaseOrderPostError = PurchaseOrderPostErrors[keyof PurchaseOrderPostErrors]; + +export type PurchaseOrderPostResponses = { + /** + * Success + */ + 200: CreateUpdatePurchaseOrderResponse; +}; + +export type PurchaseOrderPostResponse = PurchaseOrderPostResponses[keyof PurchaseOrderPostResponses]; + +export type ReferenceUnitsGetData = { + body?: never; + path?: never; + query?: never; + url: '/reference/units'; +}; + +export type ReferenceUnitsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReferenceUnitsGetResponses = { + /** + * Success - Returns array of unit objects: `[{ Unit }, ...]` + */ + 200: Array; +}; + +export type ReferenceUnitsGetResponse = ReferenceUnitsGetResponses[keyof ReferenceUnitsGetResponses]; + +export type ReferenceUnitTypesGetData = { + body?: never; + path?: never; + query?: never; + url: '/reference/unit-types'; +}; + +export type ReferenceUnitTypesGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReferenceUnitTypesGetResponses = { + /** + * Success - Returns array of unit type objects: `[{ UnitType }, ...]` + */ + 200: Array; +}; + +export type ReferenceUnitTypesGetResponse = ReferenceUnitTypesGetResponses[keyof ReferenceUnitTypesGetResponses]; + +export type ReferenceLabResultUnitsGetData = { + body?: never; + path?: never; + query?: never; + url: '/reference/lab-result-units'; +}; + +export type ReferenceLabResultUnitsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReferenceLabResultUnitsGetResponses = { + /** + * Success - Returns array of lab result unit objects: `[{ LabResultUnitData }, ...]` + */ + 200: Array; +}; + +export type ReferenceLabResultUnitsGetResponse = ReferenceLabResultUnitsGetResponses[keyof ReferenceLabResultUnitsGetResponses]; + +export type ReferenceLabResultsNamesGetData = { + body?: never; + path?: never; + query?: never; + url: '/reference/lab-results-names'; +}; + +export type ReferenceLabResultsNamesGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReferenceLabResultsNamesGetResponses = { + /** + * Success - Returns array of strings with lab result names: `["string", ...]` + */ + 200: Array; +}; + +export type ReferenceLabResultsNamesGetResponse = ReferenceLabResultsNamesGetResponses[keyof ReferenceLabResultsNamesGetResponses]; + +export type RegulatoryCategoryGetData = { + body?: never; + path?: never; + query?: never; + url: '/regulatory-category'; +}; + +export type RegulatoryCategoryGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type RegulatoryCategoryGetResponses = { + /** + * Success - Returns array of regulatory category objects: `[{ RegulatoryCategory }, ...]` + */ + 200: Array; +}; + +export type RegulatoryCategoryGetResponse = RegulatoryCategoryGetResponses[keyof RegulatoryCategoryGetResponses]; + +export type ReportingInventoryGetData = { + body?: never; + path?: never; + query?: { + includeLabResults?: boolean; + includeRoomQuantities?: boolean; + includeAllocated?: boolean; + includeLineage?: boolean; + }; + url: '/reporting/inventory'; +}; + +export type ReportingInventoryGetErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Internal Server Error + */ + 500: unknown; +}; + +export type ReportingInventoryGetResponses = { + /** + * OK + */ + 200: Array; +}; + +export type ReportingInventoryGetResponse = ReportingInventoryGetResponses[keyof ReportingInventoryGetResponses]; + +export type ReportingTransactionsGetData = { + body?: never; + path?: never; + query?: { + /** + * Specific transaction identifier for single transaction lookup. + */ + TransactionId?: number; + /** + * Start date for filtering transactions by last modified date (UTC) for incremental sync. + */ + FromLastModifiedDateUTC?: string; + /** + * End date for filtering transactions by last modified date (UTC) for incremental sync. + */ + ToLastModifiedDateUTC?: string; + /** + * Start date for filtering transactions by transaction date (UTC) for periodic reports. + */ + FromDateUTC?: string; + /** + * End date for filtering transactions by transaction date (UTC) for periodic reports. + */ + ToDateUTC?: string; + /** + * Flag to include detailed transaction item information for comprehensive reporting. + */ + IncludeDetail?: boolean; + /** + * Flag to include tax information for financial compliance reporting. + */ + IncludeTaxes?: boolean; + /** + * Flag to include order identifiers for order fulfillment tracking. + */ + IncludeOrderIds?: boolean; + /** + * Flag to include fees and donations for complete financial analysis. + */ + IncludeFeesAndDonations?: boolean; + }; + url: '/reporting/transactions'; +}; + +export type ReportingTransactionsGetErrors = { + /** + * Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: ValidationResult; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; + /** + * Temporarily disabled (kill switch). + */ + 503: unknown; +}; + +export type ReportingTransactionsGetError = ReportingTransactionsGetErrors[keyof ReportingTransactionsGetErrors]; + +export type ReportingTransactionsGetResponses = { + /** + * Success + */ + 200: Array; +}; + +export type ReportingTransactionsGetResponse = ReportingTransactionsGetResponses[keyof ReportingTransactionsGetResponses]; + +export type ReportingCustomersGetData = { + body?: never; + path?: never; + query?: { + /** + * Filter customers modified after this UTC date - Used for incremental sync + */ + fromLastModifiedDateUTC?: string; + /** + * Filter customers modified before this UTC date - Used for date range filtering + */ + toLastModifiedDateUTC?: string; + /** + * Include anonymous customers in results - Default: true + */ + includeAnonymous?: boolean; + }; + url: '/reporting/customers'; +}; + +export type ReportingCustomersGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for reporting access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReportingCustomersGetResponses = { + /** + * Success - Returns array of customer objects + */ + 200: Array; +}; + +export type ReportingCustomersGetResponse = ReportingCustomersGetResponses[keyof ReportingCustomersGetResponses]; + +export type ReportingCustomersPaginatedGetData = { + body?: never; + path?: never; + query?: { + /** + * Filter customers modified after this UTC date for incremental sync - Optional + */ + fromLastModifiedDateUTC?: string; + /** + * Filter customers modified before this UTC date for date range filtering - Optional + */ + toLastModifiedDateUTC?: string; + /** + * Page number for sequential pagination (integer, starts at 0) - Default: 0 + */ + PageNumber?: number; + /** + * Number of items per page (integer) - Default: 1000, Maximum: 10000 + */ + PageSize?: number; + /** + * Include anonymous customers in results - Default: true + */ + includeAnonymous?: boolean; + }; + url: '/reporting/customers-paginated'; +}; + +export type ReportingCustomersPaginatedGetErrors = { + /** + * Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) + */ + 400: BadRequestResponse; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for reporting access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReportingCustomersPaginatedGetError = ReportingCustomersPaginatedGetErrors[keyof ReportingCustomersPaginatedGetErrors]; + +export type ReportingCustomersPaginatedGetResponses = { + /** + * Success - Returns array of customer objects for the requested page + */ + 200: Array; +}; + +export type ReportingCustomersPaginatedGetResponse = ReportingCustomersPaginatedGetResponses[keyof ReportingCustomersPaginatedGetResponses]; + +export type ReportingRegisterAdjustmentsGetData = { + body?: never; + path?: never; + query?: { + /** + * Filter adjustments modified after this date for incremental sync - Optional + */ + fromLastModifiedDateUTC?: string; + /** + * Filter adjustments modified before this date for date range filtering - Optional + */ + toLastModifiedDateUTC?: string; + }; + url: '/reporting/register-adjustments'; +}; + +export type ReportingRegisterAdjustmentsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for reporting access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReportingRegisterAdjustmentsGetResponses = { + /** + * Success - Returns array of register adjustment objects + */ + 200: Array; +}; + +export type ReportingRegisterAdjustmentsGetResponse = ReportingRegisterAdjustmentsGetResponses[keyof ReportingRegisterAdjustmentsGetResponses]; + +export type ReportingRegisterTransactionsGetData = { + body?: never; + path?: never; + query?: { + /** + * Filter transactions modified after this date for incremental sync - Optional + */ + fromLastModifiedDateUTC?: string; + /** + * Filter transactions modified before this date for date range filtering - Optional + */ + toLastModifiedDateUTC?: string; + }; + url: '/reporting/register-transactions'; +}; + +export type ReportingRegisterTransactionsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for reporting access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReportingRegisterTransactionsGetResponses = { + /** + * Success - Returns array of RegisterTransaction objects with comprehensive transaction data + */ + 200: Array; +}; + +export type ReportingRegisterTransactionsGetResponse = ReportingRegisterTransactionsGetResponses[keyof ReportingRegisterTransactionsGetResponses]; + +export type ReportingCashSummaryGetData = { + body?: never; + path?: never; + query?: { + /** + * Filter activity after this date (must be within last 7 days) - Optional + */ + fromLastModifiedDateUTC?: string; + /** + * Filter activity before this date for date range filtering - Optional + */ + toLastModifiedDateUTC?: string; + }; + url: '/reporting/cash-summary'; +}; + +export type ReportingCashSummaryGetErrors = { + /** + * Bad Request - String error message (parse response body as plain text) + */ + 400: string; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for reporting access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReportingCashSummaryGetError = ReportingCashSummaryGetErrors[keyof ReportingCashSummaryGetErrors]; + +export type ReportingCashSummaryGetResponses = { + /** + * Success - Returns array of register cash summary objects + */ + 200: Array; +}; + +export type ReportingCashSummaryGetResponse = ReportingCashSummaryGetResponses[keyof ReportingCashSummaryGetResponses]; + +export type ReportingLoyaltySnapshotGetData = { + body?: never; + path?: never; + query?: never; + url: '/reporting/loyalty-snapshot'; +}; + +export type ReportingLoyaltySnapshotGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for reporting access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReportingLoyaltySnapshotGetResponses = { + /** + * Success - Returns array of loyalty balance snapshot objects + */ + 200: Array; +}; + +export type ReportingLoyaltySnapshotGetResponse = ReportingLoyaltySnapshotGetResponses[keyof ReportingLoyaltySnapshotGetResponses]; + +export type ReportingProductsGetData = { + body?: never; + path?: never; + query?: { + /** + * Filter products modified after this date for incremental sync - Optional + */ + fromLastModifiedDateUTC?: string; + }; + url: '/reporting/products'; +}; + +export type ReportingProductsGetErrors = { + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type ReportingProductsGetResponses = { + /** + * Success + */ + 200: Array; +}; + +export type ReportingProductsGetResponse = ReportingProductsGetResponses[keyof ReportingProductsGetResponses]; + +export type ReportingClosingReportGetData = { + body?: never; + path?: never; + query?: { + /** + * Start date for the report period (required) - Must be UTC datetime + */ + fromDateUTC?: string; + /** + * End date for the report period (required) - Must be UTC datetime + */ + toDateUTC?: string; + }; + url: '/reporting/closing-report'; +}; + +export type ReportingClosingReportGetErrors = { + /** + * Bad Request - String error message (parse response body as plain text) + */ + 400: string; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for reporting access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReportingClosingReportGetError = ReportingClosingReportGetErrors[keyof ReportingClosingReportGetErrors]; + +export type ReportingClosingReportGetResponses = { + /** + * Success - Returns comprehensive closing report object + */ + 200: ClosingReportV2; +}; + +export type ReportingClosingReportGetResponse = ReportingClosingReportGetResponses[keyof ReportingClosingReportGetResponses]; + +export type ReportingDiscountsGetData = { + body?: never; + path?: never; + query?: { + /** + * Include deleted/archived discounts in results - Default: false + */ + includeDeleted?: boolean; + }; + url: '/reporting/discounts'; +}; + +export type ReportingDiscountsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for reporting access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type ReportingDiscountsGetResponses = { + /** + * Success - Returns array of comprehensive discount configuration objects + */ + 200: Array; +}; + +export type ReportingDiscountsGetResponse = ReportingDiscountsGetResponses[keyof ReportingDiscountsGetResponses]; + +export type RoomRoomsGetData = { + body?: never; + path?: never; + query?: { + /** + * Optional room ID for specific room lookup - integer + */ + roomId?: number; + /** + * Optional room name for searching rooms by name - string + */ + roomName?: string; + }; + url: '/room/rooms'; +}; + +export type RoomRoomsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for room access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type RoomRoomsGetResponses = { + /** + * Success - Returns array of room objects: `[{ Room }, ...]` + */ + 200: Array; +}; + +export type RoomRoomsGetResponse = RoomRoomsGetResponses[keyof RoomRoomsGetResponses]; + +export type RoomPostData = { + /** + * Room information to create or update - Room object with RoomId, RoomName, and room type flags + */ + body?: Room; + path?: never; + query?: never; + url: '/room'; +}; + +export type RoomPostErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for room modification + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type RoomPostResponses = { + /** + * Success - Returns single room object: `{ Room }` + */ + 200: Room; +}; + +export type RoomPostResponse = RoomPostResponses[keyof RoomPostResponses]; + +export type SizesGetData = { + body?: never; + path?: never; + query?: never; + url: '/sizes'; +}; + +export type SizesGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type SizesGetResponses = { + /** + * Success - Returns array of size objects: `[{ Size }, ...]` + */ + 200: Array; +}; + +export type SizesGetResponse = SizesGetResponses[keyof SizesGetResponses]; + +export type StrainsGetData = { + body?: never; + path?: never; + query?: never; + url: '/strains'; +}; + +export type StrainsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for inventory access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type StrainsGetResponses = { + /** + * Success - Returns array of strain objects: `[{ StrainDetail }, ...]` + */ + 200: Array; +}; + +export type StrainsGetResponse = StrainsGetResponses[keyof StrainsGetResponses]; + +export type StrainsPostData = { + body?: UpdateStrain; + path?: never; + query?: never; + url: '/strains'; +}; + +export type StrainsPostErrors = { + /** + * Bad Request + */ + 400: string; + /** + * Unauthorized + */ + 401: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Internal Server Error + */ + 500: unknown; +}; + +export type StrainsPostError = StrainsPostErrors[keyof StrainsPostErrors]; + +export type StrainsPostResponses = { + /** + * OK + */ + 200: StrainDetail; +}; + +export type StrainsPostResponse = StrainsPostResponses[keyof StrainsPostResponses]; + +export type StrainsTypesGetData = { + body?: never; + path?: never; + query?: never; + url: '/strains/types'; +}; + +export type StrainsTypesGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for inventory access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type StrainsTypesGetResponses = { + /** + * Success - Returns array of strings with strain type names: `["Indica", "Sativa", "Hybrid", "CBD"]` + */ + 200: Array; +}; + +export type StrainsTypesGetResponse = StrainsTypesGetResponses[keyof StrainsTypesGetResponses]; + +export type TableTablesGetData = { + body?: never; + path?: never; + query?: { + /** + * Optional table ID for specific table lookup - integer + */ + tableId?: number; + /** + * Optional table name for searching tables by name - string + */ + tableName?: string; + }; + url: '/table/tables'; +}; + +export type TableTablesGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for table access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type TableTablesGetResponses = { + /** + * Success - Returns array of table objects: `[{ Table }, ...]` + */ + 200: Array; +}; + +export type TableTablesGetResponse = TableTablesGetResponses[keyof TableTablesGetResponses]; + +export type TablePostData = { + /** + * Table information to create or update - Table object with TableId and TableName fields + */ + body?: Table; + path?: never; + query?: never; + url: '/table'; +}; + +export type TablePostErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for table modification + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type TablePostResponses = { + /** + * Success - Returns single table object: `{ Table }` + */ + 200: Table; +}; + +export type TablePostResponse = TablePostResponses[keyof TablePostResponses]; + +export type TagGetData = { + body?: never; + path?: never; + query?: never; + url: '/tag'; +}; + +export type TagGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for inventory access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type TagGetResponses = { + /** + * Success - Returns array of tag objects: `[{ Tag }, ...]` + */ + 200: Array; +}; + +export type TagGetResponse = TagGetResponses[keyof TagGetResponses]; + +export type TerminalsGetData = { + body?: never; + path?: never; + query?: never; + url: '/terminals'; +}; + +export type TerminalsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type TerminalsGetResponses = { + /** + * Success - Returns array of terminal objects: `[{ Terminal }, ...]` + */ + 200: Array; +}; + +export type TerminalsGetResponse = TerminalsGetResponses[keyof TerminalsGetResponses]; + +export type TransactionCreateAnonymousPostData = { + /** + * Anonymous transaction request with optional transaction reference - CreateAnonymousTransactionRequest object + */ + body?: CreateAnonymousTransactionRequest; + path?: never; + query?: never; + url: '/transaction/create-anonymous'; +}; + +export type TransactionCreateAnonymousPostErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for transaction creation + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred during transaction creation + */ + 500: unknown; +}; + +export type TransactionCreateAnonymousPostResponses = { + /** + * Success - Returns anonymous transaction object: `{ AnonymousTransaction }` + */ + 200: AnonymousTransaction; +}; + +export type TransactionCreateAnonymousPostResponse = TransactionCreateAnonymousPostResponses[keyof TransactionCreateAnonymousPostResponses]; + +export type UtilAuthorizationHeaderByApiKeyGetData = { + body?: never; + path: { + /** + * API key to convert into authorization header format - string + */ + apiKey: string; + }; + query?: never; + url: '/util/AuthorizationHeader/{apiKey}'; +}; + +export type UtilAuthorizationHeaderByApiKeyGetResponses = { + /** + * Success - Returns formatted authorization header string: "Basic {base64-encoded-key}" + */ + 200: string; +}; + +export type UtilAuthorizationHeaderByApiKeyGetResponse = UtilAuthorizationHeaderByApiKeyGetResponses[keyof UtilAuthorizationHeaderByApiKeyGetResponses]; + +export type VehiclesGetData = { + body?: never; + path?: never; + query?: never; + url: '/vehicles'; +}; + +export type VehiclesGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for vehicle access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type VehiclesGetResponses = { + /** + * Success - Returns array of vehicle objects: `[{ VehicleDetail }, ...]` + */ + 200: Array; +}; + +export type VehiclesGetResponse = VehiclesGetResponses[keyof VehiclesGetResponses]; + +export type VehiclesPostData = { + /** + * Vehicle information to create or update - VehicleDetail object with fleet details + */ + body?: VehicleDetail; + path?: never; + query?: never; + url: '/vehicles'; +}; + +export type VehiclesPostErrors = { + /** + * Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array + */ + 400: ValidationResult; + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type VehiclesPostError = VehiclesPostErrors[keyof VehiclesPostErrors]; + +export type VehiclesPostResponses = { + /** + * Success + */ + 200: unknown; +}; + +export type VendorVendorsGetData = { + body?: never; + path?: never; + query?: { + /** + * Optional vendor ID to filter by specific vendor - Returns exact match + */ + vendorId?: number; + /** + * Optional vendor name to filter by - Supports partial matching for flexible search + */ + vendorName?: string; + }; + url: '/vendor/vendors'; +}; + +export type VendorVendorsGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for vendor access + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type VendorVendorsGetResponses = { + /** + * Success - Returns array of vendor objects: `[{ Vendor }, ...]` + */ + 200: Array; +}; + +export type VendorVendorsGetResponse = VendorVendorsGetResponses[keyof VendorVendorsGetResponses]; + +export type VendorPostData = { + /** + * Vendor information to create or update - Vendor object with supplier details + */ + body?: Vendor; + path?: never; + query?: never; + url: '/vendor'; +}; + +export type VendorPostErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - Account not authorized for vendor management + */ + 403: unknown; + /** + * Internal Server Error - Server error occurred during vendor operation + */ + 500: unknown; +}; + +export type VendorPostResponses = { + /** + * Success - Returns vendor object: `{ Vendor }` + */ + 200: Vendor; +}; + +export type VendorPostResponse = VendorPostResponses[keyof VendorPostResponses]; + +export type WasteGetData = { + body?: never; + path?: never; + query?: never; + url: '/waste'; +}; + +export type WasteGetErrors = { + /** + * Invalid API Key + */ + 401: unknown; + /** + * Account not authorized + */ + 403: unknown; + /** + * Something went wrong. + */ + 500: unknown; +}; + +export type WasteGetResponses = { + /** + * Success + */ + 200: WasteSummary; +}; + +export type WasteGetResponse = WasteGetResponses[keyof WasteGetResponses]; + +export type WasteHarvestWastePostData = { + body?: HarvestWasteDetailWaste; + path?: never; + query?: never; + url: '/waste/HarvestWaste'; +}; + +export type WasteHarvestWastePostErrors = { + /** + * Bad Request + */ + 400: string; + /** + * Unauthorized + */ + 401: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Internal Server Error + */ + 500: unknown; +}; + +export type WasteHarvestWastePostError = WasteHarvestWastePostErrors[keyof WasteHarvestWastePostErrors]; + +export type WasteHarvestWastePostResponses = { + /** + * OK + */ + 200: { + [key: string]: unknown; + }; +}; + +export type WasteHarvestWastePostResponse = WasteHarvestWastePostResponses[keyof WasteHarvestWastePostResponses]; + +export type WastePlantWastePostData = { + body?: PlantWasteDetailWaste; + path?: never; + query?: never; + url: '/waste/PlantWaste'; +}; + +export type WastePlantWastePostErrors = { + /** + * Bad Request + */ + 400: string; + /** + * Unauthorized + */ + 401: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Internal Server Error + */ + 500: unknown; +}; + +export type WastePlantWastePostError = WastePlantWastePostErrors[keyof WastePlantWastePostErrors]; + +export type WastePlantWastePostResponses = { + /** + * OK + */ + 200: { + [key: string]: unknown; + }; +}; + +export type WastePlantWastePostResponse = WastePlantWastePostResponses[keyof WastePlantWastePostResponses]; + +export type WhoamiGetData = { + body?: never; + path?: never; + query?: never; + url: '/whoami'; +}; + +export type WhoamiGetErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Forbidden - API key doesn't have access to this location + */ + 403: unknown; + /** + * Not Found - Location not found for the authenticated API key + */ + 404: unknown; + /** + * Internal Server Error - Server error occurred + */ + 500: unknown; +}; + +export type WhoamiGetResponses = { + /** + * Success - Returns location identity object: `{ LocationIdentity }` + */ + 200: LocationIdentity; +}; + +export type WhoamiGetResponse = WhoamiGetResponses[keyof WhoamiGetResponses]; diff --git a/packages/openapi-ts-tests/main/test/openapi-ts.config.ts b/packages/openapi-ts-tests/main/test/openapi-ts.config.ts index bf1515466e..8c32750ea1 100644 --- a/packages/openapi-ts-tests/main/test/openapi-ts.config.ts +++ b/packages/openapi-ts-tests/main/test/openapi-ts.config.ts @@ -34,11 +34,12 @@ export default defineConfig(() => { // }, path: path.resolve( getSpecsPath(), - '3.1.x', + '3.0.x', // 'circular.yaml', + 'dutchie.json', // 'invalid', // 'openai.yaml', - 'full.yaml', + // 'full.yaml', // 'opencode.yaml', // 'sdk-instance.yaml', // 'string-with-format.yaml', @@ -142,16 +143,17 @@ export default defineConfig(() => { // version: () => '3.1.1', }, transforms: { - enums: { - enabled: false, - mode: 'root', - // name: '{{name}}', - }, - readWrite: { - // enabled: false, - requests: '{{name}}Writable', - responses: '{{name}}', - }, + // enums: { + // enabled: false, + // mode: 'root', + // // name: '{{name}}', + // }, + propertiesRequiredByDefault: true, + // readWrite: { + // // enabled: false, + // requests: '{{name}}Writable', + // responses: '{{name}}', + // }, }, validate_EXPERIMENTAL: true, }, diff --git a/packages/openapi-ts-tests/specs/3.0.x/dutchie.json b/packages/openapi-ts-tests/specs/3.0.x/dutchie.json new file mode 100644 index 0000000000..07a1c0c03b --- /dev/null +++ b/packages/openapi-ts-tests/specs/3.0.x/dutchie.json @@ -0,0 +1,14468 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Dutchie Point of Sale API", + "description": "\r\n**Comprehensive REST API for Dutchie Point of Sale Platform Integration**\r\n\r\nThe Dutchie Point of Sale API provides complete access to your cannabis retail operations, enabling seamless integration with third-party systems, custom applications, and business intelligence tools.\r\n\r\n**Core Capabilities:**\r\n• **Product Management** - Create, update, and sync product catalogs with real-time inventory\r\n• **Customer Operations** - Manage customer profiles, loyalty programs, and purchase history \r\n• **Inventory Control** - Track stock levels, receive shipments, and monitor product movement\r\n• **Reporting & Analytics** - Access comprehensive sales, inventory, and customer data\r\n• **Compliance Integration** - Maintain regulatory compliance with automated state reporting\r\n\r\n**Base URL:** `https://api.pos.dutchie.com`\r\n\r\n**Authentication:** All requests require a valid API key provided via HTTP Basic Authentication (username: your API key, password: leave empty).\r\n\r\n**Rate Limiting:** Requests are limited to ensure optimal performance for all users. See individual endpoints for specific limits.\r\n", + "version": "v1.0.0" + }, + "servers": [ + { + "url": "/", + "description": "Current Host" + }, + { + "url": "https://api.pos.dutchie.com", + "description": "Production API Server" + } + ], + "paths": { + "/batch/lab-results": { + "post": { + "tags": ["Batch"], + "summary": "Create or Update Batch Lab Results", + "description": "**Purpose:** Create or update comprehensive laboratory testing results for a specific batch to ensure compliance with cannabis regulations and provide quality assurance data.\n\n**Request Requirements:**\n- \"PackageWrite\" role authorization required for lab data operations\n- `UpdateBatchLabResultsRequest` object in request body with lab result data\n- Content-Type: application/json\n- BatchName must exist and be accessible to your location\n\n**Response Data:**\n- Returns success confirmation (HTTP 200) upon successful creation or update\n- No response body content (void return)\n- Lab results are validated and stored for compliance and quality tracking\n- Updates are reflected immediately in batch data and inventory systems\n\n**Create vs Update Behavior:**\n- **CREATE**: When no lab results exist for the batch, new lab results will be created\n- **UPDATE**: When lab results already exist for the batch, existing results will be updated\n- **Validation**: Lab result data must pass validation requirements for regulatory compliance\n- **Batch Sharing**: All packages within the same batch share identical lab results\n\n**Request Body Fields:**\n- BatchName: Name of the batch to update lab results for (required)\n- SampleWeight: Weight of the sample tested (optional, defaults to -1)\n- LabResults: Array of lab result objects with test data (required)\n\n**Sparse Update Behavior:**\n- **Provided lab results**: Will overwrite existing test data with new values\n- **Omitted lab results**: Existing test data for those analytes will be preserved\n- **Special handling**: If multiple packages exist in the same batch, all will share the updated results\n- **Validation**: All provided lab data must meet regulatory testing standards\n\n**Lab Result Data Types:**\n- **Cannabinoid Testing**: THC, THCA, CBD, CBDA, CBN, CBG concentrations\n- **Safety Testing**: Pesticides, heavy metals, microbials, mycotoxins results\n- **Quality Testing**: Moisture content, foreign matter, residual solvents\n- **Potency Testing**: Total THC/CBD calculations and verification\n- **Terpene Testing**: Terpene profiles and concentration data\n\n**Common Use Cases:**\n- Submit initial lab results from testing laboratory for compliance reporting\n- Update lab results when retesting or additional testing is performed\n- Correct lab result data when errors are discovered\n- Add supplementary testing results (terpenes, additional cannabinoids)\n- Maintain accurate Certificate of Analysis (COA) data for regulatory compliance\n\n**Performance & Limits:**\n- Single batch operation for targeted lab result updates\n- Immediate validation and compliance checking\n- Changes propagate to all packages within the batch immediately\n- Optimized for laboratory workflow integration\n\n**Related Endpoints:**\n- `POST /package/lab-results` - Update lab results by package ID instead of batch name\n- `GET /inventory/labresults` - Retrieve lab results for display and verification\n- `GET /reference/lab-result-units` - Get valid units for lab result data\n- `GET /reference/lab-results-names` - Get valid analyte names for testing\n\n**Important Notes:**\n- **Batch Sharing**: All packages in the same batch will share these lab results\n- **Compliance Critical**: Lab results are required for legal cannabis sales and regulatory reporting\n- **Data Integrity**: Validation ensures lab results meet regulatory standards\n- **Certificate Updates**: Changes update Certificate of Analysis (COA) documentation\n- **Alternative Access**: Use POST /package/lab-results if you prefer to work with package IDs", + "operationId": "BatchLab-resultsPost", + "requestBody": { + "description": "Batch lab results update request with batch name and lab data - UpdateBatchLabResultsRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/UpdateBatchLabResultsRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBatchLabResultsRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBatchLabResultsRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdateBatchLabResultsRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Lab results successfully created or updated" + }, + "400": { + "description": "Bad Request - String error message (parse response body as plain text) OR `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResult" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "404": { + "description": "Not Found - Batch with specified name does not exist", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/brand": { + "get": { + "tags": ["Brand"], + "summary": "Get All Brands", + "description": "**Purpose:** Retrieve comprehensive list of all active product brands available for the authenticated location.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of brand objects: `[{ Brand }, ...]`\n- Array typically contains 10-100 brands per location\n- Returns empty array `[]` if no brands configured for location\n- Brand ID, name, and optional external catalog identifiers\n- Only active, non-deleted brands are included in results\n- Results automatically filtered to authenticated location\n\n**Common Use Cases:**\n- Populate brand dropdown lists in product creation and editing forms\n- Show available brands for product categorization and filtering on e-commerce sites\n- Group products by brand for inventory management and organization\n- Generate brand-specific reports for regulatory compliance requirements\n- Organize dispensary menus by brand for customer browsing\n- Synchronize brand data with external POS and e-commerce systems\n\n**Performance & Limits:**\n- Lightweight data that is typically small and fast to retrieve\n- This endpoint is commonly called for form population and product management\n- No pagination needed due to typically small brand datasets\n\n**Related Endpoints:**\n- `GET /products` - Get products which include brand information in response\n- `POST /brand` - Create or update brand information\n\n**Important Notes:**\n- Despite the singular endpoint name `/brand`, this method returns multiple brands (an array)\n- Brands are automatically scoped to the authenticated dispensary location\n- Only active brands are returned; deleted brands are excluded\n- Brands returned here can be used when creating or updating products", + "operationId": "BrandGet", + "responses": { + "200": { + "description": "Success - Returns array of brand objects: `[{ Brand }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Brand" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for brand access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + }, + "post": { + "tags": ["Brand"], + "summary": "Create or Update Brand", + "description": "**Purpose:** Creates a new brand or updates an existing brand with the provided brand information.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- `BrandEditRequest` object in request body with brand details\n- Content-Type: application/json\n\n**Response Data:**\n- Returns brand object: `{ Brand }`\n- Includes assigned or updated brand ID and all brand properties\n\n**Create vs Update Behavior:**\n- **CREATE**: When `BrandId` is null or omitted, a new brand will be created\n- **UPDATE**: When `BrandId` is provided with a valid brand ID, the existing brand will be updated\n- **Validation**: Brand name is required for both operations and must be unique within the location\n\n**Sparse Update Behavior:**\n- **Provided fields**: Will overwrite existing brand values with provided data\n- **Omitted fields**: Will preserve existing brand values (no data loss)\n- **Required validation**: BrandName must be provided even for updates\n\n**Common Use Cases:**\n- Add new product brands to the system for product categorization\n- Update existing brand information when details change\n- Maintain brand consistency across products and inventory\n- Synchronize brand data from external systems\n\n**Performance & Limits:**\n- Single brand operation for targeted updates\n- Immediate validation and response\n- Changes are reflected immediately in brand listings\n\n**Related Endpoints:**\n- `GET /brand` - Retrieve all brands to see current brand list\n- `GET /products` - View products that use specific brands\n\n**Important Notes:**\n- Brand name must be unique within the authenticated location\n- All validation errors will be returned in a structured error response\n- This endpoint handles a single brand per request\n- Successful operations return the complete brand object", + "operationId": "BrandPost", + "requestBody": { + "description": "Brand information to create or update - BrandEditRequest object with brand details", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/BrandEditRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/BrandEditRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BrandEditRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BrandEditRequest" + } + } + }, + "x-bodyName": "brand" + }, + "responses": { + "200": { + "description": "Success - Returns brand object: `{ Brand }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Brand" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/customer/customers": { + "get": { + "tags": ["Customer"], + "summary": "Get Customers", + "description": "**Purpose:** Retrieves a list of customers with optional filtering by modification date, customer ID, or unique ID for customer management and data synchronization.\n\n**Request Requirements:**\n- \"Customer\" role authorization required for customer data operations\n- Optional query parameters for filtering results\n- No request body needed\n\n**Response Data:**\n- Returns array of customer objects: `[{ Customer }, ...]`\n- Array may contain 0 to 10,000+ customers depending on location and filtering\n- Returns empty array `[]` if no customers match criteria (not null)\n- Includes loyalty status and qualifying conditions when available\n- Results automatically filtered by the authenticated user's location\n- Customer profiles with contact information and preferences\n\n**Filtering Options:**\n- No parameters: Returns all customers for the location\n- fromLastModifiedDateUTC: Returns customers modified after this date for incremental sync\n- toLastModifiedDateUTC: Returns customers modified before this date for date range filtering\n- customerID: Returns a specific customer by internal ID\n- uniqueId: Returns a specific customer by unique identifier\n- includeAnonymous: Include/exclude anonymous customers (default: true)\n\n**Common Use Cases:**\n- Call without parameters for initial sync to get all customers\n- Use fromLastModifiedDateUTC for incremental sync to get only recent changes\n- Use customerID or uniqueId for specific customer retrieval\n- Sync customer data for point-of-sale systems integration\n- Export customer data for external CRM or marketing systems\n\n**Performance & Limits:**\n- Maximum date range is configurable per location (default: 90 days)\n- Use incremental sync for large datasets to avoid timeouts\n- Optimized for high-volume data synchronization\n- Consider using paginated endpoint for very large customer bases\n\n**Related Endpoints:**\n- `GET /customer/customers-paginated` - Paginated version for large datasets\n- `POST /customer` - Create or update customer information\n- `POST /customerLookup` - Find existing customers by various search criteria\n\n**Important Notes:**\n- Results filtered to authenticated user's location for data security\n- Date range limits help prevent timeouts with large customer databases\n- Anonymous customers can be included or excluded based on business needs\n- Loyalty status information included when available for customer insights", + "operationId": "CustomerCustomersGet", + "parameters": [ + { + "name": "fromLastModifiedDateUTC", + "in": "query", + "description": "Optional date filter to return customers modified after this timestamp - Used for incremental sync", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "toLastModifiedDateUTC", + "in": "query", + "description": "Optional date filter to return customers modified before this timestamp - Used for date range filtering", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "customerID", + "in": "query", + "description": "Optional customer ID to return a specific customer by internal ID", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "includeAnonymous", + "in": "query", + "description": "Include/exclude anonymous customers in results - Default: true", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "uniqueId", + "in": "query", + "description": "Optional unique ID to return a specific customer by unique identifier - Must be valid long integer when provided", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of customer objects: `[{ Customer }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Customer" + } + } + } + } + }, + "400": { + "description": "Bad Request - Invalid date range or uniqueId format", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for customer data operations" + }, + "404": { + "description": "Not Found - Customer not found when searching by customerID or uniqueId" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/customer/customers-paginated": { + "get": { + "tags": ["Customer"], + "summary": "Get Customers (Paginated)", + "description": "**Purpose:** Retrieves customers in paginated chunks for better performance with large customer datasets and efficient memory management.\n\n**Request Requirements:**\n- \"Customer\" role authorization required for customer data operations\n- Optional query parameters for pagination and filtering\n- No request body needed\n\n**Response Data:**\n- Response format: `[{ Customer }, { Customer }, ...]`\n- **No pagination metadata**: Response contains only data array without total counts or page information\n- Array contains up to PageSize customers (default 1000, max 10000)\n- Returns empty array `[]` if no customers found for page (not null)\n- Includes loyalty status and qualifying conditions when available\n- Results automatically filtered by the authenticated user's location\n\n**Pagination Usage:**\n- **First Request**: Call with PageNumber=0 to get first page\n- **Subsequent Requests**: Increment PageNumber for each additional page\n- **End Detection**: Continue requesting pages until you receive an empty array `[]`\n- **Page Size Control**: Use PageSize parameter to control items per page (max 10,000)\n- **Example Flow**: Request PageNumber=0 → Process results → Increment PageNumber → Repeat until empty `[]` response\n\n**Pagination Detection:**\n- **End of data detection**: Continue requesting pages until you receive an empty array `[]`\n- **No metadata provided**: Response does not include total counts, page counts, or hasNextPage indicators\n- **Sequential access**: Increment PageNumber from 0 until empty response indicates no more data\n\n**Filtering Options:**\n- fromLastModifiedDateUTC: Returns customers modified after this date\n- toLastModifiedDateUTC: Returns customers modified before this date\n- includeAnonymous: Include/exclude anonymous customers (default: true)\n\n**Common Use Cases:**\n- Process large customer databases efficiently for data export\n- Batch processing customers to avoid memory issues in applications\n- Large-scale customer data synchronization with external systems\n- Generate customer reports without overwhelming system resources\n- Support high-volume customer data operations with controlled memory usage\n\n**Performance & Limits:**\n- Maximum 10,000 customers per page for optimal performance\n- Use consistent page size throughout pagination sequence for efficiency\n- Monitor response times and adjust page size for optimal performance\n- Cache results locally to minimize API calls and improve responsiveness\n- Recommended over non-paginated endpoint for datasets over 1000 customers\n\n**Related Endpoints:**\n- `GET /customer/customers` - Non-paginated version for smaller datasets\n- `POST /customer` - Create or update customer information\n- `POST /customerLookup` - Find specific customers by search criteria\n\n**Important Notes:**\n- Use this endpoint instead of /customers for better performance with large datasets\n- Results filtered to authenticated user's location for data security\n- Pagination state management required in client applications\n- Suitable for batch processing and large-scale data operations", + "operationId": "CustomerCustomers-paginatedGet", + "parameters": [ + { + "name": "fromLastModifiedDateUTC", + "in": "query", + "description": "Optional date filter to return customers modified after this timestamp", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "toLastModifiedDateUTC", + "in": "query", + "description": "Optional date filter to return customers modified before this timestamp", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "PageNumber", + "in": "query", + "description": "Page number for sequential pagination (integer, starts at 0) - Default: 0", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "PageSize", + "in": "query", + "description": "Number of items per page (integer) - Default: 1000, Maximum: 10000", + "schema": { + "type": "integer", + "format": "int32", + "default": 1000 + } + }, + { + "name": "includeAnonymous", + "in": "query", + "description": "Include/exclude anonymous customers in results - Default: true", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Customer" + } + } + } + } + }, + "400": { + "description": "Bad Request - PageSize exceeds maximum limit of 10,000", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/customer/customer-types": { + "get": { + "tags": ["Customer"], + "summary": "Get Customer Types", + "description": "**Purpose:** Retrieve the complete list of customer types available for the authenticated location, used for customer categorization and compliance.\n\n**Request Requirements:**\n- Valid API key authentication required (no specific role restrictions)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of `CustomerType` objects with customer type information\n- Response format: `[{ CustomerType }, ...]`\n- Array typically contains 2-10 customer types per location\n- Returns empty array `[]` if no customer types enabled for location (rare)\n- Each customer type includes: Id, Name, IsRetail, IsMedical flags\n- Display names include \"Adult Use\", \"Medical\", \"Wholesale\", etc.\n- Results automatically filtered to authenticated location's enabled types\n\n**Customer Type Fields:**\n- Id: Unique identifier for the customer type\n- Name: Display name of the customer type\n- IsRetail: Boolean indicating if this type is for retail customers\n- IsMedical: Boolean indicating if this type is for medical patients\n\n**Common Use Cases:**\n- Populate dropdown/selection lists for customer type in registration forms\n- Ensure customers are assigned to valid, location-specific types for compliance validation\n- Configure point-of-sale systems with available customer categories\n- Configure online ordering systems with proper customer types for e-commerce setup\n- Understand customer type structure for reporting classification and analytics\n- Validate customer type IDs before creating/updating customers\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Customer types rarely change; safe to cache for several hours\n- Small dataset suitable for client-side caching\n- Location-specific results based on API key access\n\n**Integration Workflow:**\n1. Call this endpoint to get available customer types for your location\n2. Present options to users in registration/update forms\n3. Use selected Id in POST /customer requests as CustomerTypeId\n4. Implement validation to ensure selected type is valid for your location\n\n**Related Endpoints:**\n- `POST /customer` - Create customers using these customer type IDs\n- `GET /customer/customers` - Get customers with their assigned types\n- `GET /customer/referral-sources` - Get referral source reference data\n\n**Important Notes:**\n- Customer types are location-specific and may vary between dispensary locations\n- Only returns customer types enabled for your specific location\n- Results automatically filtered based on your API key's location access\n- Use Name field for user-facing displays, Id for API calls\n- Use IsRetail/IsMedical flags for business rule implementation and compliance logic", + "operationId": "CustomerCustomer-typesGet", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomerType" + } + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/customer/referral-sources": { + "get": { + "tags": ["Customer"], + "summary": "Get Referral Sources", + "description": "**Purpose:** Retrieve the complete list of referral sources available system-wide, used for tracking customer acquisition and marketing campaign effectiveness.\n\n**Request Requirements:**\n- \"Customer\" role authorization required for customer data operations\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of string values representing available referral source options\n- Response format: `[\"string\", \"string\", ...]`\n- Array typically contains 10-20 predefined referral sources\n- Returns empty array `[]` if no referral sources configured (rare)\n- Examples include: \"Google\", \"Facebook\", \"Word of Mouth\", \"Print Ad\", \"Radio\", \"TV\", \"Yelp\", \"Instagram\"\n- Standardized list ensures consistent marketing attribution across all locations\n- System-wide reference data for marketing tracking\n\n**Common Use Cases:**\n- Populate \"How did you hear about us?\" dropdown fields in customer registration\n- Track which channels are driving customer acquisition for marketing attribution\n- Measure effectiveness of different marketing strategies for campaign analysis\n- Ensure valid referral source selection in customer profiles for form validation\n- Feed data into marketing analytics and reporting systems for analytics integration\n- Connect customer acquisition costs to specific marketing channels for ROI tracking\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Referral sources change infrequently; safe to cache for extended periods\n- Small static dataset suitable for client-side caching\n- Consistent across all organizations and locations\n\n**Integration Workflow:**\n1. Call this endpoint to get available referral source options\n2. Present options in customer registration or profile update forms\n3. Include selected value when creating/updating customers (if supported)\n4. Use for reporting to analyze customer acquisition patterns\n\n**Marketing Benefits:**\n- Attribution tracking to understand which marketing channels are most effective\n- Budget allocation optimization based on referral source performance\n- Campaign ROI measurement for different marketing campaigns\n- Customer insights to learn how customers discover your dispensary\n\n**Related Endpoints:**\n- `POST /customer` - Create customers with referral source information\n- `GET /customer/customer-types` - Get customer type reference data\n- `GET /customer/customers` - Get customers with their referral source data\n\n**Important Notes:**\n- Returns system-wide referral sources for consistent reporting across all locations\n- Consider adding \"Other\" or \"Prefer not to say\" options in your UI implementation\n- Use these values to populate selection lists in customer forms\n- Validate referral source values against this list before submitting customer data\n- Essential for marketing analytics and customer acquisition tracking", + "operationId": "CustomerReferral-sourcesGet", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/customer/customer": { + "post": { + "tags": ["Customer"], + "summary": "Create or Update Customer", + "description": "**Purpose:** Create new customer profiles or update existing customer information for dispensary operations and e-commerce integration.\n\n**Request Requirements:**\n- \"Customer\" role authorization required for customer data operations\n- `EcomCustomerEdit` object in request body with customer details\n- Content-Type: application/json\n- Optional query parameter to bypass deduplication\n- **Idempotency Support**: Requires `ConsumerKey` header and `IdempotencyKey` field for duplicate prevention (see [Idempotency Documentation](/pages/idempotency.html))\n\n**Response Data:**\n- Returns single `Customer` object (not array) with assigned system ID\n- Response format: `{ Customer }`\n- Includes loyalty program enrollment and qualification status\n- Provides both internal and external system identifiers\n- Contains full customer profile with contact and address information\n\n**Create vs Update Behavior:**\n- **CREATE**: When `CustomerId` is null, 0, or omitted, a new customer record will be created\n- **UPDATE**: When `CustomerId` is provided with a valid customer ID, the existing customer will be updated\n- **Validation**: FirstName, Address1, City, State, PostalCode, Status, and CustomerType are required\n- **Deduplication**: Create operations include smart duplicate detection unless bypassed with query parameter\n\n**Request Body Format:**\n- For new customers: Leave `CustomerId` null or 0 (will be auto-generated)\n- For updates: Include the `CustomerId` in the request\n- FirstName is required (Name will be used as FirstName if FirstName is empty)\n- Address1, City, State, PostalCode are required for address information\n- Status and CustomerType are required for customer classification\n\n**Optional Fields:**\n- DateOfBirth (must be between 1800-01-01 and current date)\n- LastName, MiddleName, NameSuffix, NamePrefix for name information\n- Address2 for additional address details\n- Phone, EmailAddress for contact information\n- EcomUserId for external e-commerce system identifier\n- UniqueId for external system integration\n\n**Sparse Update Behavior:**\n- **Provided fields**: Will overwrite existing values with provided data\n- **Omitted fields**: Will preserve existing values (no data loss for updates)\n- **Special handling**: Name field will be used as FirstName if FirstName is omitted during updates\n- **Validation**: Required fields for updates are more relaxed than for new customer creation\n\n**Smart Deduplication System:**\n- Default behavior automatically searches for existing customers with matching details\n- Helps prevent creating multiple records for the same person\n- Use `bypassDeduplication=true` to force creation of new customer record\n\n**Common Use Cases:**\n- Sync customer profiles from online ordering platforms for e-commerce integration\n- Create new customer accounts during in-store visits and walk-in registration\n- Update existing customer contact and address information\n- Add customers to dispensary loyalty and rewards programs\n- Maintain customer records for regulatory compliance requirements\n- Synchronize customer data with external customer relationship management systems\n\n**Performance & Limits:**\n- Rate limited to 1500 requests per minute (higher limit for high-volume customer operations)\n- Single customer operation for targeted updates\n- Immediate validation and duplicate detection\n- Changes are reflected immediately in customer listings\n- Smart matching algorithms optimize deduplication performance\n\n**Related Endpoints:**\n- `POST /customerLookup` - Find existing customers by various search criteria\n- `POST /search` - Search customers by name, phone, or email for quick lookup\n- `GET /by-external-id` - Retrieve customers using external system identifiers\n- `GET /customers` - List all customers with optional filtering\n\n**Important Notes:**\n- Date of birth must be realistic (between 1800 and current date) for age verification\n- Smart matching helps prevent multiple records for the same person\n- Some fields may be required based on location-specific compliance regulations\n- System validates contact information format and completeness for data quality", + "operationId": "CustomerCustomerPost", + "parameters": [ + { + "name": "bypassDeduplication", + "in": "query", + "description": "Skip duplicate detection and force creation of new customer record - Default: false", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "ConsumerKey", + "in": "header", + "description": "Optional GUID for idempotency checks. When provided with IdempotencyKey in request body, prevents duplicate customer creation", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Customer information to create or update - EcomCustomerEdit object with customer details", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/EcomCustomerEdit" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/EcomCustomerEdit" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/EcomCustomerEdit" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/EcomCustomerEdit" + } + } + }, + "x-bodyName": "customer" + }, + "responses": { + "200": { + "description": "Success - Returns complete Customer object with assigned ID and loyalty status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for customer management" + }, + "404": { + "description": "Not Found - Customer ID provided for update but customer does not exist", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Internal Server Error - Server error occurred during customer processing" + } + } + } + }, + "/customer/customerLookup": { + "post": { + "tags": ["Customer"], + "operationId": "CustomerCustomerLookupPost", + "requestBody": { + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/EcomCustomerEdit" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/EcomCustomerEdit" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/EcomCustomerEdit" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/EcomCustomerEdit" + } + } + }, + "x-bodyName": "customer" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/customer/search": { + "post": { + "tags": ["Customer"], + "summary": "Customer Search (PREVIEW)", + "description": "**NOTE - THIS ENDPOINT IS CURRENTLY IN PREVIEW - IT MAY UNDERGO BREAKING CHANGES IN UPCOMING RELEASES**\n\n\n**Purpose:** Search for customers using multiple criteria with flexible matching to support customer identification and lookup workflows.\n\n**Request Requirements:**\n- \"Customer\" role authorization required for customer data operations\n- `CustomerSearchRequest` object in request body with search criteria\n- Content-Type: application/json\n- At least one search criterion must be provided\n- Rate limited to 360 requests per minute\n\n**Response Data:**\n- Returns array of `CustomerSearchResult` objects with matching customer information\n- Response format: `[{ CustomerSearchResult }, ...]`\n- Array may contain 0 to 100+ customers depending on search criteria specificity\n- Returns empty array `[]` if no customers match search criteria (not null)\n- Same customer may appear multiple times with different match types\n- Includes match type information to identify which criteria matched\n- Results automatically filtered to authenticated location\n\n**Search Criteria (Independent Matching):**\n- **MMJ ID**: Medical marijuana patient identification number\n- **Drivers License ID**: State-issued driver's license number\n- **Email Address**: Customer's email address (exact match)\n- **Phone Number**: Customer's phone number (normalized matching)\n- **LastName + DateOfBirth**: Combined name and birth date search (both required together)\n\n**Search Behavior:**\n- **Independent Fields**: Most fields are searched independently\n- **Combined Fields**: LastName and DateOfBirth must be used together\n- **Multiple Matches**: Same customer may appear with different match types\n- **Location Scoped**: Results filtered to authenticated location only\n- **Case Sensitivity**: Email and name searches are case-insensitive\n\n**Common Use Cases:**\n- Find customers during check-in process for identification verification\n- Locate existing customer records before creating new accounts\n- Search for customers using partial or alternative identification methods\n- Verify customer identity using multiple data points\n- Support customer service lookup workflows\n\n**Performance & Limits:**\n- Rate limited to 360 requests per minute for system protection\n- Optimized for common customer lookup patterns\n- Results limited to reasonable set size for performance\n- Indexed searches for fast response times\n\n**Related Endpoints:**\n- `POST /customer/customerLookup` - Single customer lookup with hierarchy\n- `GET /customer/customers` - List all customers with filtering\n- `POST /customer/customer` - Create or update customer records\n\n**Important Notes:**\n- **PREVIEW STATUS**: This endpoint may undergo breaking changes in future releases\n- **Multiple Results**: Same customer can appear multiple times with different match types\n- **Location Filtering**: Results are automatically scoped to your authenticated location\n- **Rate Limiting**: 360 requests per minute limit applies for system stability\n- **Validation**: At least one search criterion must be provided in the request", + "operationId": "CustomerSearchPost", + "requestBody": { + "description": "Customer search request with search criteria - CustomerSearchRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/CustomerSearchRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerSearchRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CustomerSearchRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CustomerSearchRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomerSearchResult" + } + } + } + } + }, + "400": { + "description": "Bad Request - Validation errors or no search criteria provided", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/customer/by-external-id": { + "get": { + "tags": ["Customer"], + "operationId": "CustomerBy-external-idGet", + "parameters": [ + { + "name": "externalId", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomerSearchResult" + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/customer-journal": { + "get": { + "tags": ["CustomerJournal"], + "summary": "Get Customer Journal Entries", + "description": "**Purpose:** Retrieves all journal entries (notes/comments) associated with a specific customer for customer service and account management.\n\n**Request Requirements:**\n- \"Customer\" role authorization required for customer data operations\n- Customer ID query parameter required\n- No request body needed\n\n**Response Data:**\n- Returns array of journal entry objects: `[{ JournalEntry }, ...]`\n- Array may contain 0 to 100+ entries depending on customer interaction history\n- Returns empty array `[]` if no journal entries exist for customer (not null)\n- Includes entry ID, subject, body, and date\n- Results filtered by customer accessibility to authenticated location\n\n**Common Use Cases:**\n- View interaction history and notes about a customer for customer service\n- Review previous communications and issues for account management\n- Maintain audit trail of customer interactions for compliance\n- Track resolution history and follow-ups for support tickets\n\n**Performance & Limits:**\n- Efficient retrieval for individual customer journal histories\n- Results scoped to specific customer and location\n- No pagination needed for typical journal entry volumes\n\n**Related Endpoints:**\n- `POST /customer-journal/create` - Create new journal entries\n- `POST /customer-journal/update` - Update existing journal entries\n\n**Important Notes:**\n- Customer ID must exist and be accessible to your location\n- Requires customer validation before retrieving entries\n- Entries are returned in database order (not explicitly sorted)", + "operationId": "Customer-journalGet", + "parameters": [ + { + "name": "customerId", + "in": "query", + "description": "Internal customer ID to retrieve journal entries for - Must exist and be accessible to your location", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of journal entry objects: `[{ JournalEntry }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JournalEntry" + } + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for customer access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/customer-journal/update": { + "post": { + "tags": ["CustomerJournal"], + "summary": "Update Customer Journal Entry", + "description": "**Purpose:** Updates an existing journal entry's date, subject, and/or body content for customer service record management.\n\n**Request Requirements:**\n- \"Customer\" role authorization required for customer data operations\n- `UpdateJournalEntryRequest` object in request body\n- Content-Type: application/json\n- Journal entry must exist and be accessible to your location\n\n**Response Data:**\n- Returns journal entry object: `{ JournalEntry }`\n- Includes entry ID, updated subject, body, and date\n- Confirms successful update with complete entry details\n\n**Request Body Fields:**\n- JournalEntryId: The ID of the journal entry to update (required)\n- Subject: New title or summary for the entry (required)\n- Body: New detailed content for the entry (required)\n- Date: New date for the entry (required)\n\n**Update Behavior:**\n- **All fields required**: JournalEntryId, Subject, Body, and Date must all be provided\n- **Complete replacement**: All entry fields will be updated with provided values\n- **Validation**: Entry must exist and be accessible to your location\n\n**Common Use Cases:**\n- Fix typos or errors in previously created entries for correction\n- Add more details to existing notes for additional information\n- Update resolution status or follow-up information for status updates\n- Modify entries to meet regulatory requirements for compliance updates\n\n**Performance & Limits:**\n- Single entry update operation for targeted modifications\n- Immediate validation and response\n- Changes reflected immediately in journal entry lists\n\n**Related Endpoints:**\n- `GET /customer-journal` - Retrieve journal entries for a customer\n- `POST /customer-journal/create` - Create new journal entries\n\n**Important Notes:**\n- Journal entry must exist and be accessible to your location\n- Validation performed before update to ensure data integrity\n- All request fields are required for successful update", + "operationId": "Customer-journalUpdatePost", + "requestBody": { + "description": "Journal entry update request with required fields to update - UpdateJournalEntryRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/UpdateJournalEntryRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateJournalEntryRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdateJournalEntryRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdateJournalEntryRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Returns journal entry object: `{ JournalEntry }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JournalEntry" + } + } + } + }, + "400": { + "description": "Bad Request - Validation errors or invalid journal entry ID", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for customer access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/customer-journal/create": { + "post": { + "tags": ["CustomerJournal"], + "summary": "Create Customer Journal Entry", + "description": "**Purpose:** Creates a new journal entry (note/comment) for a specific customer to maintain interaction records and customer service history.\n\n**Request Requirements:**\n- \"Customer\" role authorization required for customer data operations\n- `CreateJournalEntryRequest` object in request body\n- Content-Type: application/json\n- Customer must exist and be accessible to your location\n\n**Response Data:**\n- Returns journal entry object: `{ JournalEntry }`\n- Includes assigned entry ID, subject, body, and date\n- Confirms successful creation with complete entry details\n\n**Request Body Fields:**\n- CustomerId: The customer to create the journal entry for (required)\n- Subject: Brief title or summary of the entry (required)\n- Body: Detailed content of the journal entry (required)\n- Date: When this entry should be dated (required)\n\n**Common Use Cases:**\n- Record interaction details and resolutions for customer service notes\n- Document changes to customer information for account updates\n- Log problems and their resolution status for issue tracking\n- Maintain required interaction records for compliance documentation\n- Schedule future contact or actions for follow-up reminders\n\n**Performance & Limits:**\n- Single entry creation operation for immediate record keeping\n- Immediate validation and creation\n- New entries appear immediately in journal entry lists\n\n**Related Endpoints:**\n- `GET /customer-journal` - Retrieve journal entries for a customer\n- `POST /customer-journal/update` - Update existing journal entries\n\n**Important Notes:**\n- Customer must exist and be accessible to your location\n- Validation performed before creation to ensure data integrity\n- All request fields are required for successful creation", + "operationId": "Customer-journalCreatePost", + "requestBody": { + "description": "Journal entry creation request with customer ID and entry details - CreateJournalEntryRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/CreateJournalEntryRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateJournalEntryRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CreateJournalEntryRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CreateJournalEntryRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Returns journal entry object: `{ JournalEntry }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JournalEntry" + } + } + } + }, + "400": { + "description": "Bad Request - Validation errors or invalid customer ID", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for customer access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/Deliveries": { + "get": { + "tags": ["Deliveries"], + "summary": "Get Deliveries", + "description": "**Purpose:** Retrieve delivery status information and order details for cannabis delivery operations and tracking.\n\n**Request Requirements:**\n- \"Deliveries\" role authorization required for delivery data access\n- Optional query parameters for filtering and data inclusion\n- Rate limited to 100 requests per minute\n- No request body needed\n\n**Response Data:**\n- Returns array of delivery objects: `[{ DeliveryOrderStatus }, ...]`\n- Array may contain 0 to 100+ deliveries depending on filtering criteria\n- Returns empty array `[]` if no deliveries match criteria (not null)\n- Delivery status, timing, and location information included\n- Optional line item details when includeLineItems=true\n- Results automatically filtered to authenticated location\n\n**Query Parameters:**\n- PreOrderId: Get delivery status for a specific pre-order (optional)\n- TransactionId: Get delivery status for a specific transaction (optional)\n- transactionIds: Get delivery status for multiple transactions (optional array)\n- deliveryStatus: Filter by delivery status (optional)\n- includeLineItems: Include detailed line item data (default: false)\n\n**Parameter Rules:**\n- **Mutually Exclusive**: Use only ONE of PreOrderId, TransactionId, transactionIds, or deliveryStatus\n- **Default Behavior**: If no parameters provided, returns all open deliveries from last 14 days\n- **Open Definition**: Status of 'filled' or 'received' within the last 14 days\n- **Line Items**: Only available for packages assigned to orders, not unassigned pre-order items\n\n**Delivery Status Values:**\n- **Placed**: Order has been placed but not yet processed\n- **Filled**: Order has been fulfilled and packaged for delivery\n- **Received**: Order has been received by delivery team\n- **In Transit**: Order is currently being delivered\n- **Delivered**: Order has been successfully delivered to customer\n- **Cancelled**: Order has been cancelled\n\n**Common Use Cases:**\n- Monitor delivery status for customer service and tracking\n- Generate delivery reports for operational management\n- Track order fulfillment and delivery performance\n- Provide delivery updates to customers and delivery teams\n- Integrate with third-party delivery tracking systems\n\n**Performance & Limits:**\n- Rate limited to 100 requests per minute for system protection\n- Optimized for delivery tracking and status monitoring\n- Line item data loading is conditional for performance\n- Results filtered to location scope for operational relevance\n\n**Related Endpoints:**\n- `POST /deliveries/set-route-detail` - Update delivery route and driver information\n- `GET /drivers` - Get available drivers for delivery assignments\n- `GET /preorder` - Get pre-order information that may become deliveries\n\n**Important Notes:**\n- **Exclusive Parameters**: Only use one filtering parameter at a time\n- **Line Item Limitation**: Line items only shown for assigned packages, not pre-order items\n- **Time Window**: Default query covers last 14 days of open deliveries\n- **Rate Limiting**: 100 requests per minute limit for delivery tracking operations\n- **Status Tracking**: Provides real-time delivery status for customer and operational visibility", + "operationId": "DeliveriesGet", + "parameters": [ + { + "name": "PreOrderId", + "in": "query", + "description": "Pre-order ID to get delivery status for - Optional, mutually exclusive with other filters", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "TransactionId", + "in": "query", + "description": "Transaction ID to get delivery status for - Optional, mutually exclusive with other filters", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "transactionIds", + "in": "query", + "description": "Array of transaction IDs to get delivery status for - Optional, mutually exclusive with other filters", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "includeLineItems", + "in": "query", + "description": "Include detailed line item data in response - Default: false", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "deliveryStatus", + "in": "query", + "description": "Filter deliveries by status - Optional, mutually exclusive with other filters", + "schema": { + "type": "string", + "default": "" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of delivery objects: `[{ DeliveryOrderStatus }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeliveryOrderStatus" + } + } + } + } + }, + "400": { + "description": "Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResult" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for delivery access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/Deliveries/set-route-detail": { + "post": { + "tags": ["Deliveries"], + "summary": "Set Delivery Route Detail", + "description": "**Purpose:** Update delivery route information including vehicle, driver assignments, route details, and delivery status for operational management.\n\n**Request Requirements:**\n- \"Deliveries\" role authorization required for delivery operations\n- `UpdateDeliveryRouteDetailRequest` object in request body with route details\n- Content-Type: application/json\n- Rate limited to 100 requests per minute\n- Valid delivery ID must exist and be accessible to your location\n\n**Response Data:**\n- Returns success confirmation (HTTP 200) upon successful update\n- No response body content (void return)\n- Route details are validated and stored for delivery operations\n\n\n**Request Body Fields:**\n- TransactionId: The delivery transaction to update (required)\n- DriverId: Primary driver assignment for the delivery (optional)\n- DriverId2: Secondary driver assignment for the delivery (optional)\n- VehicleId: Vehicle assigned to the delivery (optional)\n- Route: Route information or notes (optional)\n- Status: Delivery status update (optional)\n\n**Route Detail Updates:**\n- **Vehicle Assignment**: Set vehicle ID for the delivery\n- **Driver Assignment**: Assign primary and optional secondary drivers\n- **Route Information**: Update route notes or details\n- **Status Updates**: Modify delivery status\n\n**Common Use Cases:**\n- Assign delivery vehicles and drivers to pending orders\n- Update delivery routes for optimal efficiency and timing\n- Modify delivery status as orders progress through fulfillment\n- Reassign deliveries to different drivers or vehicles\n- Update delivery information for customer tracking and notifications\n\n**Performance & Limits:**\n- Rate limited to 100 requests per minute for system protection\n- Single delivery operation for targeted route updates\n- Immediate validation and storage of route information\n- Changes propagate to delivery tracking systems immediately\n\n**Related Endpoints:**\n- `GET /deliveries` - Retrieve current delivery status and information\n- `GET /drivers` - Get available drivers for delivery assignments\n- `GET /preorder` - Access pre-order information for delivery preparation\n\n**Important Notes:**\n- **Driver and Vehicle IDs**: Must reference valid drivers and vehicles in the system\n- **Validation**: Request fields are validated before processing updates\n- **Status Tracking**: Updates enable delivery tracking for operations\n- **Rate Limiting**: 100 requests per minute limit for delivery management operations", + "operationId": "DeliveriesSet-route-detailPost", + "requestBody": { + "description": "Delivery route detail update request with transaction ID and delivery information - UpdateDeliveryRouteDetailRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/UpdateDeliveryRouteDetailRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDeliveryRouteDetailRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDeliveryRouteDetailRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdateDeliveryRouteDetailRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Route details successfully updated" + }, + "400": { + "description": "Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResult" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for delivery access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/discounts": { + "get": { + "tags": ["Discounts"], + "summary": "Get Discounts (Legacy)", + "description": "**Purpose:** Retrieves basic discount information using the legacy data structure with limited configuration details.\n\n**LEGACY WARNING:** This endpoint is deprecated. Migrate to `GET /discounts/v2/list` for complete functionality.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for discount data access\n- Optional query parameters for filtering\n- No request body needed\n\n**Response Data:**\n- Returns array of `PublishedDiscount` objects with basic discount information\n- Array typically contains 5-50 discounts per location depending on active promotions\n- Returns empty array `[]` if no discounts are active or configured\n- Validity dates are converted from Eastern Time to UTC in response\n- Automatically excludes \"Loyalty Multiplier\" discount types\n- Results are filtered by the authenticated location\n\n**Key Limitations vs V2:**\n- Basic response model with limited discount information\n- Missing detailed reward and constraint configuration\n- Does not support advanced discount capabilities\n- Simple inclusion/exclusion data structure only\n\n**Common Use Cases:**\n- Legacy system integrations that cannot be updated immediately\n- Basic discount display when minimal information is sufficient\n- Temporary implementations before V2 migration\n\n**Performance & Limits:**\n- Lightweight response for basic discount listing\n- Filtered results improve response time\n- Consider V2 endpoint for comprehensive discount data\n\n**Related Endpoints:**\n- `GET /discounts/v2/list` - Recommended enhanced endpoint with complete configuration\n\n**Important Notes:**\n- This endpoint is deprecated and may be removed in future versions\n- New integrations should use the V2 endpoint\n- Date conversion assumes Eastern Time input, converts to UTC output", + "operationId": "DiscountsGet", + "parameters": [ + { + "name": "includeInactive", + "in": "query", + "description": "Include deleted or inactive discounts in results - Default: false", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeInclusionExclusionData", + "in": "query", + "description": "Include detailed product/category restriction data - Default: false", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of basic discount information", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublishedDiscount" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublishedDiscount" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublishedDiscount" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/discounts/v2/list": { + "get": { + "tags": ["Discounts"], + "summary": "Get Discounts V2 (Recommended)", + "description": "**Purpose:** Retrieves comprehensive discount information including detailed reward configuration, payment restrictions, and advanced bundling logic.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for discount data access\n- Optional query parameters for enhanced data inclusion\n- No request body needed\n\n**Response Data:**\n- Returns array of `DiscountApiResponse` objects with complete discount configuration\n- Array typically contains 5-50 discounts per location depending on active promotions\n- Returns empty array `[]` if no discounts are active or configured\n- Validity dates are converted from Eastern Time to UTC in response\n- Includes detailed reward structure and constraint details\n- Results are filtered by the authenticated location\n\n**Enhanced Features vs Legacy:**\n- Complete response model with detailed discount configuration\n- Full discount reward structure and constraint details\n- Payment method restrictions (credit card, cash, etc.)\n- Advanced bundle discount logic and stacking configuration\n- E-commerce menu display configuration and ranking\n- Optimized data retrieval and processing\n\n**Common Use Cases:**\n- New discount integrations requiring complete configuration data\n- E-commerce systems needing full discount logic implementation\n- Point-of-sale systems requiring comprehensive discount rules\n- Advanced analytics and discount performance analysis\n- Payment processing systems validating payment method restrictions\n\n**Performance & Limits:**\n- Single request retrieves all discount data efficiently\n- Optimized processing for large discount configurations\n- Consider parameter filtering to reduce response size when needed\n\n**Related Endpoints:**\n- `GET /discounts` - Legacy endpoint with basic discount information (deprecated)\n\n**Important Notes:**\n- This is the recommended endpoint for all new integrations\n- Includes latest discount capabilities and improvements\n- Date conversion assumes Eastern Time input, converts to UTC output", + "operationId": "DiscountsV2ListGet", + "parameters": [ + { + "name": "includeInactive", + "in": "query", + "description": "Include deleted or inactive discounts in results - Default: false", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeInclusionExclusionData", + "in": "query", + "description": "Include detailed product/category restriction data - Default: false", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includePaymentRestrictions", + "in": "query", + "description": "Include credit card and payment method restrictions - Default: false", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of comprehensive discount configuration objects", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiscountApiResponse" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiscountApiResponse" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiscountApiResponse" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/drivers": { + "get": { + "tags": ["Drivers"], + "summary": "Get Drivers", + "description": "**Purpose:** Retrieves the complete list of drivers for the authenticated location for delivery operations and transportation management.\n\n**Request Requirements:**\n- \"Reporting\" or \"Deliveries\" role authorization required for driver data access\n- No query parameters or request body needed\n\n**Response Data:**\n- Response format: `[{ DriverDetail }, { DriverDetail }, ...]`\n- Array typically contains 2-20 drivers per location\n- Returns empty array `[]` if no drivers configured for location\n- Includes driver ID, name, state ID, and driver's license number\n- Location-specific driver roster for delivery and transportation operations\n\n**Common Use Cases:**\n- Populate driver dropdown lists in delivery assignment systems\n- Support delivery operations and route management workflows\n- Validate driver assignments in delivery and transportation systems\n- Access basic driver information for compliance and operational purposes\n\n**Performance & Limits:**\n- Location-specific driver data filtered to authenticated location\n- No pagination needed for typical location driver counts\n- Optimized for delivery operations and transportation management\n\n**Related Endpoints:**\n- `POST /drivers` - Create or update driver information\n- `GET /deliveries` - Get deliveries that may be assigned to these drivers\n- Delivery and transportation endpoints that utilize driver assignments\n\n**Important Notes:**\n- Drivers are scoped to location level for operational relevance\n- Requires Reporting or Deliveries role for access to driver information\n- Essential for delivery operations and transportation compliance\n- Driver information includes basic licensing information\n- Used for delivery assignment and route management", + "operationId": "DriversGet", + "responses": { + "200": { + "description": "Success - Returns array of driver objects: `[{ DriverDetail }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DriverDetail" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for driver access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + }, + "post": { + "tags": ["Drivers"], + "summary": "Create or Update Driver", + "description": "**Purpose:** Creates a new driver or updates existing driver information for delivery operations and transportation management.\n\n**Request Requirements:**\n- \"Reporting\" or \"Deliveries\" role authorization required for driver data operations\n- `DriverDetail` object in request body with driver information\n- Content-Type: application/json\n- Driver data must pass validation requirements\n\n**Response Data:**\n- Response format: `200 OK` (no response body)\n- Returns success confirmation upon successful creation or update\n- Driver information is validated and stored for operational use\n- Updates reflected immediately in driver listings and assignments\n\n**Request Body Fields:**\n- DriverId: Driver identifier for updates (0 for new drivers)\n- Name: Driver's full name (required)\n- StateId: State identifier for licensing (optional)\n- DriversLicense: Driver's license number (required)\n\n**Create vs Update Behavior:**\n- **CREATE**: When DriverId is 0 or omitted, creates a new driver record\n- **UPDATE**: When DriverId is provided with valid driver ID, updates existing driver\n- **Validation**: All provided data must pass driver validation requirements\n\n**Common Use Cases:**\n- Add new drivers to the delivery team for expanding operations\n- Update existing driver information when licenses or details change\n- Maintain accurate driver records for compliance and operational purposes\n- Support driver onboarding and management workflows\n\n**Performance & Limits:**\n- Single driver operation for targeted updates\n- Immediate validation and storage\n- Changes reflected immediately in driver listings\n- Location-scoped driver management for operational relevance\n\n**Related Endpoints:**\n- `GET /drivers` - Retrieve current driver information\n- `GET /deliveries` - Get deliveries that may be assigned to drivers\n- Delivery management endpoints that utilize driver assignments\n\n**Important Notes:**\n- Driver information must pass validation before storage\n- Drivers are scoped to location level for operational management\n- Essential for delivery operations and transportation compliance\n- Basic licensing information required for compliance\n- Changes immediately available for delivery assignment and scheduling", + "operationId": "DriversPost", + "requestBody": { + "description": "Driver information to create or update - DriverDetail object with driver details", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/DriverDetail" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DriverDetail" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DriverDetail" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DriverDetail" + } + } + }, + "x-bodyName": "driver" + }, + "responses": { + "200": { + "description": "Success - Driver successfully created or updated" + }, + "400": { + "description": "Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResult" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for driver access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/employees": { + "get": { + "tags": ["Employees"], + "summary": "Get Employees", + "description": "**Purpose:** Retrieves the complete list of employees for the authenticated organization for staff management and operational workflows.\n\n**Request Requirements:**\n- \"Employee\" role authorization required for employee data access\n- No query parameters or request body needed\n- Rate limited to 300 requests per minute\n\n**Response Data:**\n- Returns array of employee objects: `[{ Employee }, ...]`\n- Array typically contains 5-100 employees per organization\n- Returns empty array `[]` if no employees configured (rare)\n- Includes employee ID, name, location assignments, and permission details\n- Organization-level employee directory filtered to authenticated organization\n- Staff information for operational and management purposes\n\n**Common Use Cases:**\n- Populate employee dropdown lists in scheduling and assignment systems\n- Support staff management and operational workflow assignments\n- Generate employee directories and contact lists for internal use\n- Validate employee assignments in transaction and operational systems\n- Enable staff-based reporting and analytics for management\n- Support payroll and HR integration systems\n\n**Performance & Limits:**\n- Rate limited to 300 requests per minute for optimal performance\n- Organization-level employee data filtered to authenticated organization\n- No pagination needed for typical organization employee counts\n- Optimized for internal operational and management use cases\n\n**Related Endpoints:**\n- Transaction endpoints that may reference employee assignments\n- Operational endpoints that utilize employee information\n- Reporting endpoints that include employee-based analytics\n\n**Important Notes:**\n- Employees are scoped to organization level (LSP) for data security\n- Requires Employee role authorization for access to sensitive staff information\n- Rate limiting enforced to protect employee data and system performance\n- Essential for staff management and operational workflow support\n- Employee information may be used for transaction tracking and audit trails\n- Supports internal operational systems and management workflows", + "operationId": "EmployeesGet", + "responses": { + "200": { + "description": "Success - Returns array of Employee objects: `[{ Employee }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Employee" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for employee access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/guestlist": { + "get": { + "tags": ["GuestList"], + "summary": "Guest List (Active Check-ins)", + "description": "**Purpose:** Retrieves a real-time list of customers currently checked into the dispensary location for queue management and customer service.\n\n**Request Requirements:**\n- \"Customer\" role authorization required for guest management functions\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of guest objects: `[{ GuestListEntry }, ...]`\n- Array typically contains 0-50 active guests depending on current business volume\n- Returns empty array `[]` if no customers are currently checked in\n- Customer details including name, customer ID, customer type, and contact information\n- Check-in status with current status and check-in timestamp in UTC\n- Transaction data with associated transaction ID and reference number\n- Terminal information showing POS terminal name where check-in occurred\n- Pre-order source indicating origin of the order (online, walk-in, etc.)\n- Returns only guests checked into the authenticated location\n\n**Data Filtering:**\n- Real-time data showing only currently active check-ins\n- Guests who have completed their visit and checked out will not appear\n- Automatically excludes guests in hidden rooms (administrative areas)\n- Automatically excludes guests in on-hold rooms (temporary holding areas)\n- Results filtered to show only the most recent check-in per customer\n\n**Common Use Cases:**\n- Monitor current guest queue and wait times for queue management\n- Display active customers for budtender assignment on staff dashboards\n- Maintain records of dispensary occupancy for compliance tracking\n- Identify guests and their order status for customer service\n- Track check-in patterns and peak hours for analytics\n\n**Performance & Limits:**\n- Data optimized for real-time display applications\n- Consider implementing appropriate polling intervals for your use case\n- Live data reflects current check-in status immediately\n- Efficient filtering for large guest lists\n\n**Related Endpoints:**\n- `POST /transaction/create-anonymous` - Create anonymous customer check-ins\n\n**Important Notes:**\n- All timestamps are returned in UTC format for consistent processing across time zones\n- Only shows currently active check-ins; completed visits are excluded\n- Location-specific data filtered to authenticated dispensary location\n- Requires customer role authorization for access to guest management functions", + "operationId": "GuestlistGet", + "responses": { + "200": { + "description": "Success - Returns array of guest objects: `[{ GuestListEntry }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GuestListEntry" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for customer access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/harvest": { + "get": { + "tags": ["Harvest"], + "summary": "Get Harvests", + "description": "**Purpose:** Retrieve harvest records for cannabis cultivation operations including tracking, compliance, and operational management.\n\n**Request Requirements:**\n- Either \"Inventory\" or \"Cultivation\" role required for harvest data access\n- Optional query parameters for filtering and date range selection\n- No request body needed\n\n**Response Data:**\n- Returns array of `Harvest` objects with comprehensive harvest information\n- Array may contain 0 to 1,000+ harvests depending on cultivation scale and filtering\n- Returns empty array `[]` if no harvests match criteria (not null)\n- Results ordered by last modified date (most recent first)\n- Harvest details include timing, quantities, strain information, and compliance data\n- Results automatically filtered to authenticated location\n\n**Filtering Options:**\n- fromLastModifiedDateUTC: Returns harvests modified after this date for incremental sync\n- toLastModifiedDateUTC: Returns harvests modified before this date for date range filtering\n- activeHarvests: Filter by harvest status (true=active, false=completed, null=completed only)\n\n**Harvest Status Definitions:**\n- **Active Harvests**: Currently in progress, not yet completed or processed\n- **Completed Harvests**: Finished harvest operations, ready for processing or completed\n- **Default Behavior**: Returns completed harvests only when activeHarvests parameter is null\n\n**Common Use Cases:**\n- Monitor harvest progress and completion status for cultivation management\n- Generate harvest reports for compliance and regulatory reporting\n- Track harvest yields and timing for operational optimization\n- Synchronize harvest data with cultivation management systems\n- Support inventory management and product traceability requirements\n\n**Performance & Limits:**\n- Optimized for cultivation tracking and harvest management workflows\n- Date range filtering recommended for large cultivation operations\n- Results sorted by modification date for chronological tracking\n- Location-scoped results for operational relevance and security\n\n**Related Endpoints:**\n- `POST /harvest` - Create or update individual harvest records\n- `POST /harvest/bulk` - Create or update multiple harvests efficiently\n- `GET /inventory` - View products created from harvest operations\n- Plant and cultivation tracking endpoints for complete workflow\n\n**Important Notes:**\n- **Default Filter**: Returns completed harvests only unless activeHarvests parameter is specified\n- **Date Filtering**: Use date parameters for incremental sync and performance optimization\n- **Compliance Tracking**: Harvest records support cannabis regulatory compliance requirements\n- **Cultivation Integration**: Links with plant tracking and inventory management systems\n- **Yield Tracking**: Provides harvest quantity and quality data for operational analytics", + "operationId": "HarvestGet", + "parameters": [ + { + "name": "fromLastModifiedDateUTC", + "in": "query", + "description": "Filter harvests modified after this date for incremental sync - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "toLastModifiedDateUTC", + "in": "query", + "description": "Filter harvests modified before this date for date range filtering - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "activeHarvests", + "in": "query", + "description": "Filter by harvest status: true=active, false=completed, null=completed only - Default: null (completed only)", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of harvest objects: `[{ Harvest }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Harvest" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for cultivation or inventory access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + }, + "post": { + "tags": ["Harvest"], + "summary": "Create or Update Harvest", + "description": "**Purpose:** Create a new harvest record or update an existing harvest with comprehensive cultivation data for compliance tracking and operational management.\n\n**Request Requirements:**\n- \"CultivationWrite\" role authorization required for harvest data operations\n- `CreateOrUpdateHarvest` object in request body with harvest details\n- Content-Type: application/json\n- Plant and strain information must be valid and accessible to your location\n\n**Response Data:**\n- Returns single integer harvest ID (not array) for the created or updated harvest\n- New harvests receive newly assigned harvest ID\n- Updated harvests return the existing harvest ID\n- ID can be used for subsequent harvest operations and tracking\n\n**Create vs Update Behavior:**\n- **CREATE**: When HarvestId is null or omitted, a new harvest record will be created\n- **UPDATE**: When HarvestId is provided with a valid harvest ID, the existing harvest will be updated\n- **Validation**: Plant and strain data must be valid for both create and update operations\n- **Compliance**: All harvest data must meet cannabis regulatory requirements\n\n**Request Body Fields:**\n- HarvestId: ID for updates (null for new harvests)\n- Plant identification and tracking information\n- Harvest timing and scheduling details\n- Yield quantities and measurement data\n- Strain and genetic information\n- Compliance and regulatory tracking data\n\n**Sparse Update Behavior:**\n- **Provided fields**: Will overwrite existing values with provided data\n- **Omitted fields**: Will preserve existing values (no data loss for updates)\n- **Special handling**: Plant and strain associations require valid references\n- **Validation**: All provided data must meet cultivation and compliance standards\n\n**Common Use Cases:**\n- Record new harvest operations as plants are processed\n- Update harvest records with final yield and quality data\n- Maintain compliance with cannabis cultivation tracking requirements\n- Track harvest timing and efficiency for operational optimization\n- Link harvests to plant tracking and inventory management systems\n\n**Performance & Limits:**\n- Single harvest operation for targeted tracking\n- Immediate validation and compliance checking\n- Changes reflected immediately in harvest listings and reporting\n- Optimized for cultivation workflow integration\n\n**Related Endpoints:**\n- `GET /harvest` - Retrieve harvest records for review and tracking\n- `POST /harvest/bulk` - Create or update multiple harvests efficiently\n- Plant tracking endpoints for complete cultivation workflow\n- `GET /inventory` - View products created from harvest operations\n\n**Important Notes:**\n- **Compliance Critical**: Harvest records are required for cannabis regulatory compliance\n- **Plant Tracking**: Must link to valid plant records for traceability\n- **Yield Accuracy**: Accurate yield data is essential for inventory and compliance\n- **Timing Tracking**: Harvest dates and timing support compliance reporting\n- **Bulk Alternative**: Use POST /harvest/bulk for multiple harvest operations", + "operationId": "HarvestPost", + "requestBody": { + "description": "Harvest information to create or update - CreateOrUpdateHarvest object with harvest details", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/CreateOrUpdateHarvest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOrUpdateHarvest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CreateOrUpdateHarvest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CreateOrUpdateHarvest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Returns harvest ID for created or updated harvest: `integer`", + "content": { + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for cultivation write access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/harvest/bulk": { + "post": { + "tags": ["Harvest"], + "summary": "Bulk Create or Update Harvests", + "description": "**Purpose:** Create or update multiple harvest records in a single operation for efficient cultivation data management and compliance tracking.\n\n**Request Requirements:**\n- \"CultivationWrite\" role authorization required for harvest data operations\n- `BulkCreateOrUpdateHarvest` object in request body with array of harvest details\n- Content-Type: application/json\n- All plant and strain information must be valid and accessible to your location\n- Request validation performed before any operations are executed\n\n**Response Data:**\n- Returns single `BulkCreateOrUpdateHarvestResponse` object (not array) with operation results\n- CreatedHarvestIds: Array of newly created harvest IDs\n- UpdatedHarvestIds: Array of updated harvest IDs\n- Success message confirming completion of operations\n- All operations are atomic - either all succeed or all fail\n\n**Create vs Update Behavior:**\n- **CREATE**: When HarvestId is null or omitted in harvest objects, new harvest records will be created\n- **UPDATE**: When HarvestId is provided with valid harvest IDs, existing harvests will be updated\n- **Mixed Operations**: Single request can include both create and update operations\n- **Validation**: All harvest data must pass validation before any operations are executed\n- **Atomic Processing**: All operations succeed together or all operations fail together\n\n**Request Body Structure:**\n- Harvests: Array of CreateOrUpdateHarvest objects\n- Each harvest object contains the same fields as individual harvest operations\n- Plant identification, timing, yield, strain, and compliance data for each harvest\n- Mixed create (HarvestId=null) and update (HarvestId=provided) operations supported\n\n**Bulk Processing Benefits:**\n- **Efficiency**: Process multiple harvests in single API call\n- **Performance**: Optimized database operations for large cultivation operations\n- **Consistency**: Atomic operations ensure data integrity\n- **Compliance**: Batch compliance checking and validation\n- **Convenience**: Simplifies integration for cultivation management systems\n\n**Common Use Cases:**\n- Process multiple harvest operations from cultivation management systems\n- Synchronize harvest data between external systems and LeafLogix\n- Update multiple harvest records with final yield and quality data\n- Import harvest data from spreadsheets or external cultivation tracking\n- Maintain compliance with cannabis cultivation tracking requirements\n\n**Performance & Limits:**\n- Optimized for bulk cultivation data processing\n- Atomic transaction processing ensures data consistency\n- All validation performed before any operations are executed\n- Efficient for large-scale cultivation operations\n- Changes reflected immediately in harvest listings and reporting\n\n**Related Endpoints:**\n- `GET /harvest` - Retrieve harvest records for review and tracking\n- `POST /harvest` - Create or update individual harvest records\n- Plant tracking endpoints for complete cultivation workflow\n- `GET /inventory` - View products created from harvest operations\n\n**Important Notes:**\n- **Atomic Operations**: All harvests in the request succeed or fail together\n- **Validation Required**: Complete validation performed before any processing\n- **Compliance Critical**: All harvest records must meet cannabis regulatory requirements\n- **Plant Tracking**: All harvests must link to valid plant records for traceability\n- **Efficiency**: Preferred method for multiple harvest operations", + "operationId": "HarvestBulkPost", + "requestBody": { + "description": "Bulk harvest request with array of harvest operations - BulkCreateOrUpdateHarvest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/BulkCreateOrUpdateHarvest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/BulkCreateOrUpdateHarvest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/BulkCreateOrUpdateHarvest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/BulkCreateOrUpdateHarvest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Returns bulk harvest response object: `{ BulkCreateOrUpdateHarvestResponse }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BulkCreateOrUpdateHarvestResponse" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for cultivation write access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/okcomputer": { + "get": { + "tags": ["HealthCheck"], + "summary": "Health Check Endpoint", + "description": "**Purpose:** Provides a simple health check endpoint to verify the API service is running and responsive.\n\n**Request Requirements:**\n- No authentication or API key required for infrastructure access\n- AllowAnonymous endpoint for monitoring systems\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns health status object: `{ SuccessResult }`\n- HTTP 200 status when the service is healthy\n- Lightweight JSON response for fast monitoring\n\n**Common Use Cases:**\n- Load balancer health checks to route traffic only to healthy instances\n- External monitoring services (Pingdom, DataDog) for uptime alerting\n- Infrastructure monitoring by DevOps teams for service availability\n- Service verification before making other API calls\n- Automated health monitoring in deployment pipelines\n\n**Performance & Limits:**\n- Designed to respond quickly with minimal system requirements\n- No rate limiting applied to health checks\n- Minimal dependencies to ensure reliable health indication\n- Optimized for frequent polling by monitoring systems\n\n**Related Endpoints:**\n- No related endpoints - this is a standalone health check\n\n**Important Notes:**\n- This endpoint bypasses normal authentication for infrastructure access\n- Designed for automated monitoring and load balancer health checks\n- Simple response format optimized for parsing by monitoring tools\n- Available on both `/health-check` and `/okcomputer` routes", + "operationId": "OkcomputerGet", + "responses": { + "200": { + "description": "Success - Service is healthy and responsive", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/SuccessResult" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResult" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResult" + } + } + } + }, + "500": { + "description": "Internal Server Error - Service is experiencing issues" + } + } + } + }, + "/integration/integration-recon": { + "get": { + "tags": ["Integration"], + "summary": "Get Inventory Integration Reconciliation", + "description": "**Purpose:** Retrieve inventory reconciliation data between LeafLogix and external state tracking systems for compliance and integration monitoring.\n\n**Request Requirements:**\n- \"Integrations\" role authorization required for integration data access\n- No query parameters or request body needed\n- Integration management permissions for system reconciliation\n\n**Response Data:**\n- Returns single `InventoryIntegrationReconResponse` object (not array) with reconciliation results\n- Includes inventory discrepancies and integration status information\n- State system synchronization details and compliance tracking data\n- Integration health and data consistency information\n\n**Reconciliation Information Included:**\n- **Inventory Discrepancies**: Items with differences between systems\n- **Integration Status**: Current state of external system synchronization\n- **Compliance Data**: Regulatory tracking and audit trail information\n- **Sync Health**: Integration system connectivity and data flow status\n\n**Common Use Cases:**\n- Monitor inventory synchronization between LeafLogix and state tracking systems\n- Identify and resolve inventory discrepancies for compliance\n- Support compliance audits and regulatory reporting requirements\n- Troubleshoot integration issues and data synchronization problems\n- Maintain accurate inventory records across integrated systems\n\n**Performance & Limits:**\n- Real-time reconciliation data for immediate integration monitoring\n- Comprehensive reconciliation across integrated state tracking systems\n- Optimized for compliance monitoring and integration management workflows\n- Results include comprehensive integration status and discrepancy details\n\n**Related Endpoints:**\n- `GET /inventory` - View current inventory status for comparison\n- `GET /plant` - Check plant inventory integration status\n- `GET /harvest` - Monitor harvest integration synchronization\n\n**Important Notes:**\n- **Compliance Critical**: Essential for regulatory compliance and audit requirements\n- **Integration Monitoring**: Real-time visibility into external system synchronization\n- **Complete Data Access**: Provides comprehensive reconciliation across all integrated systems\n- **State System Integration**: Specific to external state tracking system connectivity\n- **Audit Ready**: Data formatted for compliance reporting and audit requirements", + "operationId": "IntegrationIntegration-reconGet", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InventoryIntegrationReconResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/inventory": { + "get": { + "tags": ["Inventory"], + "summary": "Get Inventory", + "description": "**Purpose:** Retrieve current inventory levels and product details for API-enabled products with available stock.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for inventory data access\n- Optional query parameters for enhanced data inclusion\n- No request body needed\n\n**Response Data:**\n- Returns array of `InventoryItem` objects with current stock and product information\n- Response format: `[{ InventoryItem }, { InventoryItem }, ...]`\n- Array may contain 0 to 5,000+ inventory items depending on location inventory size\n- Returns empty array `[]` if no inventory items have stock or meet criteria\n- Stock levels including available quantities, unit weights, flower equivalent amounts\n- Product details with SKU, name, description, category, brand, pricing (retail/medical)\n- Package data including package ID, batch name, package status, expiration dates\n- Lab results with potency testing, cannabinoid profiles, test dates (when includeLabResults=true)\n- Room breakdown showing quantities by storage location (when includeRoomQuantities=true)\n- Compliance data including external package IDs (METRC/BioTrack), strain information, producer details\n\n**Filtering Options:**\n- includeLabResults: Include detailed lab testing data and cannabinoid profiles (default: false)\n- includeRoomQuantities: Include quantity breakdown by storage room/location (default: false)\n\n**Common Use Cases:**\n- Update online store inventory levels and product availability for e-commerce sync\n- Perform real-time stock checks during sales transactions for POS integration\n- Monitor stock levels across multiple storage locations for inventory management\n- Track package-level inventory for regulatory compliance reporting\n- Show potency and testing information to customers for lab data display\n\n**Performance & Limits:**\n- Response times optimized for high-volume integrations\n- Use minimal parameters for fastest response times\n- Standard rate limits apply for high-volume integrations\n- Data reflects current system state with real-time accuracy\n\n**Related Endpoints:**\n- `GET /products` - Complete product catalog regardless of stock levels (use for menu/catalog display)\n\n**Important Notes:**\n- Only products enabled for API access are returned for access control\n- Products with zero inventory are automatically excluded\n- Results automatically filtered to authenticated user's location only\n- Inventory data reflects current stock levels with real-time accuracy", + "operationId": "InventoryGet", + "parameters": [ + { + "name": "includeLabResults", + "in": "query", + "description": "Include detailed lab testing data and cannabinoid profiles - Default: false", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeRoomQuantities", + "in": "query", + "description": "Include quantity breakdown by storage room/location - Default: false", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of inventory items with product and stock details", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InventoryItem" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for inventory access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/inventory/labresults": { + "get": { + "tags": ["Inventory"], + "operationId": "InventoryLabresultsGet", + "parameters": [ + { + "name": "BatchName", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LabResult" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/inventory/snapshot": { + "get": { + "tags": ["Inventory"], + "operationId": "InventorySnapshotGet", + "parameters": [ + { + "name": "fromDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InventorySnapshot" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/inventory/receivedinventory": { + "get": { + "tags": ["Inventory"], + "operationId": "InventoryReceivedinventoryGet", + "parameters": [ + { + "name": "receiveInventoryHistoryId", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "startDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReceivedInventory" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/inventory/inventorytransaction": { + "get": { + "tags": ["Inventory"], + "operationId": "InventoryInventorytransactionGet", + "parameters": [ + { + "name": "startDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "endDate", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "transactionType", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InventoryTransaction" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/inventory/receiveinventory": { + "post": { + "tags": ["Inventory"], + "summary": "Create Receive Inventory Order", + "description": "**Purpose:** Create a new inventory receive order for incoming transfers, purchase orders, or direct inventory additions.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for inventory operations\n- `ReceiveInventorySave` object in request body with vendor and item details\n- Content-Type: application/json\n- UserId or UserName required when ReceiveIntoInventory=true\n\n**Response Data:**\n- Response format: `{ SavedReceive }`\n- Returns transaction ID and processing status information\n\n**Processing Options:**\n- **Draft Mode (ReceiveIntoInventory=false):** Creates a saved receive order that can be opened/edited in LeafLogix\n- **Direct Processing (ReceiveIntoInventory=true):** Immediately processes items into inventory (requires UserId or UserName)\n\n**Required Information:**\n- **Items Array:** Product details, quantities, costs, room assignments, batch information\n- **Vendor Information:** VendorId, delivery details, licensing information\n- **User Context:** UserId or UserName (required when ReceiveIntoInventory=true)\n\n**Item Details Required:**\n- **Product Identification:** ProductId or SKU, product name\n- **Quantities:** Receive quantity, unit of measure\n- **Costs:** Unit cost, total cost (for cost tracking)\n- **Storage:** Room assignment, expiration dates\n- **Compliance:** Package tags, batch names, lab testing status\n\n**Common Use Cases:**\n- **Transfer Processing:** Receive inventory from other licensed locations\n- **Purchase Orders:** Process incoming vendor deliveries\n- **Direct Additions:** Add inventory directly to stock levels\n- **Compliance Tracking:** Maintain chain of custody for regulatory reporting\n- **Batch Processing:** Handle multiple items in a single receive transaction\n\n**Validation Features:**\n- **Vendor Verification:** Validates vendor exists and is active\n- **Room Validation:** Confirms room assignments are valid for location\n- **Potency Indicators:** Validates required compliance fields\n- **Duplicate Prevention:** ExternalId checking prevents duplicate receives\n- **User Authorization:** Verifies user permissions for inventory operations\n\n**Important Notes:**\n- **User Requirement:** UserId or UserName required when ReceiveIntoInventory=true (cannot specify both)\n- **External ID Uniqueness:** ExternalId must be unique or omitted to prevent duplicates\n- **Vendor License Support:** Supports vendor license code mapping for compliance requirements\n- **Location Scoped:** All operations scoped to authenticated user's location\n- **Enhanced Validation:** Additional validation rules may apply based on location settings\n\n**Request Format:**\nProvide a `ReceiveInventorySave` object containing vendor details, delivery information, and an array of items to receive.", + "operationId": "InventoryReceiveinventoryPost", + "requestBody": { + "description": "Receive inventory order details including vendor, delivery, and item information", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/ReceiveInventorySave" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReceiveInventorySave" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ReceiveInventorySave" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ReceiveInventorySave" + } + } + }, + "x-bodyName": "recInv" + }, + "responses": { + "200": { + "description": "Success - Returns SavedReceive object with transaction details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SavedReceive" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) OR String error message (parse response body as plain text)", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for inventory access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/lineages": { + "get": { + "tags": ["Lineage"], + "summary": "Get Lineages", + "description": "**Purpose:** Retrieves the complete list of genetic lineages available for the authenticated organization for product classification and cannabis genetic tracking.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of lineage objects: `[{ Lineage }, ...]`\n- Array typically contains 10-50 genetic lineages per organization\n- Returns empty array `[]` if no lineages configured (rare)\n- Includes lineage ID, name, and genetic classification details\n- Cannabis genetic lineages and hereditary information for product categorization\n- Results filtered to authenticated organization level\n\n**Common Use Cases:**\n- Track genetic lineage and hereditary information for cannabis products\n- Support compliance reporting with genetic background documentation\n- Populate lineage dropdown lists in product creation and strain management forms\n- Validate genetic lineage assignments in product and cultivation systems\n- Generate lineage-specific reports for cultivation and breeding programs\n- Enable genetic tracking for quality control and consistency\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Small dataset suitable for client-side caching\n- No pagination needed due to manageable number of genetic lineages\n- Results consistent across all locations within organization\n\n**Related Endpoints:**\n- `GET /strains` - Get strains that may be associated with these lineages\n- `GET /products` - Get products with lineage genetic information\n- Cultivation and breeding endpoints that utilize genetic lineage data\n\n**Important Notes:**\n- Lineages are defined at organization level (LSP) for consistency\n- Essential for cannabis genetic tracking and breeding program documentation\n- Used for compliance reporting and genetic background verification\n- Supports cultivation operations with genetic lineage documentation\n- May be required for certain cannabis regulations and track-and-trace systems\n- Helps maintain genetic consistency and quality control in cultivation", + "operationId": "LineagesGet", + "responses": { + "200": { + "description": "Success - Returns array of lineage objects: `[{ Lineage }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Lineage" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/package/set-tags": { + "post": { + "tags": ["Package"], + "summary": "Set Package Tags", + "description": "**Purpose:** Set inventory tags for packages, completely replacing any existing tags with the new tag set for organization and tracking.\n\n**Request Requirements:**\n- \"PackageWrite\" role authorization required for package tag operations\n- `UpdatePackageTagsRequest` object in request body with package identifiers and tags\n- Content-Type: application/json\n- Must specify either InventoryIds OR PackageIds, but not both\n- All specified packages must be accessible to your location\n\n**Response Data:**\n- Returns success confirmation (HTTP 200) upon successful tag assignment\n- No response body content (void return)\n- Tags are validated and applied immediately to specified packages\n- Changes are reflected immediately in inventory listings and package data\n\n**Package Identification Options:**\n- **InventoryIds**: Target specific inventory records directly (one-to-one relationship)\n- **PackageIds**: Target packages by serial numbers (may affect multiple inventory records)\n- **Mutually Exclusive**: Specify either InventoryIds OR PackageIds, never both\n- **Validation**: Using both types will result in 400 Bad Request error\n\n**Tag Operation Behavior:**\n- **Complete Replacement**: All existing tags are removed and replaced with new tags\n- **Tag Validation**: All tags must be valid and available in the system\n- **Immediate Effect**: Changes apply immediately to all specified packages\n- **Bulk Operation**: Can target multiple packages in a single request\n\n**Request Body Fields:**\n- InventoryIds: Array of inventory record IDs (optional, mutually exclusive with PackageIds)\n- PackageIds: Array of package serial numbers (optional, mutually exclusive with InventoryIds)\n- Tags: Array of tag names to apply to the specified packages (required)\n\n**Common Use Cases:**\n- Standardize tag sets across multiple packages for consistency\n- Replace outdated or incorrect tags with current classification\n- Implement new tagging schema by completely updating existing tags\n- Clean up tag sets by removing unwanted tags and setting only desired ones\n- Maintain organized inventory classification for operational efficiency\n\n**Performance & Limits:**\n- Bulk operation optimized for multiple package updates\n- Immediate validation and tag assignment\n- Changes propagate to inventory systems immediately\n- Efficient for large-scale tag management operations\n\n**Related Endpoints:**\n- `POST /package/add-tags` - Add tags while preserving existing tags\n- `POST /package/remove-tags` - Remove specific tags while preserving others\n- `GET /tags` - Retrieve available tag options for validation\n- `GET /inventory` - View packages with their current tag assignments\n\n**Important Notes:**\n- **Complete Replacement**: This operation removes ALL existing tags and replaces them\n- **Tag Validation**: All tags must exist in the system and be valid\n- **Package Access**: All specified packages must be accessible to your authenticated location\n- **Mutual Exclusion**: Cannot use both InventoryIds and PackageIds in the same request\n- **Alternative Operations**: Use add-tags or remove-tags for partial tag modifications", + "operationId": "PackageSet-tagsPost", + "requestBody": { + "description": "Package tag update request with package identifiers and replacement tags - UpdatePackageTagsRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Tags successfully set on specified packages" + }, + "400": { + "description": "Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResult" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/package/add-tags": { + "post": { + "tags": ["Package"], + "summary": "Add Package Tags", + "description": "**Purpose:** Add new inventory tags to packages while preserving all existing tags for enhanced organization and classification.\n\n**Request Requirements:**\n- \"PackageWrite\" role authorization required for package tag operations\n- `UpdatePackageTagsRequest` object in request body with package identifiers and tags\n- Content-Type: application/json\n- Must specify either InventoryIds OR PackageIds, but not both\n- All specified packages must be accessible to your location\n\n**Response Data:**\n- Returns success confirmation (HTTP 200) upon successful tag addition\n- No response body content (void return)\n- New tags are validated and added immediately to specified packages\n- Changes are reflected immediately in inventory listings and package data\n\n**Package Identification Options:**\n- **InventoryIds**: Target specific inventory records directly (one-to-one relationship)\n- **PackageIds**: Target packages by serial numbers (may affect multiple inventory records)\n- **Mutually Exclusive**: Specify either InventoryIds OR PackageIds, never both\n- **Validation**: Using both types will result in 400 Bad Request error\n\n**Tag Operation Behavior:**\n- **Additive Operation**: New tags are added while preserving all existing tags\n- **Duplicate Handling**: Duplicate tags are automatically ignored (no error)\n- **Tag Validation**: All new tags must be valid and available in the system\n- **Immediate Effect**: Changes apply immediately to all specified packages\n- **Bulk Operation**: Can target multiple packages in a single request\n\n**Request Body Fields:**\n- InventoryIds: Array of inventory record IDs (optional, mutually exclusive with PackageIds)\n- PackageIds: Array of package serial numbers (optional, mutually exclusive with InventoryIds)\n- Tags: Array of tag names to add to the specified packages (required)\n\n**Common Use Cases:**\n- Add seasonal or promotional tags to existing products without losing current classification\n- Enhance product categorization by adding supplementary organizational tags\n- Apply new quality control or testing tags while maintaining existing product tags\n- Add compliance or regulatory tags for audit trails without disrupting inventory organization\n- Implement progressive tagging workflows where tags are added over time\n\n**Performance & Limits:**\n- Bulk operation optimized for multiple package updates\n- Immediate validation and tag addition\n- Changes propagate to inventory systems immediately\n- Efficient for incremental tag management operations\n\n**Related Endpoints:**\n- `POST /package/set-tags` - Replace all existing tags with new tag set\n- `POST /package/remove-tags` - Remove specific tags while preserving others\n- `GET /tags` - Retrieve available tag options for validation\n- `GET /inventory` - View packages with their current tag assignments\n\n**Important Notes:**\n- **Preserves Existing**: This operation keeps ALL existing tags and adds new ones\n- **Duplicate Safe**: Adding tags that already exist will not cause errors\n- **Tag Validation**: All new tags must exist in the system and be valid\n- **Package Access**: All specified packages must be accessible to your authenticated location\n- **Mutual Exclusion**: Cannot use both InventoryIds and PackageIds in the same request", + "operationId": "PackageAdd-tagsPost", + "requestBody": { + "description": "Package tag update request with package identifiers and additional tags - UpdatePackageTagsRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Tags successfully added to specified packages" + }, + "400": { + "description": "Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array" + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/package/remove-tags": { + "post": { + "tags": ["Package"], + "summary": "Remove Package Tags", + "description": "**Purpose:** Remove specific inventory tags from packages while preserving all other existing tags for selective tag management.\n\n**Request Requirements:**\n- \"PackageWrite\" role authorization required for package tag operations\n- `UpdatePackageTagsRequest` object in request body with package identifiers and tags to remove\n- Content-Type: application/json\n- Must specify either InventoryIds OR PackageIds, but not both\n- All specified packages must be accessible to your location\n\n**Response Data:**\n- Returns success confirmation (HTTP 200) upon successful tag removal\n- No response body content (void return)\n- Specified tags are removed immediately from specified packages\n- Changes are reflected immediately in inventory listings and package data\n\n**Package Identification Options:**\n- **InventoryIds**: Target specific inventory records directly (one-to-one relationship)\n- **PackageIds**: Target packages by serial numbers (may affect multiple inventory records)\n- **Mutually Exclusive**: Specify either InventoryIds OR PackageIds, never both\n- **Validation**: Using both types will result in 400 Bad Request error\n\n**Tag Operation Behavior:**\n- **Selective Removal**: Only specified tags are removed, all others are preserved\n- **Missing Tag Handling**: Removing tags that don't exist is silently ignored (no error)\n- **Immediate Effect**: Changes apply immediately to all specified packages\n- **Bulk Operation**: Can target multiple packages in a single request\n- **Preservation**: All non-specified tags remain unchanged\n\n**Request Body Fields:**\n- InventoryIds: Array of inventory record IDs (optional, mutually exclusive with PackageIds)\n- PackageIds: Array of package serial numbers (optional, mutually exclusive with InventoryIds)\n- Tags: Array of tag names to remove from the specified packages (required)\n\n**Common Use Cases:**\n- Remove outdated seasonal or promotional tags while keeping product classification\n- Clean up temporary testing or quality control tags after completion\n- Remove incorrect or duplicate tags while preserving accurate classification\n- Implement tag lifecycle management by removing obsolete organizational tags\n- Support compliance workflows by removing temporary audit or review tags\n\n**Performance & Limits:**\n- Bulk operation optimized for multiple package updates\n- Immediate tag removal processing\n- Changes propagate to inventory systems immediately\n- Efficient for selective tag cleanup operations\n\n**Related Endpoints:**\n- `POST /package/set-tags` - Replace all existing tags with new tag set\n- `POST /package/add-tags` - Add new tags while preserving existing tags\n- `GET /tags` - Retrieve available tag options for validation\n- `GET /inventory` - View packages with their current tag assignments\n\n**Important Notes:**\n- **Preserves Others**: This operation keeps ALL non-specified tags unchanged\n- **Missing Tag Safe**: Removing tags that don't exist will not cause errors\n- **Package Access**: All specified packages must be accessible to your authenticated location\n- **Mutual Exclusion**: Cannot use both InventoryIds and PackageIds in the same request\n- **Selective Operation**: Use for precise tag management without affecting other classification", + "operationId": "PackageRemove-tagsPost", + "requestBody": { + "description": "Package tag update request with package identifiers and tags to remove - UpdatePackageTagsRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdatePackageTagsRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Tags successfully removed from specified packages" + }, + "400": { + "description": "Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array" + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant": { + "get": { + "tags": ["Plant"], + "summary": "Get Plants", + "description": "**Purpose:** Retrieve cannabis plant records for cultivation tracking, compliance monitoring, and operational management.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for plant data access\n- Optional query parameters for filtering by plant attributes and date ranges\n- No request body needed\n\n**Response Data:**\n- Response format: `[{ Plant }, { Plant }, ...]`\n- Returns array of `Plant` objects with comprehensive plant information\n- Array may contain 0 to 10,000+ plants depending on cultivation scale and filtering\n- Returns empty array `[]` if no plants match criteria (not null)\n- Plant details include identification, growth status, cultivation tracking, and compliance data\n- Results automatically filtered to authenticated location\n\n**Filtering Options:**\n- plantId: Filter by specific LeafLogix internal plant ID for individual plant lookup\n- serialNumber: Filter by plant serial number for tracking system integration\n- status: Filter by plant status (Active, Harvesting, Harvested, Retired)\n- lastModifiedDateStart: Returns plants modified after this date for incremental sync\n- lastModifiedDateEnd: Returns plants modified before this date for date range filtering\n\n**Plant Status Definitions:**\n- **Active**: Plants currently growing and under cultivation\n- **Harvesting**: Plants currently being harvested or in harvest process\n- **Harvested**: Plants that have completed harvest operations\n- **Retired**: Plants that have been retired from cultivation (destroyed, failed, etc.)\n\n**Common Use Cases:**\n- Monitor plant growth progress and cultivation status for operational management\n- Generate compliance reports for regulatory tracking and auditing\n- Synchronize plant data with cultivation management and tracking systems\n- Track plant lifecycle from cultivation through harvest completion\n- Support inventory management and product traceability requirements\n\n**Performance & Limits:**\n- Optimized for cultivation tracking and plant management workflows\n- Date range filtering recommended for large cultivation operations\n- Plant status filtering efficient for operational dashboards\n- Location-scoped results for operational relevance and security\n\n**Related Endpoints:**\n- `POST /plant/harvest` - Move plants into harvest status\n- `POST /harvest` - Create harvest records for harvested plants\n- `GET /inventory` - View products created from harvested plants\n- Plant lifecycle and cultivation management endpoints\n\n**Important Notes:**\n- **Compliance Tracking**: Plant records support cannabis regulatory compliance requirements\n- **Lifecycle Management**: Tracks complete plant lifecycle from cultivation to harvest\n- **Date Filtering**: Use date parameters for incremental sync and performance optimization\n- **Status Filtering**: Essential for operational workflows and cultivation management\n- **Traceability**: Links with harvest and inventory systems for complete product tracking", + "operationId": "PlantGet", + "parameters": [ + { + "name": "plantId", + "in": "query", + "description": "Dutchie internal plant ID for specific plant lookup - Optional", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "serialNumber", + "in": "query", + "description": "Plant serial number for tracking system integration - Optional", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "Plant status filter: Active, Harvesting, Harvested, Retired - Optional", + "schema": { + "type": "string" + } + }, + { + "name": "lastModifiedDateStart", + "in": "query", + "description": "Filter plants modified after this date for incremental sync - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "lastModifiedDateEnd", + "in": "query", + "description": "Filter plants modified before this date for date range filtering - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Plant" + } + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + }, + "post": { + "tags": ["Plant"], + "summary": "Add Plant", + "description": "**Purpose:** Create a new cannabis plant record in the cultivation system with unique identification and tracking for compliance monitoring and operational management.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for plant creation operations\n- `CreatePlantRequest` object in request body with plant identification and group details\n- Content-Type: application/json\n- Serial number must be unique within the facility\n- Plant group must exist or strain must be provided for new group creation\n\n**Response Data:**\n- Response format: `int` (Plant ID)\n- Returns the newly created plant's unique LeafLogix plant ID\n- Plant ID can be used in subsequent plant management operations\n- Immediate plant creation with tracking system integration\n\n**Request Body Fields:**\n- `PlantGroupName`: Name of plant group for batch tracking (required)\n- `SerialNumber`: Unique plant identifier for compliance tracking (required, must be unique)\n- `Strain`: Strain name for new plant groups (required when creating new plant group)\n- `Room`: Cultivation room name for plant location (required when using state integrations)\n- `BypassStateIntegration`: Skip external system integration (optional, default: false)\n- `DateCreated`: Plant creation date (optional, defaults to current UTC time)\n- `PhaseStartDate`: Initial growth phase start date (optional, defaults to current UTC time)\n\n**Plant Group Behavior:**\n- **Existing Groups**: If plant group exists, strain information is inherited\n- **New Groups**: If plant group doesn't exist, strain must be provided for group creation\n- **Batch Tracking**: Plant groups enable batch-based cultivation tracking and compliance\n- **Strain Assignment**: All plants in a group share the same strain genetics\n\n**Validation Rules:**\n- **Serial Number**: Must be unique across the facility for compliance tracking\n- **Plant Group**: Required for batch organization and cultivation management\n- **Strain Requirement**: Must provide strain when creating new plant groups\n- **Room Validation**: Room name must exist and be accessible when using integrations\n- **State Integration**: Room required unless bypassing external system integration\n\n**Common Use Cases:**\n- Register new clones or seedlings entering the cultivation facility\n- Create plant records for compliance tracking and regulatory reporting\n- Initialize plant tracking for cultivation workflow management\n- Support batch-based cultivation and harvest planning\n- Integrate with external cultivation and compliance systems\n\n**Performance & Limits:**\n- Single plant creation for precise record management\n- Immediate validation and unique identifier assignment\n- Optional integration with external cultivation systems\n- Efficient for individual plant registration workflows\n\n**Related Endpoints:**\n- `GET /plant` - Retrieve created plant information and status\n- `POST /plant/assign-plants-to-group` - Assign existing plants to groups\n- `POST /plant/move` - Move plants between cultivation rooms\n- Plant lifecycle management endpoints for complete workflow\n\n**Important Notes:**\n- **Unique Tracking**: Serial numbers must be unique for compliance and tracking\n- **Compliance Critical**: Plant registration is required for cannabis regulatory compliance\n- **Group Management**: Plant groups support batch-based cultivation workflows\n- **Integration**: External system integration supports cultivation management platforms\n- **Immediate Processing**: Plant creation is immediate with tracking system updates", + "operationId": "PlantPost", + "requestBody": { + "description": "Plant creation request with identification and group details - see `CreatePlantRequest` model for complete field documentation", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/CreatePlantRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePlantRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CreatePlantRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CreatePlantRequest" + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success - Returns newly created plant ID as integer", + "content": { + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "400": { + "description": "Bad Request - Validation errors or duplicate serial number", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/harvest": { + "post": { + "tags": ["Plant"], + "summary": "Harvest Plants", + "description": "**Purpose:** Move plants from cultivation into harvest status with optional weight tracking for cannabis cultivation compliance and operational management.\n\n**Request Requirements:**\n- \"CultivationWrite\" role authorization required for plant harvest operations\n- `HarvestPlantRequest` object in request body with plant identifiers and harvest details\n- Content-Type: application/json\n- Rate limited to 300 requests per minute\n- All specified plants must be accessible to your location and in valid status for harvesting\n\n**Response Data:**\n- Response format: No response body (void)\n- Returns success confirmation (HTTP 200) upon successful harvest initiation\n- No response body content (void return)\n- Plants are moved to harvesting status immediately\n- Changes are reflected immediately in plant listings and cultivation tracking\n\n**Request Body Fields:**\n- Plant identifiers for the plants to be harvested\n- Optional wet weight measurements for harvest tracking\n- Harvest timing and operational details\n- Compliance and tracking information required for regulatory reporting\n\n**Harvest Operation Behavior:**\n- **Status Change**: Plants are moved from Active to Harvesting status\n- **Weight Tracking**: Optional wet weight can be recorded for yield tracking\n- **Bulk Processing**: Multiple plants can be harvested in a single operation\n- **Compliance**: All operations logged for regulatory compliance requirements\n- **Immediate Effect**: Status changes apply immediately to all specified plants\n\n**Common Use Cases:**\n- Initiate harvest operations for mature cannabis plants ready for processing\n- Record harvest timing and initial weight measurements for yield tracking\n- Maintain compliance with cannabis cultivation and harvest regulations\n- Support cultivation workflow transitions from growing to processing phases\n- Track harvest operations for operational efficiency and planning\n\n**Performance & Limits:**\n- Rate limited to 300 requests per minute for cultivation workflow protection\n- Bulk operation optimized for multiple plant processing\n- Immediate status updates and tracking system integration\n- Efficient for large-scale cultivation harvest operations\n\n**Related Endpoints:**\n- `GET /plant` - Retrieve plant records and current status\n- `POST /harvest` - Create harvest records for tracking and compliance\n- `GET /harvest` - Monitor harvest progress and completion status\n- Cultivation and inventory management endpoints for complete workflow\n\n**Important Notes:**\n- **Status Requirements**: Plants must be in Active status to be harvested\n- **Compliance Critical**: Harvest operations are required for cannabis regulatory compliance\n- **Weight Tracking**: Wet weight measurements support yield tracking and compliance\n- **Rate Limiting**: 300 requests per minute limit for cultivation workflow stability\n- **Immediate Processing**: Status changes are immediate and irreversible through this endpoint", + "operationId": "PlantHarvestPost", + "requestBody": { + "description": "Plant harvest request with plant identifiers and optional weight data - HarvestPlantRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/HarvestPlantRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HarvestPlantRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HarvestPlantRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/HarvestPlantRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Plants successfully moved to harvest status" + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/move": { + "post": { + "tags": ["Plant"], + "summary": "Move Plants", + "description": "**Purpose:** Move cannabis plants to a different room or cultivation area within the same facility for cultivation workflow management and compliance tracking.\n\n**Request Requirements:**\n- \"CultivationWrite\" role authorization required for plant movement operations\n- `MovePlantRequest` object in request body with plant IDs and target room information\n- Content-Type: application/json\n- All specified plants must be accessible to your location and in moveable status\n- Target room must be within the same facility (location)\n\n**Response Data:**\n- Response format: No response body (void)\n- Returns success confirmation (HTTP 200) upon successful plant movement\n- No response body content (void return)\n- Plants are moved to new room immediately\n- Changes are reflected immediately in plant location tracking\n\n**Request Body Fields:**\n- `PlantIds`: Array of LeafLogix plant IDs to move (required)\n- `RoomId`: Target room ID within the same facility (required)\n- `TableId`: Optional table assignment within the target room\n\n**Movement Operation Behavior:**\n- **Location Validation**: Target room must belong to the same facility\n- **Bulk Processing**: Multiple plants can be moved in a single operation\n- **Stage Updates**: If target room has cultivation stage, plants automatically update to that stage\n- **Compliance**: All movement operations logged for regulatory compliance requirements\n- **Integration**: Movement synchronized with external cultivation systems when configured\n\n**Common Use Cases:**\n- Move plants between cultivation rooms as they progress through growth stages\n- Relocate plants for environmental optimization and cultivation management\n- Transfer plants to harvest preparation areas when ready for processing\n- Support cultivation workflow automation and plant lifecycle management\n- Maintain compliance with cannabis cultivation and tracking regulations\n\n**Performance & Limits:**\n- Bulk operation optimized for multiple plant processing\n- Immediate location updates and tracking system integration\n- Efficient for large-scale cultivation facility operations\n- Location validation prevents cross-facility security violations\n\n**Related Endpoints:**\n- `GET /plant` - Retrieve current plant locations and status\n- `POST /plant/change-phase` - Update growth phases when moving between rooms\n- `GET /room` - List available rooms for plant movement planning\n- Cultivation management endpoints for complete workflow\n\n**Important Notes:**\n- **Facility Restriction**: Plants cannot be moved to rooms in different facilities\n- **Compliance Critical**: Plant movements are required for cannabis regulatory compliance\n- **Stage Automation**: Room-specific cultivation stages applied automatically when configured\n- **Immediate Processing**: Location changes are immediate and tracked for audit purposes\n- **Integration**: Movement synchronized with external cultivation and compliance systems", + "operationId": "PlantMovePost", + "requestBody": { + "description": "Plant movement request with plant IDs and target room information - see `MovePlantRequest` model for complete field documentation", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/MovePlantRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/MovePlantRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/MovePlantRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/MovePlantRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Plants successfully moved to target room" + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)" + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/change-phase": { + "post": { + "tags": ["Plant"], + "summary": "Change Plants Growth Phase", + "description": "**Purpose:** Update the cultivation growth phase of cannabis plants to track their development stage and optimize cultivation management.\n\n**Request Requirements:**\n- \"CultivationWrite\" role authorization required for plant growth phase operations\n- `ChangeGrowthPhaseRequest` object in request body with plant IDs and growth phase information\n- Content-Type: application/json\n- All specified plants must be accessible to your location and in valid status for phase changes\n- Growth phase must be one of the valid phase values\n\n**Response Data:**\n- Response format: No response body (void)\n- Returns success confirmation (HTTP 200) upon successful phase change\n- No response body content (void return)\n- Plants are updated to new growth phase immediately\n- Changes are reflected immediately in plant cultivation tracking\n\n**Request Body Fields:**\n- `PlantIds`: Array of LeafLogix plant IDs to update (required)\n- `GrowthPhase`: Target cultivation phase - must be one of: `Vegetative`, `Propagation`, `Flowering` (required)\n- `PhaseStartDate`: Date when new phase begins - defaults to current UTC time if omitted (optional)\n\n**Growth Phase Values:**\n- **Propagation**: Initial plant development and cloning phase\n- **Vegetative**: Active vegetative growth before flowering initiation\n- **Flowering**: Reproductive growth phase leading to harvest\n\n**Phase Change Operation Behavior:**\n- **Phase Validation**: Growth phase value validated against allowed phases\n- **Bulk Processing**: Multiple plants can be updated in a single operation\n- **Date Management**: Phase start date defaults to current time if not specified\n- **Compliance**: All phase changes logged for regulatory compliance requirements\n- **Integration**: Phase updates synchronized with external cultivation systems when configured\n\n**Common Use Cases:**\n- Transition plants from vegetative to flowering phase for harvest timing\n- Update plant phases during cultivation workflow automation\n- Maintain accurate cultivation records for compliance reporting\n- Support cultivation planning and scheduling optimization\n- Synchronize growth phases with environmental control systems\n\n**Performance & Limits:**\n- Bulk operation optimized for multiple plant processing\n- Immediate phase updates and tracking system integration\n- Efficient for large-scale cultivation facility operations\n- Phase validation prevents invalid cultivation state transitions\n\n**Related Endpoints:**\n- `GET /plant` - Retrieve current plant phases and cultivation status\n- `POST /plant/move` - Move plants between rooms optimized for different phases\n- `POST /plant/harvest` - Harvest plants when flowering phase is complete\n- Cultivation management endpoints for complete workflow\n\n**Important Notes:**\n- **Phase Validation**: Only `Vegetative`, `Propagation`, and `Flowering` phases are accepted\n- **Compliance Critical**: Phase tracking is required for cannabis regulatory compliance\n- **Date Tracking**: Phase start dates support cultivation timeline management\n- **Immediate Processing**: Phase changes are immediate and tracked for audit purposes\n- **Integration**: Phase updates synchronized with external cultivation and compliance systems", + "operationId": "PlantChange-phasePost", + "requestBody": { + "description": "Growth phase change request with plant IDs and target phase information - see `ChangeGrowthPhaseRequest` model for complete field documentation", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/ChangeGrowthPhaseRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeGrowthPhaseRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ChangeGrowthPhaseRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ChangeGrowthPhaseRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Plants successfully updated to new growth phase" + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)" + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/retire": { + "post": { + "tags": ["Plant"], + "summary": "Retire Plants", + "description": "**Purpose:** Permanently retire cannabis plants from cultivation due to various reasons such as disease, damage, or end-of-life for compliance tracking and waste management.\n\n**Request Requirements:**\n- \"CultivationWrite\" role authorization required for plant retirement operations\n- `RetirePlantRequest` object in request body with plant IDs and retirement details\n- Content-Type: application/json\n- Rate limited to 300 requests per minute\n- All specified plants must be accessible to your location and in retirable status\n- Either `ReasonId` or `ReasonCode` must be provided for retirement justification\n\n**Response Data:**\n- Response format: No response body (void)\n- Returns success confirmation (HTTP 200) upon successful plant retirement\n- No response body content (void return)\n- Plants are permanently retired from cultivation immediately\n- Changes are reflected immediately in plant status and compliance tracking\n\n**Request Body Fields:**\n- `PlantIds`: Array of LeafLogix plant IDs to retire (required)\n- `ReasonId`: Numeric reason ID for retirement - use if known (optional if ReasonCode provided)\n- `ReasonCode`: String reason code for retirement - use if ReasonId unknown (optional if ReasonId provided)\n- `RoomId`: Room where retirement occurs for waste tracking (required)\n- `WasteType`: Type of waste generated from retirement (optional)\n- `WasteWeight`: Weight of waste material in specified units (optional)\n- `PlantWeight`: Weight of plant material being retired (optional)\n- `WasteDate`: Date of waste generation for compliance tracking (optional)\n- Additional waste tracking and compliance fields\n\n**Reason Code Management:**\n- **ReasonId Priority**: If both ReasonId and ReasonCode provided, ReasonId takes precedence\n- **Code Lookup**: ReasonCode automatically looked up to find corresponding ReasonId\n- **Validation**: Invalid ReasonId or ReasonCode will result in 400 Bad Request response\n- **Flexibility**: Use ReasonCode when integrating without pre-knowledge of reason IDs\n\n**Retirement Operation Behavior:**\n- **Permanent Action**: Plant retirement is irreversible once completed\n- **Bulk Processing**: Multiple plants can be retired in a single operation\n- **Waste Tracking**: Optional waste weight and material tracking for compliance\n- **Compliance**: All retirement operations logged for regulatory compliance requirements\n- **Integration**: Retirement synchronized with external cultivation and waste tracking systems\n\n**Common Use Cases:**\n- Retire diseased or damaged plants to prevent contamination spread\n- Remove plants that have reached end-of-life or failed quality standards\n- Comply with regulatory requirements for plant destruction documentation\n- Manage cultivation space by removing non-productive plants\n- Support waste tracking and disposal compliance reporting\n\n**Performance & Limits:**\n- Rate limited to 300 requests per minute for cultivation workflow protection\n- Bulk operation optimized for multiple plant processing\n- Immediate retirement status updates and tracking system integration\n- Efficient for large-scale cultivation facility operations\n\n**Related Endpoints:**\n- `GET /plant` - Retrieve current plant status before retirement\n- `GET /plant/get-reason-codes` - List available retirement reason codes\n- `POST /waste` - Create waste records for retired plant material\n- Cultivation and compliance management endpoints\n\n**Important Notes:**\n- **Irreversible Action**: Plant retirement cannot be undone once completed\n- **Reason Required**: Either ReasonId or ReasonCode must be provided for compliance\n- **Compliance Critical**: Retirement tracking is required for cannabis regulatory compliance\n- **Rate Limiting**: 300 requests per minute limit for cultivation workflow stability\n- **Waste Integration**: Retirement can generate waste records for disposal tracking", + "operationId": "PlantRetirePost", + "requestBody": { + "description": "Plant retirement request with plant IDs, reason codes, and waste tracking details - see `RetirePlantRequest` model for complete field documentation", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/RetirePlantRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/RetirePlantRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/RetirePlantRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/RetirePlantRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Plants successfully retired from cultivation" + }, + "400": { + "description": "Bad Request - Invalid reason ID/code or validation errors", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/get-reason-codes": { + "get": { + "tags": ["Plant"], + "summary": "Get Plant Reason Codes", + "description": "**Purpose:** Retrieve the list of valid reason codes for cannabis plant retirement operations to support compliance documentation and proper retirement categorization.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for plant data access\n- No query parameters or request body needed\n\n**Response Data:**\n- Response format: `[string, string, ...]`\n- Returns array of string reason codes for plant retirement\n- Array typically contains 5-20 reason codes depending on organization configuration\n- Returns empty array `[]` if no reason codes configured (rare)\n- Reason codes are organization-specific and configurable by administrators\n- Results automatically filtered to authenticated organization\n\n**Common Reason Code Examples:**\n- Disease or pest infestation requiring plant destruction\n- Physical damage or environmental stress failures\n- Quality control failures or contamination issues\n- End-of-life or harvest completion scenarios\n- Regulatory compliance or audit requirements\n\n**Common Use Cases:**\n- Populate reason code dropdown lists in plant retirement forms\n- Validate reason codes before submitting plant retirement requests\n- Generate compliance reports showing retirement reasons and frequencies\n- Support cultivation management workflows with proper retirement categorization\n- Maintain audit trails for regulatory compliance and operational analysis\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Small dataset suitable for client-side caching\n- No pagination needed due to manageable reason code catalog sizes\n- Results filtered to organization-specific reason configurations\n\n**Related Endpoints:**\n- `POST /plant/retire` - Retire plants using these reason codes for compliance\n- `GET /plant` - Retrieve plant status before determining retirement reasons\n- Plant lifecycle and cultivation management endpoints\n\n**Important Notes:**\n- **Organization-Specific**: Reason codes vary by organization and compliance requirements\n- **Compliance Required**: Proper reason codes are essential for cannabis regulatory compliance\n- **Validation**: Use these codes to validate retirement requests before submission\n- **Reference Data**: Cache locally for performance in plant retirement workflows\n- **Administrative**: Reason codes are configured by system administrators", + "operationId": "PlantGet-reason-codesGet", + "responses": { + "200": { + "description": "Success - Returns array of reason code strings: `[string, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/assign-plants-to-group": { + "post": { + "tags": ["Plant"], + "summary": "Assign Plants to Group", + "description": "**Purpose:** Assign existing cannabis plants to a specific plant group for batch management and cultivation workflow organization using plant serial numbers.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for plant group management operations\n- `AssignPlantsToGroupRequest` object in request body with group name and plant serial numbers\n- Content-Type: application/json\n- All specified plant serial numbers must exist and be accessible to your location\n- Target plant group must exist within the facility\n\n**Response Data:**\n- Response format: No response body (void)\n- Returns success confirmation (HTTP 200) upon successful plant assignment\n- No response body content (void return)\n- Plants are assigned to target group immediately\n- Changes are reflected immediately in plant group organization and batch tracking\n\n**Request Body Fields:**\n- `PlantGroupName`: Name of target plant group for batch organization (required)\n- `PlantSerialNumbers`: Array of plant serial numbers to assign to the group (required)\n\n**Plant Group Assignment Behavior:**\n- **Batch Organization**: Plants assigned to groups for batch-based cultivation tracking\n- **Serial Number Lookup**: Plants identified by serial numbers for precise assignment\n- **Group Validation**: Target plant group must exist before assignment\n- **Bulk Processing**: Multiple plants can be assigned to the same group in a single operation\n- **Immediate Processing**: Group assignments are immediate and tracked for compliance\n\n**Validation Rules:**\n- **Plant Existence**: All serial numbers must correspond to existing plants\n- **Location Access**: Plants must be accessible to the authenticated location\n- **Group Existence**: Target plant group must exist within the facility\n- **Serial Number Format**: Serial numbers must match existing plant tracking identifiers\n\n**Common Use Cases:**\n- Reorganize plants into batch groups for cultivation workflow management\n- Assign newly created plants to existing cultivation batches\n- Support batch-based harvest planning and cultivation scheduling\n- Maintain proper plant group organization for compliance reporting\n- Facilitate cultivation management and operational efficiency\n\n**Performance & Limits:**\n- Bulk operation optimized for multiple plant assignment\n- Immediate group assignment and tracking system integration\n- Efficient for cultivation workflow organization and batch management\n- Serial number validation ensures accurate plant identification\n\n**Related Endpoints:**\n- `GET /plant` - Retrieve current plant group assignments and status\n- `POST /plant` - Create new plants that can be assigned to groups\n- Plant group and cultivation management endpoints for complete workflow\n\n**Important Notes:**\n- **Batch Management**: Plant groups enable batch-based cultivation tracking and compliance\n- **Serial Number Precision**: Use exact serial numbers for accurate plant identification\n- **Compliance Support**: Proper group organization supports regulatory compliance requirements\n- **Immediate Processing**: Group assignments are immediate and tracked for audit purposes\n- **Workflow Integration**: Supports cultivation management and harvest planning workflows", + "operationId": "PlantAssign-plants-to-groupPost", + "requestBody": { + "description": "Plant group assignment request with group name and plant serial numbers - see `AssignPlantsToGroupRequest` model for complete field documentation", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/AssignPlantsToGroupRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssignPlantsToGroupRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AssignPlantsToGroupRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/AssignPlantsToGroupRequest" + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success - Plants successfully assigned to target group" + }, + "400": { + "description": "Bad Request - Validation errors or invalid plant serial numbers", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/nonsts/update": { + "post": { + "tags": ["PlantNonsts"], + "summary": "Update Existing Plants (Non-State Tracking)", + "description": "**Purpose:** Update existing plant records with cultivation data without reporting to state traceability systems for internal plant management.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for plant data modification\n- `UpdatePlantsRequest` object in request body with plant update details\n- Content-Type: application/json\n- Valid PlantId required for each plant to be updated\n- Feature flag \"rollout.trym-integration\" must be enabled\n\n**Response Data:**\n- Returns single `SuccessResult` object (not array) with operation confirmation\n- Includes success message confirming plants were updated\n- Operation status and any relevant update information\n\n**Sparse Update Behavior:**\n- **Null/Empty/Omitted Fields**: Will NOT have their data updated (preserves existing values)\n- **Provided Fields**: Only fields with values in the request will be updated\n- **Field Independence**: Each field can be updated independently without affecting others\n- **Safe Updates**: Omitted fields maintain their current database values\n\n**Non-State Tracking (NONSTS) Behavior:**\n- **Internal Only**: Updates are for internal cultivation tracking only\n- **No External Reporting**: Changes are NOT reported to state traceability systems\n- **Cultivation Focus**: Designed for internal plant management and cultivation workflows\n- **Compliance Safe**: Does not interfere with official state tracking requirements\n\n**Common Use Cases:**\n- Update internal plant cultivation notes and observations\n- Modify plant growth stage information for internal tracking\n- Update plant location within cultivation facility\n- Record internal plant health and development data\n- Maintain cultivation workflow information without state system updates\n\n**Performance & Limits:**\n- Batch plant updates for efficient cultivation management\n- Validation performed before any changes to ensure data integrity\n- Changes reflected immediately in internal cultivation systems\n- Optimized for cultivation facility management workflows\n\n**Related Endpoints:**\n- `GET /plant` - Retrieve current plant data before updates\n- `POST /plant/nonsts` - Create new plants for internal tracking\n- `POST /plant/harvest` - Official plant harvest operations (state tracked)\n\n**Important Notes:**\n- **Feature Gated**: Requires \"rollout.trym-integration\" feature flag to be enabled\n- **Internal Tracking**: Updates are for internal cultivation management only\n- **State Compliance**: Does not affect official state traceability system records\n- **Validation Required**: Plant IDs must exist and be valid for the location\n- **Cultivation Focus**: Designed specifically for cultivation facility workflows", + "operationId": "PlantNonstsUpdatePost", + "requestBody": { + "description": "Plant update request with PlantId and field updates - UpdatePlantsRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/UpdatePlantsRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePlantsRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePlantsRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdatePlantsRequest" + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResult" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/nonsts/batch/immatureplants": { + "post": { + "tags": ["PlantNonsts"], + "summary": "Create Immature Plant Batch (Non-State Tracking)", + "description": "**Purpose:** Create a batch of immature plants for internal cultivation tracking without reporting to state traceability systems.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for plant creation\n- `PostImmatureBatchRequest` object in request body with batch details\n- Content-Type: application/json\n- Valid plant data for each immature plant in the batch\n- Feature flag \"rollout.trym-integration\" must be enabled\n\n**Response Data:**\n- Returns single `ApiResult` object (not array) with creation results\n- Includes array of created plant IDs for tracking and reference\n- Batch creation status and success confirmation\n- Plant ID assignments for newly created immature plants\n\n**Batch Creation Process:**\n- **Multiple Plants**: Creates multiple immature plants in a single operation\n- **ID Assignment**: Each plant receives a unique PlantId for future operations\n- **Validation**: All plant data validated before batch creation\n- **Atomic Operation**: Batch succeeds or fails as a complete unit\n\n**Non-State Tracking (NONSTS) Behavior:**\n- **Internal Only**: Plant creation for internal cultivation tracking only\n- **No External Reporting**: Plant creation NOT transmitted to state traceability systems\n- **Cultivation Focus**: Designed for internal plant management and cultivation workflows\n- **Compliance Safe**: Does not interfere with official state tracking requirements\n\n**Immature Plant Characteristics:**\n- **Growth Stage**: Plants in early vegetative or seedling stage\n- **Tracking Ready**: Created with unique identifiers for cultivation tracking\n- **Development Phase**: Pre-flowering plants requiring cultivation management\n- **Internal Records**: Maintained in internal cultivation systems only\n\n**Common Use Cases:**\n- Create batches of seedlings for internal cultivation tracking\n- Initialize plant records for new cultivation cycles\n- Set up immature plant inventory for facility management\n- Start cultivation workflows without state system integration\n- Manage internal plant genetics and breeding programs\n\n**Performance & Limits:**\n- Batch processing for efficient plant creation workflows\n- Validation performed before any plant creation\n- Changes reflected immediately in internal cultivation systems\n- Optimized for cultivation facility startup and expansion workflows\n\n**Related Endpoints:**\n- `POST /plant/nonsts/update` - Update created plants with cultivation data\n- `GET /plant` - Retrieve created plant information\n- `POST /plant/harvest` - Official plant harvest operations (state tracked)\n\n**Important Notes:**\n- **Feature Gated**: Requires \"rollout.trym-integration\" feature flag to be enabled\n- **Plant IDs Returned**: Save returned plant IDs for future plant management operations\n- **Internal Tracking**: Plants created for internal cultivation management only\n- **State Compliance**: Does not affect official state traceability system records\n- **Batch Efficiency**: Creates multiple plants efficiently in single operation", + "operationId": "PlantNonstsBatchImmatureplantsPost", + "requestBody": { + "description": "Immature plant batch request with plant details - PostImmatureBatchRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/PostImmatureBatchRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostImmatureBatchRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PostImmatureBatchRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/PostImmatureBatchRequest" + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateImmaturePlantBatchResponseApiResult" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/nonsts/batch/convert/immatureplants": { + "post": { + "tags": ["PlantNonsts"], + "summary": "Convert Immature Plant Batch to Mature (Non-State Tracking)", + "description": "**Purpose:** Convert immature plant batches to mature plant status for internal cultivation tracking without reporting to state traceability systems.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for plant conversion\n- `ConvertImmatureBatchRequest` object in request body with conversion details\n- Content-Type: application/json\n- Valid immature batch data for conversion to mature plants\n- Feature flag \"rollout.trym-integration\" must be enabled\n\n**Response Data:**\n- Returns single `ApiResult` object (not array) with conversion results\n- Includes array of converted plant IDs for tracking and reference\n- Plant conversion status and success confirmation\n- Mature plant ID assignments for newly converted plants\n\n**Plant Conversion Process:**\n- **Status Transition**: Converts immature plants to mature plant status\n- **ID Retention**: Existing plant IDs maintained through conversion process\n- **Validation**: All conversion data validated before processing\n- **Batch Processing**: Multiple immature plants converted in single operation\n\n**Non-State Tracking (NONSTS) Behavior:**\n- **Internal Only**: Plant creation for internal cultivation tracking only\n- **No External Reporting**: Plant conversion NOT transmitted to state traceability systems\n- **Cultivation Focus**: Designed for internal plant management and cultivation workflows\n- **Compliance Safe**: Does not interfere with official state tracking requirements\n\n**Maturity Transition:**\n- **Growth Stage**: Immature to mature plant status transition\n- **Cultivation Ready**: Mature plants ready for flowering phase management\n- **Tracking Continuity**: Maintains plant tracking through maturity transition\n- **Workflow Integration**: Supports cultivation facility growth phase workflows\n\n**Common Use Cases:**\n- Convert vegetative plants to mature flowering status\n- Transition immature batches to mature cultivation phases\n- Progress plants through cultivation development stages\n- Support internal cultivation workflow maturity management\n- Manage plant lifecycle transitions without state system integration\n\n**Performance & Limits:**\n- Efficient plant conversion for cultivation management\n- Validation performed before any plant conversion\n- Changes reflected immediately in internal cultivation systems\n- Optimized for cultivation facility maturity workflows\n\n**Related Endpoints:**\n- `POST /plant/nonsts/update` - Update converted plants with cultivation data\n- `GET /plant` - Retrieve converted plant information\n- `POST /plant/harvest` - Official plant harvest operations (state tracked)\n\n**Important Notes:**\n- **Feature Gated**: Requires \"rollout.trym-integration\" feature flag to be enabled\n- **Plant IDs Returned**: Save returned plant IDs for future plant management operations\n- **Internal Tracking**: Plants converted for internal cultivation management only\n- **State Compliance**: Does not affect official state traceability system records\n- **Cultivation Ready**: Mature plants ready for internal cultivation tracking workflows", + "operationId": "PlantNonstsBatchConvertImmatureplantsPost", + "requestBody": { + "description": "Immature batch conversion request with conversion details - ConvertImmatureBatchRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/ConvertImmatureBatchRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConvertImmatureBatchRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ConvertImmatureBatchRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ConvertImmatureBatchRequest" + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConvertImmaturePlantResponseApiResult" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/nonsts/batch/matureplants": { + "post": { + "tags": ["PlantNonsts"], + "summary": "Create Mature Plant Batch (Non-State Tracking)", + "description": "**Purpose:** Create a batch of mature plants ready for flowering phase cultivation tracking without reporting to state traceability systems.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for mature plant creation\n- `CreateMatureBatchRequest` object in request body with mature plant batch details\n- Content-Type: application/json\n- Valid mature plant data for each plant in the batch\n- Feature flag \"rollout.trym-integration\" must be enabled\n\n**Response Data:**\n- Returns single `ApiResult` object (not array) with creation results\n- Includes array of created plant IDs for tracking and reference\n- Batch creation status and success confirmation\n- Plant ID assignments for newly created mature plants\n\n**Mature Plant Batch Creation:**\n- **Multiple Plants**: Creates multiple mature plants in a single operation\n- **Flowering Ready**: Plants created at mature stage ready for flowering phase\n- **ID Assignment**: Each plant receives a unique PlantId for future operations\n- **Validation**: All plant data validated before batch creation\n- **Atomic Operation**: Batch succeeds or fails as a complete unit\n\n**Non-State Tracking (NONSTS) Behavior:**\n- **Internal Only**: Plant creation for internal cultivation tracking only\n- **No External Reporting**: Plant creation NOT transmitted to state traceability systems\n- **Cultivation Focus**: Designed for internal mature plant management and flowering workflows\n- **Compliance Safe**: Does not interfere with official state tracking requirements\n\n**Mature Plant Characteristics:**\n- **Growth Stage**: Plants ready for flowering phase cultivation\n- **Cultivation Ready**: Created with unique identifiers for flowering management\n- **Production Phase**: Mature plants prepared for harvest cultivation workflows\n- **Internal Records**: Maintained in internal cultivation systems only\n\n**Common Use Cases:**\n- Create batches of mature plants for flowering room management\n- Initialize mature plant inventory for production cycles\n- Set up flowering phase plant tracking for facility management\n- Start mature cultivation workflows without state system integration\n- Manage internal mature plant genetics and production programs\n\n**Performance & Limits:**\n- Batch processing for efficient mature plant creation workflows\n- Validation performed before any plant creation\n- Changes reflected immediately in internal cultivation systems\n- Optimized for cultivation facility flowering phase workflows\n\n**Related Endpoints:**\n- `POST /plant/nonsts/update` - Update created mature plants with cultivation data\n- `POST /plant/nonsts/batch/immatureplants` - Create immature plant batches\n- `POST /plant/nonsts/batch/convert/immatureplants` - Convert immature to mature plants\n- `GET /plant` - Retrieve created mature plant information\n- `POST /plant/harvest` - Official plant harvest operations (state tracked)\n\n**Important Notes:**\n- **Feature Gated**: Requires \"rollout.trym-integration\" feature flag to be enabled\n- **Plant IDs Returned**: Save returned plant IDs for future mature plant management operations\n- **Internal Tracking**: Plants created for internal cultivation management only\n- **State Compliance**: Does not affect official state traceability system records\n- **Flowering Ready**: Mature plants ready for flowering phase cultivation workflows\n- **Batch Efficiency**: Creates multiple mature plants efficiently in single operation", + "operationId": "PlantNonstsBatchMatureplantsPost", + "requestBody": { + "description": "Mature plant batch request with plant details - CreateMatureBatchRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/CreateMatureBatchRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMatureBatchRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CreateMatureBatchRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CreateMatureBatchRequest" + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success - Returns ApiResult with created plant IDs: `{ \"data\": { \"createdPlants\": [plantId1, plantId2, ...] }, \"message\": \"Successfully created mature plants from batches.\", \"success\": true }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMaturePlantsResponseApiResult" + } + } + } + }, + "400": { + "description": "Bad Request - Validation failed or invalid request data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for mature plant creation or feature flag disabled" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/plant/nonsts/retag": { + "post": { + "tags": ["PlantNonsts"], + "summary": "Retag Plant or Clone (Non-State Tracking)", + "description": "**Purpose:** Update plant or clone tag identification for internal cultivation tracking without reporting to state traceability systems.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for plant retagging\n- `RetagPlantRequest` object in request body with retagging details\n- Content-Type: application/json\n- Valid existing plant identification and new tag information\n- Feature flag \"rollout.trym-integration\" must be enabled\n\n**Response Data:**\n- Returns HTTP 200 with no response body on success\n- No data returned - operation confirmation only\n- Operation status confirms successful retagging completion\n\n**Retagging Process:**\n- **Tag Replacement**: Updates existing plant tag with new identification\n- **Plant Identification**: Maintains plant record while updating tag reference\n- **Validation**: Ensures new tag is unique and valid for the facility\n- **Immediate Update**: Tag change reflected immediately in cultivation systems\n\n**Non-State Tracking (NONSTS) Behavior:**\n- **Internal Only**: Tag updates for internal cultivation tracking only\n- **No External Reporting**: Retagging NOT transmitted to state traceability systems\n- **Cultivation Focus**: Designed for internal plant management and tag organization\n- **Compliance Safe**: Does not interfere with official state tracking requirements\n\n**Retagging Applications:**\n- **Tag Damage**: Replace damaged or unreadable plant tags\n- **Organization**: Update tag numbering for facility organization\n- **Growth Stage**: Retag plants when moving between cultivation areas\n- **Clone Management**: Update clone tags for genetic tracking\n\n**Common Use Cases:**\n- Replace damaged plant tags for continued tracking\n- Update plant identification for facility reorganization\n- Retag clones for genetic lineage management\n- Maintain plant tag consistency across cultivation areas\n- Support internal cultivation workflow tag requirements\n\n**Performance & Limits:**\n- Single plant retagging operation for targeted tag management\n- Validation performed before any tag changes\n- Changes reflected immediately in internal cultivation systems\n- Optimized for cultivation facility tag management workflows\n\n**Related Endpoints:**\n- `POST /plant/nonsts/update` - Update other plant data beyond tags\n- `GET /plant` - Retrieve plant information with current tags\n- `POST /plant/nonsts` - Create new plants with initial tags\n\n**Important Notes:**\n- **Feature Gated**: Requires \"rollout.trym-integration\" feature flag to be enabled\n- **Tag Uniqueness**: New tag must be unique within the cultivation facility\n- **Internal Tracking**: Tag changes for internal cultivation management only\n- **State Compliance**: Does not affect official state traceability system records\n- **Cultivation Continuity**: Maintains plant tracking continuity with updated identification", + "operationId": "PlantNonstsRetagPost", + "requestBody": { + "description": "Plant retagging request with plant and new tag details - RetagPlantRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/RetagPlantRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/RetagPlantRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/RetagPlantRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/RetagPlantRequest" + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/nonsts/batch/retire": { + "post": { + "tags": ["PlantNonsts"], + "summary": "Retire Immature Plant Batch (Non-State Tracking)", + "description": "**Purpose:** Retire batches of immature plants or clones from active cultivation for internal tracking without reporting to state traceability systems.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for plant retirement\n- `RetireImmaturePlantsRequest` object in request body with retirement details\n- Content-Type: application/json\n- Valid immature plant or clone identification for retirement\n- Plants must be in immature stage for this operation\n\n**Response Data:**\n- Returns HTTP 200 with no response body on success\n- No data returned - operation confirmation only\n- Status confirmation indicates successful plant retirement completion\n\n**Plant Retirement Process:**\n- **Batch Retirement**: Retires multiple immature plants or clones in single operation\n- **Status Change**: Updates plant status to retired/inactive in cultivation systems\n- **Validation**: Ensures plants are valid and in immature stage before retirement\n- **Immediate Effect**: Retirement status applied immediately to cultivation records\n\n**Non-State Tracking (NONSTS) Behavior:**\n- **Internal Only**: Plant retirement for internal cultivation tracking only\n- **No External Reporting**: Retirement actions NOT transmitted to state traceability systems\n- **Cultivation Focus**: Designed for internal plant lifecycle management\n- **Compliance Safe**: Does not interfere with official state tracking requirements\n\n**Immature Plant Retirement Reasons:**\n- **Quality Control**: Remove plants that don't meet cultivation standards\n- **Space Management**: Retire excess plants for cultivation area optimization\n- **Health Issues**: Remove unhealthy or diseased plants from active cultivation\n- **Selection Process**: Retire plants not selected for continued cultivation\n- **Facility Management**: Clear immature plants for cultivation workflow changes\n\n**Common Use Cases:**\n- Retire poor-performing immature plants or clones\n- Remove excess immature plants to optimize cultivation space\n- Clear unhealthy plants from cultivation areas\n- Support cultivation selection and quality control processes\n- Manage immature plant inventory for facility efficiency\n\n**Performance & Limits:**\n- Batch processing for efficient plant retirement workflows\n- Validation performed before any retirement actions\n- Changes reflected immediately in internal cultivation systems\n- Optimized for cultivation facility plant lifecycle management\n\n**Related Endpoints:**\n- `POST /plant/nonsts/batch/immatureplants` - Create immature plant batches\n- `POST /plant/nonsts/update` - Update immature plants before retirement\n- `GET /plant` - Retrieve plant information including retirement status\n- `POST /plant/nonsts/batch/convert/immatureplants` - Convert immature to mature plants\n\n**Important Notes:**\n- **Immature Only**: This endpoint specifically handles immature plants and clones\n- **Batch Operation**: Can retire multiple plants efficiently in single request\n- **Internal Tracking**: Retirement for internal cultivation management only\n- **State Compliance**: Does not affect official state traceability system records\n- **Irreversible**: Plant retirement action cannot be easily undone\n- **Validation Required**: Plants must exist and be in immature stage for retirement", + "operationId": "PlantNonstsBatchRetirePost", + "requestBody": { + "description": "Immature plant retirement request with plant details - RetireImmaturePlantsRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/RetireImmaturePlantsRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/RetireImmaturePlantsRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/RetireImmaturePlantsRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/RetireImmaturePlantsRequest" + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success - No response body, operation completed successfully" + }, + "400": { + "description": "Bad Request - Validation failed or invalid plant data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for plant retirement" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/plant/nonsts/batch/finish-harvest": { + "post": { + "tags": ["PlantNonsts"], + "summary": "Finish or Unfinish Harvest Batch (Non-State Tracking)", + "description": "**Purpose:** Mark harvest batches as finished or unfinished for internal cultivation tracking without reporting to state traceability systems.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for harvest status management\n- `FinishHarvestBatchRequest` object in request body with harvest batch details\n- Content-Type: application/json\n- Valid harvest batch identification and finish/unfinish action\n- Feature flag \"rollout.trym-integration\" must be enabled\n\n**Response Data:**\n- Returns HTTP 200 with no response body on success\n- No data returned - operation confirmation only\n- Status confirmation indicates successful harvest batch update\n\n**Finish/Unfinish Operations:**\n- **FINISH**: Marks harvest batch as completed and ready for processing\n- **UNFINISH**: Reverts harvest batch to in-progress status for continued work\n- **Status Toggle**: Can switch between finished and unfinished states as needed\n- **Batch Management**: Affects entire harvest batch status uniformly\n\n**Non-State Tracking (NONSTS) Behavior:**\n- **Internal Only**: Harvest status updates for internal cultivation tracking only\n- **No External Reporting**: Status changes NOT transmitted to state traceability systems\n- **Cultivation Focus**: Designed for internal harvest workflow management\n- **Compliance Safe**: Does not interfere with official state tracking requirements\n\n**Harvest Batch Status Management:**\n- **Workflow Control**: Controls harvest batch progression through processing stages\n- **Quality Gates**: Finish status indicates batch readiness for next processing steps\n- **Reversible Actions**: Unfinish allows returning to active harvest work\n- **Batch Integrity**: Maintains harvest batch data consistency\n\n**Common Use Cases:**\n- Mark harvest batches as complete when cultivation work is finished\n- Unfinish harvest batches to allow additional cultivation work\n- Control harvest workflow progression through processing stages\n- Manage harvest batch status for internal tracking and reporting\n- Support cultivation facility harvest workflow requirements\n\n**Performance & Limits:**\n- Single batch operation for targeted harvest status management\n- Immediate status update reflected in cultivation systems\n- Optimized for harvest workflow management and status tracking\n- Validation performed before any status changes\n\n**Related Endpoints:**\n- `GET /harvest` - Retrieve harvest batch information and current status\n- `POST /plant/harvest` - Official plant harvest operations (state tracked)\n- `POST /plant/nonsts/update` - Update plant data related to harvest\n\n**Important Notes:**\n- **Feature Gated**: Requires \"rollout.trym-integration\" feature flag to be enabled\n- **Reversible Operation**: Finish and unfinish actions can be toggled as needed\n- **Internal Tracking**: Status changes for internal cultivation management only\n- **State Compliance**: Does not affect official state traceability system records\n- **Workflow Control**: Critical for managing internal harvest processing workflows", + "operationId": "PlantNonstsBatchFinish-harvestPost", + "requestBody": { + "description": "Harvest batch finish/unfinish request with batch details - FinishHarvestBatchRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FinishOrUnfinishBatchDetails" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FinishOrUnfinishBatchDetails" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FinishOrUnfinishBatchDetails" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FinishOrUnfinishBatchDetails" + } + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/plant/nonsts/split": { + "post": { + "tags": ["PlantNonsts"], + "summary": "Split Immature Plant Batch (Non-State Tracking)", + "description": "**Purpose:** Split immature plant or clone batches into two separate batches for internal cultivation management without reporting to state traceability systems.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for batch splitting\n- `SplitImmaturePlantsRequest` object in request body with split details\n- Content-Type: application/json\n- Valid immature batch identification and split configuration\n- Source batch must contain multiple plants to enable splitting\n\n**Response Data:**\n- Returns single `ApiResult` object (not array) with split results\n- Includes details of both resulting batches after split operation\n- Batch split status and success confirmation\n- Plant distribution information for the two new batches\n\n**Batch Splitting Process:**\n- **Source Division**: Divides single immature batch into two separate batches\n- **Plant Distribution**: Distributes plants between original and new batch\n- **Batch Integrity**: Maintains plant tracking continuity through split operation\n- **Validation**: Ensures source batch is valid and contains sufficient plants for splitting\n- **Atomic Operation**: Split succeeds or fails as complete operation\n\n**Non-State Tracking (NONSTS) Behavior:**\n- **Internal Only**: Batch splitting for internal cultivation tracking only\n- **No External Reporting**: Split operations NOT transmitted to state traceability systems\n- **Cultivation Focus**: Designed for internal batch management and cultivation workflows\n- **Compliance Safe**: Does not interfere with official state tracking requirements\n\n**Immature Batch Splitting Applications:**\n- **Facility Management**: Split large batches for different cultivation areas\n- **Growth Phase Management**: Separate plants based on development stage\n- **Quality Control**: Isolate high-performing plants from standard batches\n- **Genetic Management**: Separate clones for different breeding programs\n- **Space Optimization**: Distribute plants across multiple cultivation rooms\n\n**Common Use Cases:**\n- Split large immature plant batches for better facility management\n- Separate high-quality clones from standard cultivation batches\n- Distribute plants across different cultivation rooms or areas\n- Create specialized batches for different cultivation treatments\n- Support cultivation workflow organization and plant management\n\n**Performance & Limits:**\n- Single batch operation creating two resulting batches\n- Validation performed before any batch splitting\n- Changes reflected immediately in internal cultivation systems\n- Optimized for cultivation facility batch management workflows\n\n**Related Endpoints:**\n- `POST /plant/nonsts/batch/immatureplants` - Create original immature plant batches\n- `POST /plant/nonsts/update` - Update plants within split batches\n- `GET /plant` - Retrieve plant information for both resulting batches\n- `POST /plant/nonsts/batch/convert/immatureplants` - Convert split batches to mature\n\n**Important Notes:**\n- **Immature Only**: This endpoint specifically handles immature plant and clone batches\n- **Two-Batch Result**: Split operation always creates exactly two batches\n- **Plant Continuity**: All plants maintain their tracking through the split process\n- **Internal Tracking**: Split operations for internal cultivation management only\n- **State Compliance**: Does not affect official state traceability system records\n- **Batch Requirements**: Source batch must contain multiple plants to enable splitting", + "operationId": "PlantNonstsSplitPost", + "requestBody": { + "description": "Immature plant batch split request with batch and split details - SplitImmaturePlantsRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/SplitImmaturePlantsRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SplitImmaturePlantsRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SplitImmaturePlantsRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/SplitImmaturePlantsRequest" + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success - Returns ApiResult with split batch details: `{ \"data\": { \"originalBatch\": {...}, \"newBatch\": {...} }, \"message\": \"Successfully split immature batches of plants.\", \"success\": true }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SplitImmaturePlantResultApiResult" + } + } + } + }, + "400": { + "description": "Bad Request - Validation failed or invalid batch data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for batch splitting" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/plant/nonsts/batch": { + "post": { + "tags": ["PlantNonsts"], + "summary": "Update Plant Batch (Non-State Tracking)", + "description": "**Purpose:** Update plant batch information such as strain or location for internal cultivation tracking without reporting to state traceability systems.\n\n**Request Requirements:**\n- \"Inventory\" or \"Cultivation\" role authorization required for batch data modification\n- `UpdateBatchRequest` object in request body with batch update details\n- Content-Type: application/json\n- Valid batch identification and field updates\n- Feature flag \"rollout.trym-integration\" must be enabled\n\n**Response Data:**\n- Returns HTTP 200 with no response body on success\n- No data returned - operation confirmation only\n- Status confirmation indicates successful batch update completion\n\n**Batch Update Capabilities:**\n- **Strain Updates**: Modify strain information for entire plant batch\n- **Location Updates**: Change cultivation location or room assignment for batch\n- **Batch Properties**: Update other batch-level cultivation characteristics\n- **Bulk Changes**: Apply updates to all plants within the specified batch\n\n**Sparse Update Behavior:**\n- **Selective Updates**: Only provided fields in the request will be updated\n- **Field Independence**: Each batch property can be updated independently\n- **Preservation**: Omitted fields maintain their current values\n- **Validation**: All provided updates validated before application\n\n**Non-State Tracking (NONSTS) Behavior:**\n- **Internal Only**: Batch updates for internal cultivation tracking only\n- **No External Reporting**: Changes NOT transmitted to state traceability systems\n- **Cultivation Focus**: Designed for internal batch management and cultivation workflows\n- **Compliance Safe**: Does not interfere with official state tracking requirements\n\n**Common Use Cases:**\n- Update strain information when batch genetics are reclassified\n- Move plant batches to different cultivation rooms or areas\n- Modify batch properties for improved cultivation tracking\n- Correct batch information for accurate facility management\n- Support cultivation workflow batch organization requirements\n\n**Performance & Limits:**\n- Single batch operation affecting all plants in the specified batch\n- Validation performed before any batch changes\n- Changes reflected immediately in internal cultivation systems\n- Optimized for cultivation facility batch management workflows\n\n**Related Endpoints:**\n- `POST /plant/nonsts/update` - Update individual plant data within batches\n- `GET /plant` - Retrieve current plant and batch information\n- `POST /plant/nonsts` - Create new plant batches with initial properties\n\n**Important Notes:**\n- **Feature Gated**: Requires \"rollout.trym-integration\" feature flag to be enabled\n- **Batch-Wide Impact**: Updates affect all plants within the specified batch\n- **Internal Tracking**: Changes for internal cultivation management only\n- **State Compliance**: Does not affect official state traceability system records\n- **Cultivation Efficiency**: Streamlines batch-level cultivation management operations", + "operationId": "PlantNonstsBatchPost", + "requestBody": { + "description": "Batch update request with batch identification and field updates - UpdateBatchRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/UpdateBatchRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBatchRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBatchRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdateBatchRequest" + } + } + }, + "x-bodyName": "request" + }, + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/preorder/submit": { + "post": { + "tags": ["PreOrder"], + "summary": "Create PreOrder", + "description": "**Purpose:** Create a new customer pre-order by submitting cart items with customer information and fulfillment details.\n\n**Request Requirements:**\n- \"PreOrder\" role authorization required for order creation\n- `CreatePreOrderRequest` object in request body with complete order details\n- Content-Type: application/json\n- Valid customer ID that exists in the system\n- **Idempotency Support**: Requires `ConsumerKey` header and `IdempotencyKey` field for duplicate prevention (see [Idempotency Documentation](/pages/idempotency.html))\n\n**Response Data:**\n- Returns `PreOrderResponse` object with assigned order ID and transaction ID\n- Order ID can be used for tracking and future order operations\n- Transaction ID links to the transaction for fulfillment tracking\n\n**Required Request Information:**\n- Valid CustomerId for the order recipient\n- Array of cart items with products, quantities, and any special instructions\n- Order source for tracking and reporting (Web, In-Store, Express)\n- Fulfillment details with pickup or delivery information and timing\n\n**Order Sources Available:**\n- Web: Online orders from e-commerce platforms\n- In-Store: Orders placed directly at dispensary location\n- Express: Expedited or curbside pickup orders\n- Note: Order Source is deprecated and will be replaced with more comprehensive tracking values\n\n**Delivery Time Windows:**\n- TimeWindowXXXDateUtc fields express desired delivery time windows\n- May be expanded to pickup orders in the future\n- Data exposed to locations with \"Delivery Management\" feature enabled\n\n**Redemptions Support:**\n- Third-party loyalty redemptions and LeafLogix discount codes supported\n- Valid types: SpringBig Rewards/Offers, Alpine IQ, LeafLogix Codes, Fyllo\n- Redemption ID should be discount code, reward ID, offer ID, or template ID\n\n**Common Use Cases:**\n- Process e-commerce orders from online platforms\n- Create pickup orders for customer convenience\n- Handle delivery orders with specified time windows\n- Apply loyalty rewards and promotional discounts\n- Enable customers to secure products before visiting store\n\n**Performance & Limits:**\n- Uses idempotency key to prevent duplicate order creation\n- Product validation ensures availability and purchase limits\n- Customer verification confirms validity for location\n- Compliance checking for local regulations and restrictions\n\n**Related Endpoints:**\n- `POST /preorder/price-cart` - Calculate pricing before order submission\n- `POST /transaction/create-anonymous` - Anonymous customers without full profiles\n\n\n**Important Notes:**\n- Payment occurs later at pickup/delivery, not during order creation\n- System validates product availability and customer purchase limits\n- Customer must exist and be valid for the authenticated location\n- Orders must comply with local regulations and purchase restrictions\n- Use IdempotencyKey to prevent duplicate order creation", + "operationId": "PreorderSubmitPost", + "requestBody": { + "description": "Pre-order details including customer, cart items, and fulfillment information - CreatePreOrderRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/CreatePreOrderRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePreOrderRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CreatePreOrderRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CreatePreOrderRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Returns orderId and transactionId for the created pre-order", + "content": { + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/preorder/update": { + "post": { + "tags": ["PreOrder"], + "summary": "Update PreOrder", + "description": "**✏️ Purpose:** Modify an existing pre-order's items, delivery information, notes, or redemptions.\n\n**🔄 Updatable Fields:**\n- **Cart Items:** Add, remove, or modify product quantities and special instructions\n- **Order Notes:** Update customer notes or special handling instructions\n- **Delivery Information:** Change delivery address or timing preferences\n- **Loyalty Redemptions:** Add, remove, or modify applied discounts and rewards\n- **Order Source:** Update tracking source information\n\n**🚫 Non-Updatable Fields:**\n- **Customer ID:** Cannot transfer order to different customer\n- **Idempotency Key:** Cannot modify unique transaction identifier\n- **Order ID:** Core order identifier remains fixed\n\n**📋 Update Behavior:**\n- **Redemptions:** If redemptions field is omitted, existing redemptions are preserved\n- **Items:** Complete replacement of cart items with provided array\n- **Delivery:** Updates only if delivery information is provided\n- **Incremental Changes:** Only provided fields are modified\n\n**⏰ Update Restrictions:**\nOrders can only be updated while in specific states:\n- ✅ **Submitted/Pending:** Full updates allowed\n- ✅ **Processing:** Limited updates may be available\n- ❌ **Filled/Complete:** No updates permitted\n- ❌ **Checked Out:** Payment completed, updates blocked\n\n**🎯 Common Use Cases:**\n- **Cart Modifications:** Customer wants to add/remove items before fulfillment\n- **Address Changes:** Update delivery location for customer convenience\n- **Special Instructions:** Add preparation notes or customer preferences\n- **Discount Updates:** Apply newly available promotions or loyalty rewards\n- **Fulfillment Changes:** Switch between pickup and delivery options\n\n**🔧 Request Format:**\nProvide an `UpdatePreOrderRequest` object with OrderId and the fields to be updated.\n\n**⚠️ Important Notes:**\n- **Status Check:** Use the status endpoint to verify order is still updateable\n- **Inventory Impact:** Item changes may affect product availability\n- **Pricing Recalculation:** Updates may change order totals and taxes\n- **Delivery Validation:** Address changes subject to delivery zone verification", + "operationId": "PreorderUpdatePost", + "requestBody": { + "description": "Update details including OrderId and fields to be modified", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/UpdatePreOrderRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePreOrderRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePreOrderRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdatePreOrderRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Order updated successfully" + }, + "400": { + "description": "Bad Request - Empty response body (handle via HTTP status code only)" + }, + "404": { + "description": "Not Found - Order ID does not exist" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/preorder/cancel": { + "post": { + "tags": ["PreOrder"], + "summary": "Cancel PreOrder", + "description": "**❌ Purpose:** Cancel an existing pre-order and release any reserved inventory.\n\n**🔍 Cancellation Requirements:**\nOrder must be in a cancellable state - use the status endpoint to verify before attempting cancellation.\n\n**✅ Cancellable States:**\n- **Submitted/Pending:** Order not yet started by staff\n- **Processing:** Order in early preparation stages (may vary by location)\n\n**🚫 Non-Cancellable States:**\n- **Checked Out:** Payment has been processed\n- **Filled/Complete:** Order fulfillment finished\n- **Partially Filled:** Some items already prepared/dispensed\n- **In Transit:** Delivery orders already out for delivery\n\n**🔄 Cancellation Effects:**\n- **Inventory Release:** Reserved items returned to available inventory\n- **Payment Handling:** Refunds processed according to payment method\n- **Loyalty Redemptions:** Applied rewards/discounts are restored to customer account\n- **Order Status:** Permanently marked as cancelled\n- **Customer Notification:** Automated notifications sent if configured\n\n**🎯 Common Cancellation Reasons:**\n- **Customer Request:** Customer no longer wants the order\n- **Inventory Issues:** Items became unavailable after order placement\n- **Payment Problems:** Payment processing failed or was declined\n- **Delivery Issues:** Address problems or delivery zone restrictions\n- **Business Operations:** Store closure or emergency situations\n\n**🔧 Request Format:**\nProvide a `CancelPreOrderRequest` object with the OrderId to cancel.\n\n**Performance & Limits:**\n- Rate limited to 240 requests per minute for order management protection\n- Single order cancellation operation for targeted processing\n- Immediate inventory and payment processing upon successful cancellation\n\n**⚠️ Important Notes:**\n- **Irreversible Action:** Cancelled orders cannot be restored or reactivated\n- **Status Verification:** Always check cancellable status before attempting cancellation\n- **Refund Processing:** Payment refunds may take time depending on payment method\n- **Inventory Impact:** Cancellation immediately releases reserved inventory\n- **Customer Communication:** Consider notifying customer of cancellation reason", + "operationId": "PreorderCancelPost", + "requestBody": { + "description": "Cancellation request containing the OrderId to cancel", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/CancelPreorderRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CancelPreorderRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CancelPreorderRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CancelPreorderRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Order cancelled successfully", + "content": { + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "400": { + "description": "Bad Request - Empty response body (handle via HTTP status code only)" + }, + "404": { + "description": "Not Found - Order ID does not exist" + }, + "500": { + "description": "Internal Server Error - Server error occurred", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/preorder/Status": { + "get": { + "tags": ["PreOrder"], + "summary": "Get PreOrder Status", + "description": "**📊 Purpose:** Retrieve current status and details for pre-orders to track fulfillment progress.\n\n**🔍 Query Options:**\n- **Specific Order:** Provide PreOrderId to get detailed status for a single order\n- **All Open Orders:** Omit PreOrderId to retrieve all recent active orders (last 14 days)\n- **Line Item Details:** Set includeLineItems=true for detailed product information (requires PreOrderId)\n\n**📋 Status Information Returned:**\n- **Order Details:** Order ID, transaction ID, customer information, timestamps\n- **Current Status:** Order state (Submitted, Processing, Filled, Complete, Cancelled)\n- **Fulfillment Info:** Pickup/delivery details, estimated completion times\n- **Update Permissions:** Whether order can still be modified or cancelled\n- **Payment Status:** Payment processing state and totals\n- **Line Items:** Product details, quantities, allocated inventory (when requested)\n\n**📦 Order Status States:**\n- **Submitted:** Order received and queued for processing\n- **Processing:** Staff actively preparing order items\n- **Filled:** All items prepared and ready for customer\n- **Complete:** Customer has received order (pickup/delivery completed)\n- **Cancelled:** Order cancelled and inventory released\n\n**⚡ Performance Features:**\n- **Optimized for Real-Time:** Designed for frequent status checking and monitoring\n- **Batch Queries:** Retrieve multiple order statuses efficiently without PreOrderId\n- **Selective Detail:** Choose level of detail needed with includeLineItems parameter\n\n**🎯 Common Use Cases:**\n- **Customer Updates:** Provide real-time order progress to customers\n- **Operations Dashboard:** Monitor all active orders across fulfillment workflow\n- **Integration Sync:** Keep external systems updated with current order states\n- **Customer Service:** Quick lookup of order status for support inquiries\n- **Automated Notifications:** Trigger customer alerts based on status changes\n\n**⚠️ Important Notes:**\n- **Line Item Restriction:** includeLineItems requires a specific PreOrderId\n- **Recent Orders Filter:** Bulk queries return orders from last 14 days only\n- **Location Scoped:** Results filtered to authenticated user's location\n- **Real-Time Data:** Status reflects current state, may change during fulfillment", + "operationId": "PreorderStatusGet", + "parameters": [ + { + "name": "PreOrderId", + "in": "query", + "description": "Specific order ID to retrieve status for (optional - omit for all open orders)", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "includeLineItems", + "in": "query", + "description": "Include detailed product line item information (requires PreOrderId)", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success - Returns PreOrderStatus object(s) with current order information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreOrderStatus" + } + } + } + }, + "400": { + "description": "Bad Request - Empty response body (handle via HTTP status code only)" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/preorder/price-cart": { + "post": { + "tags": ["PreOrder"], + "summary": "Calculate Cart Pricing", + "description": "**💰 Purpose:** Calculate accurate pricing for a cart before order submission, including taxes, discounts, and final totals.\n\n**📋 Required Information:**\n- **Customer Identity:** Either CustomerId (existing customer) OR CustomerTypeId (customer category)\n- **Cart Items:** Array of products with quantities to be priced\n- **Fulfillment Type:** Specify if delivery pricing applies (affects taxes/fees)\n\n**💵 Pricing Components Calculated:**\n- **Subtotal:** Base product prices multiplied by quantities\n- **Taxes:** Location-specific tax rates applied to taxable items\n- **Discounts:** Customer-specific pricing, loyalty discounts, promotional offers\n- **Delivery Fees:** Additional charges for delivery service (if applicable)\n- **Final Total:** Complete order amount including all fees and adjustments\n\n**🎯 Customer Pricing Options:**\n- **Existing Customer:** Use CustomerId for personalized pricing and loyalty benefits\n- **Customer Type:** Use CustomerTypeId for category-based pricing (Medical, Recreational, etc.)\n- **Delivery Context:** Set IsDelivery=true to include delivery-specific pricing\n\n**🔍 Pricing Accuracy:**\n- **Real-Time Calculations:** Pricing reflects current product costs and tax rates\n- **Location-Specific:** Taxes and fees calculated based on dispensary location\n- **Customer-Specific:** Applies individual discounts, loyalty rewards, and membership benefits\n- **Delivery Zones:** Delivery fees calculated based on customer address when provided\n\n**🎯 Common Use Cases:**\n- **Cart Preview:** Show customers accurate totals before checkout\n- **Price Comparison:** Compare costs across different customer types or delivery options\n- **Integration Sync:** Keep external e-commerce platforms synchronized with current pricing\n- **Customer Service:** Provide accurate quotes for customer inquiries\n- **Mobile Apps:** Real-time cart totals for mobile ordering experiences\n\n**🔧 Request Format:**\nProvide a `PriceCartRequest` object with customer information, cart items, and delivery preferences.\n\n**Performance & Limits:**\n- Rate limited to 240 requests per minute for pricing calculation protection\n- Real-time pricing calculations optimized for responsive user experience\n- Single cart operation for immediate pricing feedback\n\n**⚠️ Important Notes:**\n- **Unique Products:** Each product should only appear once in the cart array\n- **Customer Requirement:** Must specify either CustomerId OR CustomerTypeId (not both)\n- **Pricing Volatility:** Prices may change between calculation and order submission\n- **Location Dependency:** Pricing is specific to the authenticated dispensary location\n- **Address Impact:** Delivery address affects tax calculations and delivery fees", + "operationId": "PreorderPrice-cartPost", + "requestBody": { + "description": "Pricing request containing customer information, cart items, and delivery preferences", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/PriceCartRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceCartRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PriceCartRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/PriceCartRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Returns detailed pricing breakdown for the cart", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CartPrice" + } + } + } + }, + "400": { + "description": "Bad Request - String error message (parse response body as plain text)", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Internal Server Error - Server error occurred during pricing calculation" + } + } + } + }, + "/pricing-tiers": { + "get": { + "tags": ["PricingTier"], + "summary": "Get Pricing Tiers", + "description": "**Purpose:** Retrieves the complete list of pricing tiers available for the authenticated organization for product pricing strategy and customer segmentation.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of pricing tier objects: `[{ PricingTier }, ...]`\n- Array typically contains 2-8 pricing tiers per organization\n- Returns empty array `[]` if no pricing tiers configured (rare)\n- Includes tier ID, name, and configuration details\n- Organization-level pricing tiers for customer segmentation (e.g., \"Retail\", \"Wholesale\", \"Medical\", \"VIP\")\n- Results filtered to authenticated organization level\n\n**Common Use Cases:**\n- Configure product pricing based on customer tier assignments\n- Support tiered pricing strategies for different customer segments\n- Populate pricing tier dropdown lists in customer management forms\n- Validate pricing tier assignments in product and order management systems\n- Generate tier-specific pricing reports and analytics\n- Enable dynamic pricing based on customer classifications\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Small dataset suitable for client-side caching\n- No pagination needed due to limited number of pricing tiers\n- Results consistent across all locations within organization\n\n**Related Endpoints:**\n- `GET /products` - Get products with tier-based pricing\n- `GET /customer/customer-types` - Get customer types that may use pricing tiers\n- Pricing calculation endpoints that utilize these tiers\n\n**Important Notes:**\n- Pricing tiers are defined at organization level (LSP) not location level\n- Essential for implementing tiered pricing strategies and customer segmentation\n- Used for dynamic pricing calculations based on customer classifications\n- Supports business models with wholesale, retail, and VIP pricing structures\n- May be used in conjunction with customer types for comprehensive pricing strategies", + "operationId": "Pricing-tiersGet", + "responses": { + "200": { + "description": "Success - Returns array of pricing tier objects: `[{ PricingTier }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PricingTier" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/producers": { + "get": { + "tags": ["Producer"], + "summary": "Get Producers", + "description": "**Purpose:** Retrieve basic producer identification information for product attribution and reference data needs.\n\n**Request Requirements:**\n- Valid authentication required for producer data access\n- No request body needed\n- No query parameters required\n\n**Response Data:**\n- Returns array of producer objects: `[{ Producer }, ...]`\n- Array typically contains 1-50 producers per organization\n- Returns empty array `[]` if no producers configured (rare)\n- Producer details include basic identification information only\n- Results automatically filtered to authenticated organization and exclude deleted records\n\n**Producer Information:**\n- **Producer ID**: Unique identifier for the producer\n- **Producer Name**: Display name of the producer\n\n**Common Use Cases:**\n- Populate producer dropdown lists in product management forms\n- Display producer names for product attribution and branding\n- Support basic producer identification in product catalogs\n- Enable producer-based filtering and organization in product displays\n- Provide producer reference data for product creation workflows\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Organization-scoped results for operational relevance and security\n- Small dataset suitable for client-side caching\n- Essential reference data for basic producer identification\n\n**Related Endpoints:**\n- `GET /products` - View products that include producer information\n- `GET /brands` - Related brand information for product attribution\n- `GET /vendors` - Related vendor information and business relationships\n\n**Important Notes:**\n- **Basic Reference Data**: Provides minimal producer identification information\n- **Organization Scoped**: Results filtered to authenticated organization level and exclude deleted records\n- **Limited Data**: Only includes producer ID and name - no licensing, contact, or compliance details\n- **Product Attribution**: Enables basic producer attribution for product displays", + "operationId": "ProducersGet", + "responses": { + "200": { + "description": "Success - Returns array of producer objects: `[{ Producer }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Producer" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/products/location-overrides": { + "get": { + "tags": ["Product"], + "summary": "Get Location Product Overrides", + "description": "**Purpose:** Retrieve all location-specific product overrides for pricing, availability, and display customization at the current location.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for product override data access\n- No query parameters required\n- No request body needed\n\n**Response Data:**\n- Returns array of `LocationProductOverride` objects with location-specific settings\n- Array typically contains 50-5,000+ overrides depending on location customization\n- Returns empty array `[]` if no overrides exist for the location (not null)\n- If a field is `null`, then the product master version of that field applies\n- Includes pricing overrides, availability settings, and display configurations\n- Results automatically filtered to authenticated location\n\n**Override Behavior:**\n- **Null Fields**: When override field is null, the product master value is used\n- **Set Fields**: When override field has a value, it replaces the master value\n- **Location Specific**: Overrides only apply to the authenticated location\n- **Inheritance**: Non-overridden fields inherit from product master data\n\n**Common Use Cases:**\n- Retrieve location-specific pricing for multi-location businesses\n- Get availability overrides for location inventory management\n- Access display customizations for location-specific product presentation\n- Synchronize location overrides with external point-of-sale systems\n- Generate location-specific product catalogs and pricing sheets\n\n**Performance & Limits:**\n- Optimized for location-specific product management workflows\n- Results filtered automatically to current location scope\n- Efficient for multi-location businesses with location-specific pricing\n- Consider caching for frequent access to override data\n\n**Related Endpoints:**\n- `POST /products/location-overrides` - Create or update location overrides\n- `GET /products` - Get product master data with default values\n- `GET /inventory` - Get current inventory levels for overridden products\n\n**Important Notes:**\n- **Inheritance Model**: Null override fields inherit from product master data\n- **Location Scoped**: Results automatically filtered to authenticated location\n- **Override Priority**: Location overrides take precedence over master product data\n- **Multi-Location**: Essential for businesses operating multiple dispensary locations\n- **Pricing Control**: Enables location-specific pricing strategies and market adaptation", + "operationId": "ProductsLocation-overridesGet", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationProductOverride" + } + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + }, + "post": { + "tags": ["Product"], + "summary": "Create or Update Location Product Overrides", + "description": "**Purpose:** Create or update location-specific product overrides for pricing, availability, and display customization to support multi-location business operations.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for product override modification\n- Array of `LocationProductOverrideRequest` objects in request body\n- Content-Type: application/json\n- Valid ProductId required for each override\n\n**Response Data:**\n- Returns HTTP 200 with no response body on success\n- No data returned - operation confirmation only\n- Returns HTTP 400 with validation errors if request data is invalid\n- Partial success possible: some overrides may save even if others fail\n\n**Create vs Update Behavior:**\n- **CREATE**: When no existing override exists for the ProductId at this location, a new override is created\n- **UPDATE**: When an override already exists for the ProductId at this location, it is updated\n- **Identification**: Override existence determined by ProductId and authenticated location\n- **Automatic Detection**: System automatically determines create vs update based on existing data\n\n**Sparse Update Behavior:**\n- **Omitted Fields**: Retain their current override value (no change)\n- **Null Values**: Remove the override for that field (product master value will apply)\n- **Set Values**: Update the override with the provided value\n- **Field Independence**: Each field can be updated independently without affecting others\n\n**Override Management:**\n- **Removal**: Set fields to null to remove overrides and revert to product master values\n- **Addition**: Set fields to specific values to create new overrides\n- **Location Scoped**: All overrides apply only to the authenticated location\n- **Dual Pricing**: Automatically handles recreational price sync when dual pricing is disabled\n\n**Common Use Cases:**\n- Set location-specific pricing for multi-location businesses\n- Override product availability for location inventory management\n- Customize product display settings for location-specific presentation\n- Manage location-based pricing strategies and market adaptation\n- Synchronize pricing changes from external systems to specific locations\n\n**Performance & Limits:**\n- Batch processing for efficient multi-product override updates\n- Validation performed before any changes to ensure data integrity\n- Partial success handling: some overrides may succeed even if others fail\n- Optimized for location-specific product management workflows\n\n**Related Endpoints:**\n- `GET /products/location-overrides` - Retrieve current location overrides\n- `GET /products` - Get product master data for comparison\n- `GET /inventory` - Check inventory levels for overridden products\n\n**Important Notes:**\n- **Partial Success**: Some overrides may save successfully even if others fail validation\n- **Null Behavior**: Setting fields to null removes overrides and reverts to master data\n- **Location Isolation**: Overrides only affect the authenticated location\n- **Validation Required**: All ProductIds must exist and be valid for the location\n- **Dual Pricing Sync**: Recreational prices automatically sync with medical when dual pricing disabled", + "operationId": "ProductsLocation-overridesPost", + "requestBody": { + "description": "Array of location product override requests with ProductId and override values - LocationProductOverrideRequest objects", + "content": { + "application/json-patch+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationProductOverrideRequest" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationProductOverrideRequest" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationProductOverrideRequest" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationProductOverrideRequest" + } + } + } + }, + "x-bodyName": "updates" + }, + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)" + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong. One or more overrides may have been saved" + } + } + } + }, + "/products": { + "get": { + "tags": ["Product"], + "summary": "Get Products", + "description": "**Purpose:** Retrieve comprehensive product catalog information for API-enabled products, regardless of current inventory levels.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for product data access\n- Optional query parameters for filtering results\n- No request body needed\n\n**Response Data:**\n- Returns array of product objects: `[{ ProductDetail }, ...]`\n- Array may contain 0 to 10,000+ products depending on location inventory size\n- Returns empty array `[]` if no products match criteria (not null)\n- Product details including SKU, name, description, category, brand, strain information\n- Pricing data with retail and medical pricing, tax rates, discount eligibility\n- Classification data including product types, categories, regulatory classifications\n- Lab results with potency data, cannabinoid profiles, test results when available\n- Inventory data showing stock levels and availability status\n- Media assets including product images and visual content\n- Compliance data with external IDs, producer information, regulatory data\n\n**Filtering Options:**\n- No parameters: Returns all API-enabled products for the location\n- fromLastModifiedDateUTC: Returns products modified after this date for incremental sync\n- isActive: Filter by active status (true/false/null for all)\n\n**Product Filtering Logic:**\n- Only products specifically enabled for API access are returned\n- Only includes products with online availability enabled (onlyOnlineAvailable = true)\n- Products returned even if currently out of stock\n- Results automatically filtered to authenticated user's location only\n\n**Common Use Cases:**\n- Get complete product catalog for first-time integration setup\n- Use incremental updates with fromLastModifiedDateUTC to sync only recent changes\n- Populate e-commerce online store with complete product information\n- Maintain up-to-date product database for point-of-sale systems\n- Build dispensary menus with detailed product information\n- Analyze product catalog for purchasing and inventory planning decisions\n\n**Performance & Limits:**\n- Use incremental sync with fromLastModifiedDateUTC for regular updates to minimize data transfer\n- Filter by isActive=true to exclude discontinued products for better performance\n- Run full catalog sync during off-peak hours for optimal performance\n- Large product catalogs may require pagination in future versions\n\n**Related Endpoints:**\n- `GET /inventory` - Current stock levels for products with available inventory\n- `GET /products/strains` - Strain-specific information and genetics data\n- `GET /products/external-categories` - Product categorization and classification data\n\n**Important Notes:**\n- This endpoint respects the \"API access\" setting on products for access control\n- Returns only online-available products (excludes products not enabled for online sales)\n- Response includes comprehensive product information for full integration capabilities\n- Products are automatically filtered to the authenticated location", + "operationId": "ProductsGet", + "parameters": [ + { + "name": "fromLastModifiedDateUTC", + "in": "query", + "description": "Optional date filter to return only products modified after this timestamp - Used for incremental sync", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "isActive", + "in": "query", + "description": "Optional status filter - true for active products only, false for inactive only, null for all products", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of product objects: `[{ ProductDetail }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProductDetail" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for inventory access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/products/product": { + "post": { + "tags": ["Product"], + "summary": "Create or Update Product", + "description": "**Purpose:** Creates a new product or updates an existing product with comprehensive product information for inventory management.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for product data access\n- `ProductDetailUpload` object in request body with product details\n- Content-Type: application/json\n- SKU and ProductName required for new products\n\n**Response Data:**\n- Returns single `ProductDetail` object (not array) with updated product information\n- Response format: `{ ProductDetail }`\n- Includes assigned product ID for new products or updated ID for existing products\n- Complete product information with all fields populated\n\n**CRITICAL DATA LOSS WARNING:**\nMost fields will be overwritten with null/zero values if not provided in the request.\nRECOMMENDED APPROACH: First GET the existing product, modify only the fields you want to change, then POST the complete object back.\n\n**Required Fields:**\n- For CREATE: SKU and ProductName are required\n- For UPDATE: Only ProductId is required (SKU and ProductName can be omitted to preserve existing values)\n\n**Field Behavior:**\n- Optional Fields: Can be explicitly set to null or omitted to preserve existing values\n- Regular Fields: Will be set to null/zero if omitted, potentially causing data loss\n- Exception: Fields like SKU and ProductName preserve existing values when omitted during updates\n\n**Common Use Cases:**\n- Add new products to the catalog for inventory management\n- Update existing product information when details change\n- Synchronize product data from external inventory systems\n- Bulk product updates for pricing or categorization changes\n- Maintain accurate product information for compliance and sales\n\n**Performance & Limits:**\n- Single product operation for targeted updates\n- Immediate validation and response\n- Changes reflected immediately in product catalogs\n- Consider using GET before POST to avoid data loss\n\n**Related Endpoints:**\n- `GET /products` - Retrieve existing product data before updates\n- `GET /brand` - Get valid brand IDs for product association\n- `GET /strains` - Get valid strain IDs for product classification\n\n**Important Notes:**\n- Data loss risk: Always retrieve existing product data before updates\n- Product ID assignment for successful new product creation\n- Validation performed before creation/update to ensure data integrity\n- Changes propagate to inventory and sales systems immediately", + "operationId": "ProductsProductPost", + "requestBody": { + "description": "Product information to create or update - ProductDetailUpload object with product details", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/ProductDetailUpload" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductDetailUpload" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProductDetailUpload" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ProductDetailUpload" + } + } + }, + "x-bodyName": "product" + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductDetail" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/products/products": { + "post": { + "tags": ["Product"], + "summary": "Bulk Create or Update Products", + "description": "**Purpose:** Create or update multiple products in a single operation for efficient catalog management and bulk data synchronization.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for product data operations\n- Array of `ProductDetailUpload` objects in request body with product details\n- Content-Type: application/json\n- Each product requires SKU and ProductName for creation, ProductId for updates\n\n**Response Data:**\n- Returns mixed array: `[{ ProductDetail }, { SaveProductError }, ...]`\n- Successful operations return complete `ProductDetail` objects with updated product information\n- Failed operations return `SaveProductError` objects with ProductId, SKU, ProductName, and ErrorMessage\n- HTTP 200 for successful processing - check individual items in response array for success/error status\n- HTTP 400 for validation errors that prevent processing\n- Mixed array allows partial success - some products may succeed while others fail\n\n**CRITICAL DATA LOSS WARNING:**\nMost fields will be overwritten with null/zero values if not provided in the request.\n**RECOMMENDED APPROACH:** First GET existing products, modify only desired fields, then POST complete objects back.\n\n**Create vs Update Behavior:**\n- **CREATE**: When ProductId is null or omitted, new product records will be created\n- **UPDATE**: When ProductId is provided with valid product IDs, existing products will be updated\n- **Mixed Operations**: Single request can include both create and update operations\n- **Validation**: SKU and ProductName required for creates, ProductId required for updates\n- **Individual Processing**: Each product processed independently - some may succeed while others fail\n\n**Field Preservation Behavior:**\n- **Optional Fields**: Can be explicitly set to null or omitted to preserve existing values\n- **Regular Fields**: Will be set to null/zero if omitted, potentially causing data loss\n- **Preserved Fields**: SKU and ProductName preserve existing values when omitted during updates\n- **Best Practice**: Always provide complete product objects to avoid unintended data loss\n\n**Error Handling:**\n- **Partial Success**: Some products may succeed while others fail within the same request\n- **Error Identification**: Failed products include ErrorMessage, ProductId, SKU, and ProductName\n- **Validation Errors**: Returns HTTP 400 for validation errors that prevent processing\n- **Processing Errors**: Returns HTTP 200 with mixed results for individual product errors\n- **Rollback Behavior**: No automatic rollback - successful operations persist even if others fail\n\n**Common Use Cases:**\n- Import large product catalogs from external systems efficiently\n- Synchronize product changes across multiple products simultaneously\n- Bulk update pricing, categorization, or product attributes\n- Migrate product data between systems with batch processing\n- Update multiple products after inventory or regulatory changes\n\n**Performance & Limits:**\n- Optimized for bulk product operations and catalog management\n- Individual product validation and processing for data integrity\n- No automatic external system broadcasting for performance\n- Efficient for large-scale product catalog updates\n\n**Related Endpoints:**\n- `GET /products` - Retrieve existing product data before bulk updates\n- `POST /products/product` - Create or update individual products with external sync\n- `GET /brand` - Get valid brand IDs for product associations\n- `GET /strains` - Get valid strain IDs for product classifications\n\n**Important Notes:**\n- **Individual Processing**: Each product processed independently with separate success/failure results\n- **No External Broadcast**: Traceability system broadcasting not supported on this endpoint\n- **Data Loss Risk**: Always retrieve existing product data before bulk updates\n- **Error Checking Required**: Always check response for individual product errors\n- **Performance Optimized**: Designed for efficient bulk operations without external system overhead", + "operationId": "ProductsProductsPost", + "requestBody": { + "description": "Array of product information to create or update - IEnumerable objects", + "content": { + "application/json-patch+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProductDetailUpload" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProductDetailUpload" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProductDetailUpload" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProductDetailUpload" + } + } + } + }, + "x-bodyName": "products" + }, + "responses": { + "200": { + "description": "Success - Products processed with individual success/error results", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors) OR `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResult" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/products/set-image": { + "post": { + "tags": ["Product"], + "summary": "Set Product Image", + "description": "**Purpose:** Add or update a single image for a product to enhance product presentation and visual merchandising.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for product image management\n- `SetImageRequest` object in request body with ProductId and image data\n- Content-Type: application/json\n- Valid ProductId and base64-encoded image data required\n\n**Response Data:**\n- Returns single image response object: `{ SetImageResponse }`\n- Includes unique image ID for future image management operations\n- Provides image URL for immediate access to uploaded image\n- Contains ImageId (integer) and ImageUrl (string) fields only\n\n**Image Processing:**\n- **Single Image**: Adds one image per request to the specified product\n- **Image ID Assignment**: Returns unique DPOS product image ID for tracking\n- **Format Support**: Supports standard image formats via base64 encoding\n- **Validation**: Validates image data and product existence before processing\n\n**Integration Behavior:**\n- **Metrc Integration**: If using Metrc with upload product images enabled, the image will automatically upload to Metrc on next product save\n- **Automatic Sync**: Integration occurs when `Save Product` is called for this ProductId\n- **Compliance**: Supports regulatory compliance through integrated system image sync\n- **External Systems**: Compatible with cultivation and compliance system requirements\n\n**Common Use Cases:**\n- Add product photos for e-commerce and point-of-sale display\n- Update existing product images for marketing and merchandising\n- Comply with regulatory requirements for product visual documentation\n- Enhance customer experience with high-quality product imagery\n- Support integrated systems with automated image synchronization\n\n**Performance & Limits:**\n- Single image processing for targeted product updates\n- Base64 encoding for secure image data transmission\n- Validation performed before processing to ensure data integrity\n- Optimized for product visual merchandising workflows\n\n**Related Endpoints:**\n- `POST /products/remove-image` - Remove product images using the returned image ID\n- `POST /products/product` - Save product data and trigger Metrc image sync\n- `GET /products` - Retrieve products with associated image information\n\n**Important Notes:**\n- **Image ID Required**: Save the returned image ID for future image management operations\n- **Metrc Auto-Upload**: Images automatically sync to Metrc on next product save when enabled\n- **Single Operation**: One image per request - use multiple requests for multiple images\n- **Validation Required**: ProductId must exist and image data must be valid\n- **Integration Ready**: Supports automated compliance system synchronization", + "operationId": "ProductsSet-imagePost", + "requestBody": { + "description": "Image upload request with ProductId and base64 image data - SetImageRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/SetImageRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetImageRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SetImageRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/SetImageRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetImageResponse" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/products/remove-image": { + "post": { + "tags": ["Product"], + "summary": "Delete Product Image", + "description": "**Purpose:** Remove a specific image from a product using the image ID to maintain clean product presentation and manage visual merchandising.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for product image management\n- `DeleteImageRequest` object in request body with ProductId and ImageId\n- Content-Type: application/json\n- Valid ProductId and ImageId required (ImageId obtained from set-image response)\n\n**Response Data:**\n- Returns success confirmation object: `{ SuccessResult }`\n- Simple success confirmation with HTTP 200 status\n- No additional data fields returned beyond success indicator\n\n**Image Removal Process:**\n- **Targeted Deletion**: Removes specific image identified by ImageId\n- **Product Association**: Verifies image belongs to the specified ProductId\n- **Validation**: Ensures both ProductId and ImageId exist and are valid\n- **Clean Removal**: Permanently removes image from product and storage systems\n\n**Safety & Validation:**\n- **Existence Check**: Validates ProductId and ImageId before deletion\n- **Ownership Verification**: Ensures image belongs to the specified product\n- **Authorization**: Confirms user has permission to modify product images\n- **Error Handling**: Returns appropriate errors for invalid requests\n\n**Common Use Cases:**\n- Remove outdated or incorrect product images from visual merchandising\n- Clean up product galleries by deleting unwanted or duplicate images\n- Manage product image lifecycle for marketing and compliance requirements\n- Maintain accurate product representation in e-commerce and point-of-sale systems\n- Support product image management workflows and content updates\n\n**Performance & Limits:**\n- Single image deletion for targeted image management\n- Immediate removal from product and storage systems\n- Validation performed before deletion to ensure data integrity\n- Optimized for product visual merchandising and content management workflows\n\n**Related Endpoints:**\n- `POST /products/set-image` - Add images and obtain ImageId for future deletion\n- `GET /products` - Retrieve products with current image information\n- `POST /products/product` - Update product data and manage overall product information\n\n**Important Notes:**\n- **ImageId Required**: Use ImageId returned from set-image endpoint for deletion\n- **Permanent Operation**: Image deletion is permanent and cannot be undone\n- **Validation Critical**: Both ProductId and ImageId must be valid and associated\n- **Single Target**: One image per request - use multiple requests for multiple deletions\n- **Clean Management**: Essential for maintaining organized product image galleries", + "operationId": "ProductsRemove-imagePost", + "requestBody": { + "description": "Image deletion request with ProductId and ImageId - DeleteImageRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/DeleteImageRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteImageRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DeleteImageRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DeleteImageRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResult" + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/products/strains": { + "get": { + "tags": ["Product"], + "summary": "Get Product Strains", + "description": "**Purpose:** Retrieve all available cannabis strains for product classification and inventory management in compliance with industry standards.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for strain data access\n- No query parameters required\n- No request body needed\n\n**Response Data:**\n- Returns array of strain objects: `[{ StrainDetail }, ...]`\n- Array typically contains 50-1,000+ strains depending on dispensary catalog\n- Returns empty array `[]` if no strains are configured (not null)\n- Basic strain information including ID, name, description, type, and external ID\n- Results automatically filtered to authenticated location strain catalog\n\n**Strain Information:**\n- **Strain ID**: Unique identifier for the strain\n- **Strain Name**: Display name of the strain\n- **Strain Description**: Basic text description of the strain\n- **Strain Abbreviation**: Short code or abbreviation for the strain\n- **Strain Type**: Basic type classification (e.g., Indica, Sativa, Hybrid)\n- **External ID**: External system identifier for integration\n\n**Common Use Cases:**\n- Populate strain dropdown lists in product creation and management forms\n- Display basic strain information for product attribution\n- Support strain-based product categorization and filtering\n- Enable strain identification in inventory management systems\n- Provide strain reference data for product classification workflows\n\n**Performance & Limits:**\n- Optimized for product classification and strain selection workflows\n- Comprehensive strain database for complete cannabis product categorization\n- Results filtered to location-specific strain catalog\n- Efficient for strain-based product search and filtering operations\n\n**Related Endpoints:**\n- `GET /products` - View products with assigned strain classifications\n- `POST /products/product` - Assign strains to products during creation/update\n- `GET /strains` - Manage strain master data and configurations\n\n**Important Notes:**\n- **Basic Reference Data**: Provides essential strain identification information only\n- **Limited Data**: Only includes basic strain details - no cannabinoid profiles, genetics, or effects\n- **Product Classification**: Strains used for basic product categorization and identification\n- **Location Catalog**: Results filtered to strains available for the authenticated location\n- **External Integration**: Includes External ID for traceability system integration", + "operationId": "ProductsStrainsGet", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StrainDetail" + } + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/products/external-categories": { + "get": { + "tags": ["Product"], + "summary": "Get External Categories", + "description": "**Purpose:** Retrieve external system categories for product classification to support integration with traceability and compliance systems.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for external category data access\n- UserId query parameter highly recommended for traceability system integration\n- No request body needed\n\n**Response Data:**\n- Returns array of string values with external category names\n- Response format: `[string, string, ...]`\n- Array contains categories available from integrated traceability systems\n- Returns empty array `[]` if no external categories are available (not null)\n- Category names correspond to external system classification standards\n- Used for populating ExternalCategory field in product data\n- Results depend on configured integrated systems and user permissions\n\n**Integration Requirements:**\n- **Traceability Systems**: Categories pulled from connected compliance systems (e.g., Metrc, BioTrack)\n- **User Context**: UserId parameter provides system access context for category retrieval\n- **System Configuration**: Available categories depend on integrated system configuration\n- **Compliance Mapping**: Categories align with regulatory compliance requirements\n\n**Parameter Guidelines:**\n- **UserId**: Technically optional but highly recommended for traceability system calls\n- **System Failure**: Call may fail without UserId when categories come from traceability systems\n- **Permission Context**: UserId provides proper system access permissions for category retrieval\n- **Default Fallback**: Uses default user (ID 6) when UserId not provided\n\n**Common Use Cases:**\n- Populate product ExternalCategory field with valid compliance categories\n- Synchronize product classifications with regulatory traceability systems\n- Ensure product categories align with state compliance requirements\n- Support automated product categorization for integrated systems\n- Validate product classifications against external system standards\n\n**Performance & Limits:**\n- Real-time integration with external traceability systems\n- Response time dependent on external system availability\n- Error handling for external system connectivity issues\n- Optimized for product classification and compliance workflows\n\n**Related Endpoints:**\n- `POST /products/product` - Use external categories in ExternalCategory field\n- `GET /products` - View products with assigned external categories\n- `POST /products/products` - Bulk assign external categories to products\n\n**Important Notes:**\n- **UserId Critical**: Highly recommended to prevent traceability system call failures\n- **External Dependency**: Categories sourced from integrated traceability systems\n- **Compliance Essential**: External categories required for regulatory compliance\n- **System Specific**: Available categories depend on configured integrated systems\n- **Error Handling**: May return errors if external systems are unavailable", + "operationId": "ProductsExternal-categoriesGet", + "parameters": [ + { + "name": "userId", + "in": "query", + "description": "User ID for traceability system access context (highly recommended) - Optional but prevents system failures", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "description": "Bad Request - String error message (parse response body as plain text)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/product-category": { + "get": { + "tags": ["ProductCategory"], + "summary": "Get Product Categories", + "description": "**Purpose:** Retrieves the complete list of product categories available for the authenticated organization for product classification and menu organization.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of product category objects: `[{ ProductCategory }, ...]`\n- Array typically contains 10-30 product categories per organization\n- Returns empty array `[]` if no categories configured (rare)\n- Includes category ID, name, and master category classification\n- Standard cannabis product categories (Flower, Edibles, Concentrates, etc.)\n- Results filtered to authenticated organization level and exclude deleted records\n\n**Common Use Cases:**\n- Populate product category dropdown lists in product creation forms\n- Organize product menus by category for customer browsing\n- Validate product categorization in inventory management systems\n- Generate category-specific reports for sales analytics\n- Support e-commerce product filtering and navigation\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Small dataset suitable for client-side caching\n- No pagination needed due to limited number of categories\n- Results consistent across all locations within organization\n\n**Related Endpoints:**\n- `GET /products` - Get products that use these categories\n- `POST /product` - Create products with category assignments\n- `GET /regulatory-category` - Get regulatory category classifications\n\n**Important Notes:**\n- Categories are defined at organization level (LSP) not location level\n- Standard cannabis industry categories for compliance and consistency\n- Used for product menu organization and customer filtering\n- Essential reference data for product management workflows", + "operationId": "Product-categoryGet", + "responses": { + "200": { + "description": "Success - Returns array of product category objects: `[{ ProductCategory }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProductCategory" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/purchase-order": { + "get": { + "tags": ["PurchaseOrder"], + "summary": "Get Purchase Orders", + "description": "**Purpose:** Retrieve purchase orders with comprehensive filtering options to support procurement management and vendor relationship tracking.\n\n**Request Requirements:**\n- \"PurchaseOrder\" role authorization required for purchase order data access\n- Optional query parameters available for filtering purchase orders\n- Purchase order management permissions for procurement operations\n\n**Response Data:**\n- Response format: `[{ PurchaseOrderData }, { PurchaseOrderData }, ...]`\n- **No pagination metadata**: Response contains only data array without total counts or page information\n- Array contains up to PageSize purchase orders (default 1000)\n- Returns empty array `[]` if no purchase orders match filtering criteria\n- Includes comprehensive purchase order details and line item information\n- Results automatically filtered to authenticated location\n\n**Pagination Usage:**\n- **First Request**: Call with PageNumber=0 to get first page\n- **Subsequent Requests**: Increment PageNumber for each additional page\n- **End Detection**: Continue requesting pages until you receive an empty array `[]`\n- **Page Size Control**: Use PageSize parameter to control items per page\n- **Example Flow**: Request PageNumber=0 → Process results → Increment PageNumber → Repeat until empty `[]` response\n\n**Pagination Detection:**\n- **End of data detection**: Continue requesting pages until you receive an empty array `[]`\n- **No metadata provided**: Response does not include total counts, page counts, or hasNextPage indicators\n- **Sequential access**: Increment PageNumber from 0 until empty response indicates no more data\n\n**Filtering Options:**\n- **FromDateCreated**: Optional date parameter to filter orders created after specific date\n- **ToDateCreated**: Optional date parameter to filter orders created before specific date\n- **PurchaseOrderId**: Optional integer parameter to retrieve specific purchase order\n- **IncludeItemDetails**: Optional boolean to include detailed line item information\n\n**Purchase Order Information Included:**\n- **Order Details**: Purchase order identification, status, and vendor information\n- **Line Items**: Product details and quantities (when IncludeItemDetails is true)\n- **Dates**: Creation, modification, and expected delivery dates\n- **Financial Data**: Order totals, costs, and payment information\n\n**Common Use Cases:**\n- Display purchase orders for procurement management and vendor tracking\n- Filter orders by date ranges for reporting and analysis\n- Retrieve specific purchase orders for detailed review and management\n- Support vendor relationship management and procurement workflows\n- Generate procurement reports and purchase order analytics\n\n**Performance & Limits:**\n- Use consistent page size throughout pagination sequence for efficiency\n- Monitor response times and adjust page size for optimal performance\n- Cache results locally to minimize API calls and improve responsiveness\n- Validation performed on all query parameters before processing\n- Optimized for procurement management and vendor tracking workflows\n\n**Related Endpoints:**\n- `POST /purchase-order` - Create or update purchase orders\n- `GET /vendors` - View vendors associated with purchase orders\n- `GET /inventory` - View inventory levels for procurement planning\n\n**Important Notes:**\n- **Procurement Integration**: Essential for vendor management and procurement workflows\n- **Flexible Filtering**: Multiple parameters can be combined for precise order lookup\n- **Location Scoped**: Purchase orders filtered to authenticated location operations\n- **Validation Required**: All query parameters validated before purchase order retrieval", + "operationId": "Purchase-orderGet", + "parameters": [ + { + "name": "FromDateCreated", + "in": "query", + "description": "Start date filter for purchase orders created after this date (optional).", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "ToDateCreated", + "in": "query", + "description": "End date filter for purchase orders created before this date (optional).", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "PurchaseOrderId", + "in": "query", + "description": "Specific purchase order identifier for single order retrieval (optional).", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "IncludeItemDetails", + "in": "query", + "description": "Whether to include detailed line item information in the response (default: false).", + "schema": { + "type": "boolean" + } + }, + { + "name": "PageNumber", + "in": "query", + "description": "Page number for pagination control (default: 0).", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "PageSize", + "in": "query", + "description": "Number of results per page for pagination (default: 1000).", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PurchaseOrderData" + } + } + } + } + }, + "400": { + "description": "Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + }, + "post": { + "tags": ["PurchaseOrder"], + "summary": "Create or Update Purchase Orders", + "description": "**Purpose:** Create new purchase orders or update existing purchase orders for procurement management and vendor relationship operations.\n\n**Request Requirements:**\n- \"PurchaseOrder\" role authorization required for purchase order modification\n- `CreateUpdatePurchaseOrdersRequest` object in request body with purchase order details\n- Content-Type: application/json\n- Purchase order management permissions for procurement operations\n\n**Response Data:**\n- Returns result object with purchase order creation/update status\n- Response format: `{ \"createdPurchaseOrderIds\": [int, ...], \"updatedPurchaseOrderIds\": [int, ...] }`\n- Includes arrays of created and updated purchase order IDs\n- Purchase order identification and processing results\n\n**Create vs Update Behavior:**\n- **CREATE**: When PurchaseOrderId is null, a new purchase order will be created\n- **UPDATE**: When PurchaseOrderId is non-null, the existing purchase order will be updated\n- **Identification**: Purchase order existence determined by PurchaseOrderId value\n- **Line Item Updates**: Updates affect both purchase order header and line item details\n\n**Purchase Order Data Fields:**\n- **Header Information**: Vendor details, order dates, and procurement specifications\n- **Line Items**: Product details, quantities, costs, and delivery requirements\n- **Financial Data**: Order totals, taxes, and payment terms\n- **Status Information**: Order status and processing workflow details\n\n**Common Use Cases:**\n- Create new purchase orders for vendor procurement operations\n- Update existing purchase orders with revised quantities or specifications\n- Modify purchase order line items for procurement adjustments\n- Support vendor relationship management and procurement workflows\n- Maintain accurate procurement records and vendor tracking\n\n**Performance & Limits:**\n- Validation performed before any purchase order processing\n- Batch processing for multiple purchase order operations\n- Optimized for procurement management and vendor tracking workflows\n- Changes reflected immediately in procurement and vendor systems\n\n**Related Endpoints:**\n- `GET /purchase-order` - Retrieve purchase orders for review before updates\n- `GET /vendors` - View vendors for purchase order creation\n- `GET /inventory` - Check inventory levels for procurement planning\n\n**Important Notes:**\n- **Validation Critical**: All purchase order data validated before processing\n- **Procurement Integration**: Purchase orders affect vendor management and procurement workflows\n- **Location Scoped**: Purchase orders automatically associated with authenticated location\n- **Batch Processing**: Multiple purchase orders can be processed in single operation\n- **Vendor Relationships**: Purchase order creation strengthens vendor tracking and management", + "operationId": "Purchase-orderPost", + "requestBody": { + "description": "Purchase order creation/update request with order details - CreateUpdatePurchaseOrdersRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/CreateUpdatePurchaseOrdersRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateUpdatePurchaseOrdersRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CreateUpdatePurchaseOrdersRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CreateUpdatePurchaseOrdersRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateUpdatePurchaseOrderResponse" + } + } + } + }, + "400": { + "description": "Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/reference/units": { + "get": { + "tags": ["ReferenceData"], + "summary": "Get Units", + "description": "**Purpose:** Retrieves the complete list of measurement units available for product tracking and inventory management.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of unit objects: `[{ Unit }, ...]`\n- Array typically contains 20-30 measurement units\n- Returns empty array `[]` if no units configured (rare)\n- Includes unit ID, name, abbreviation, and conversion factors\n- Standard measurement units (grams, ounces, pounds, units, etc.)\n- Essential reference data for product weight and quantity tracking\n\n**Common Use Cases:**\n- Configure product measurement units in inventory systems\n- Support weight-based pricing and inventory calculations\n- Validate unit measurements in product and package operations\n- Generate reports with proper unit conversions and formatting\n- Enable accurate compliance reporting with regulatory weight requirements\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Small static dataset suitable for client-side caching\n- No pagination needed due to limited number of standard units\n- Consistent across all organizations and locations\n\n**Related Endpoints:**\n- `GET /reference/unit-types` - Get unit type classifications\n- `GET /products` - Get products with unit measurements\n- `GET /inventory` - Get inventory with unit-based quantities\n\n**Important Notes:**\n- Standard cannabis industry measurement units for compliance\n- Essential for accurate weight tracking and regulatory reporting\n- Used throughout the system for product and inventory operations\n- Supports both metric and imperial measurement systems", + "operationId": "ReferenceUnitsGet", + "responses": { + "200": { + "description": "Success - Returns array of unit objects: `[{ Unit }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Unit" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reference/unit-types": { + "get": { + "tags": ["ReferenceData"], + "summary": "Get Unit Types", + "description": "**Purpose:** Retrieves the complete list of unit type classifications used to categorize different measurement units.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of unit type objects: `[{ UnitType }, ...]`\n- Array typically contains 5-10 unit type categories\n- Returns empty array `[]` if no unit types configured (rare)\n- Includes type ID, name, and category descriptions\n- Unit type categories (Weight, Volume, Count, etc.) for measurement classification\n- Reference data for organizing units by measurement type\n\n**Common Use Cases:**\n- Organize units by measurement type in user interfaces\n- Validate unit assignments based on product type requirements\n- Support advanced filtering and categorization of measurement units\n- Enable proper unit selection based on product characteristics\n- Generate reports organized by measurement type categories\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Small static dataset suitable for client-side caching\n- No pagination needed due to limited number of unit types\n- Consistent across all organizations and locations\n\n**Related Endpoints:**\n- `GET /reference/units` - Get specific units within these types\n- `GET /products` - Get products using typed unit measurements\n- `GET /inventory` - Get inventory with type-based unit tracking\n\n**Important Notes:**\n- Standard measurement type categories for consistent classification\n- Helps organize units for better user experience and validation\n- Used for advanced unit selection and validation logic\n- Essential for proper measurement type categorization", + "operationId": "ReferenceUnit-typesGet", + "responses": { + "200": { + "description": "Success - Returns array of unit type objects: `[{ UnitType }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UnitType" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reference/lab-result-units": { + "get": { + "tags": ["ReferenceData"], + "summary": "Get Lab Result Units", + "description": "**Purpose:** Retrieves the complete list of measurement units specifically used for laboratory test results and cannabinoid/terpene reporting.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of lab result unit objects: `[{ LabResultUnitData }, ...]`\n- Array typically contains 5-15 specialized lab measurement units\n- Returns empty array `[]` if no lab units configured (rare)\n- Includes lab result unit ID and unit name/abbreviation\n- Specialized units for cannabinoid and terpene concentration measurements\n- Essential reference data for laboratory test result reporting\n\n**Common Use Cases:**\n- Configure lab result units in testing and compliance systems\n- Validate unit measurements in laboratory data submissions\n- Support cannabinoid and terpene concentration reporting\n- Generate compliance reports with proper lab result unit formatting\n- Enable accurate potency testing and COA (Certificate of Analysis) generation\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Small static dataset suitable for client-side caching\n- No pagination needed due to limited number of lab result units\n- Consistent across all organizations and locations\n\n**Related Endpoints:**\n- `GET /reference/lab-results-names` - Get available lab result names\n- `GET /reference/units` - Get general measurement units\n- Lab result POST endpoints (for submitting test data)\n\n**Important Notes:**\n- Specialized units for cannabis laboratory testing and analysis\n- Essential for compliance with cannabis testing regulations\n- Used specifically for cannabinoid and terpene concentration measurements\n- Required for accurate Certificate of Analysis (COA) reporting\n- Different from general product measurement units", + "operationId": "ReferenceLab-result-unitsGet", + "responses": { + "200": { + "description": "Success - Returns array of lab result unit objects: `[{ LabResultUnitData }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LabResultUnitData" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reference/lab-results-names": { + "get": { + "tags": ["ReferenceData"], + "summary": "Get Lab Result Names", + "description": "**Purpose:** Retrieves the complete list of available lab result names that can be used with lab result POST endpoints for cannabinoid and terpene testing.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of strings with valid lab result names: `[\"string\", ...]`\n- Array typically contains 50-100 cannabinoid and terpene names\n- Returns empty array `[]` if no lab result names configured (rare)\n- Standard cannabinoid names (THC, CBD, CBG, CBN, etc.)\n- Common terpene names (Myrcene, Limonene, Pinene, etc.)\n- All acceptable values for lab result name validation\n\n**Common Use Cases:**\n- Validate lab result names before submitting test data\n- Populate dropdown lists for lab result entry forms\n- Reference data for cannabinoid and terpene testing workflows\n- Support laboratory data integration and validation\n- Generate dynamic forms for Certificate of Analysis (COA) entry\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Static dataset suitable for client-side caching\n- No pagination needed due to manageable list size\n- Consistent across all organizations and locations\n\n**Related Endpoints:**\n- `GET /reference/lab-result-units` - Get valid units for these results\n- Lab result POST endpoints - Submit test data using these names\n- `GET /products` - Get products with lab result data\n\n**Important Notes:**\n- These are the only valid values accepted for lab result names\n- Standard cannabis testing terminology for consistency\n- Essential for proper cannabinoid and terpene data submission\n- Used throughout the system for lab result validation\n- Required for compliance with cannabis testing standards", + "operationId": "ReferenceLab-results-namesGet", + "responses": { + "200": { + "description": "Success - Returns array of strings with lab result names: `[\"string\", ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/regulatory-category": { + "get": { + "tags": ["RegulatoryCategory"], + "summary": "Get Regulatory Categories", + "description": "**Purpose:** Retrieves the complete list of regulatory categories available for the authenticated location for compliance reporting and state-mandated product classification.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of regulatory category objects: `[{ RegulatoryCategory }, ...]`\n- Array typically contains 5-20 regulatory categories per jurisdiction\n- Returns empty array `[]` if no regulatory categories configured (rare)\n- Includes category ID, name, and state-specific compliance codes\n- State-mandated product categories for regulatory reporting (varies by jurisdiction)\n- Results filtered to authenticated location's regulatory requirements\n\n**Common Use Cases:**\n- Validate product regulatory classification for compliance reporting\n- Generate state-mandated reports with proper category classifications\n- Ensure product data meets regulatory requirements for each jurisdiction\n- Support track-and-trace system integration with proper categorization\n- Populate regulatory category fields in product management systems\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Small dataset specific to location's regulatory jurisdiction\n- No pagination needed due to limited number of regulatory categories\n- Results may vary by location based on state/local regulations\n\n**Related Endpoints:**\n- `GET /product-category` - Get general product categories\n- `GET /products` - Get products with regulatory category assignments\n- `POST /product` - Create products with regulatory category classifications\n\n**Important Notes:**\n- Categories are specific to location's regulatory jurisdiction\n- Required for compliance with state cannabis regulations\n- Essential for accurate track-and-trace system reporting\n- Category requirements may change based on evolving regulations\n- Used for state-mandated reporting and audit compliance", + "operationId": "Regulatory-categoryGet", + "responses": { + "200": { + "description": "Success - Returns array of regulatory category objects: `[{ RegulatoryCategory }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RegulatoryCategory" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reporting/inventory": { + "get": { + "tags": ["Reporting"], + "operationId": "ReportingInventoryGet", + "parameters": [ + { + "name": "includeLabResults", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeRoomQuantities", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeAllocated", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "includeLineage", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportingInventoryItem" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/reporting/transactions": { + "get": { + "tags": ["Reporting"], + "summary": "Transactions List", + "description": "Retrieves POS and Wholesale transaction(s) from the provided dates and/or transactionId.\nThe use of transactionId, to/from transaction date, and to/from last modified date are mutually exclusive.\nProviding more than one will result in a validation error.\n\n**Performance & Limits:**\n- Rate limited to 600 requests per minute (higher limit for frequently accessed transaction data)\n- Optimized for transaction reporting and financial analysis workflows\n- Use date range filtering to limit result size for better performance", + "operationId": "ReportingTransactionsGet", + "parameters": [ + { + "name": "TransactionId", + "in": "query", + "description": "Specific transaction identifier for single transaction lookup.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "FromLastModifiedDateUTC", + "in": "query", + "description": "Start date for filtering transactions by last modified date (UTC) for incremental sync.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "ToLastModifiedDateUTC", + "in": "query", + "description": "End date for filtering transactions by last modified date (UTC) for incremental sync.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "FromDateUTC", + "in": "query", + "description": "Start date for filtering transactions by transaction date (UTC) for periodic reports.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "ToDateUTC", + "in": "query", + "description": "End date for filtering transactions by transaction date (UTC) for periodic reports.", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "IncludeDetail", + "in": "query", + "description": "Flag to include detailed transaction item information for comprehensive reporting.", + "schema": { + "type": "boolean" + } + }, + { + "name": "IncludeTaxes", + "in": "query", + "description": "Flag to include tax information for financial compliance reporting.", + "schema": { + "type": "boolean" + } + }, + { + "name": "IncludeOrderIds", + "in": "query", + "description": "Flag to include order identifiers for order fulfillment tracking.", + "schema": { + "type": "boolean" + } + }, + { + "name": "IncludeFeesAndDonations", + "in": "query", + "description": "Flag to include fees and donations for complete financial analysis.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Transaction" + } + } + } + } + }, + "400": { + "description": "Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResult" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + }, + "503": { + "description": "Temporarily disabled (kill switch)." + } + } + } + }, + "/reporting/customers": { + "get": { + "tags": ["Reporting"], + "summary": "Customers List (Reporting)", + "description": "**Purpose:** Retrieves a comprehensive list of wholesale and POS customers optimized for reporting and analytics.\n\n**Request Requirements:**\n- \"Reporting\" role authorization required for analytics data access\n- Optional UTC date parameters for filtering\n- No request body needed\n\n**Response Data:**\n- Response format: `[{ Customer }, { Customer }, ...]`\n- Array of `Customer` objects with complete customer information\n- Includes primary and secondary qualifying conditions for medical customers\n- Contains customer profile data, contact information, and preferences\n- Results are automatically filtered by the authenticated location\n\n**How This Differs from `/customer/customers`:**\n- Requires \"Reporting\" role instead of \"Customer\" role authorization\n- Optimized for reporting and analytics rather than operational management\n- Returns ALL customers for comprehensive reporting purposes\n- Enhanced date range filtering designed for reporting workflows\n- Performance tuned for bulk data export and analysis\n\n**Common Use Cases:**\n- Generate comprehensive customer reports and analytics\n- Export customer data for external systems or compliance requirements\n- Synchronize customer changes with external databases using incremental sync\n- Review customer records for regulatory compliance audits\n- Analyze customer demographics and behavior patterns for marketing\n\n**Performance & Limits:**\n- Rate limited to 600 requests per minute (higher limit for frequently accessed reporting data)\n- Use date range filtering to limit result size for better performance\n- Consider using `/reporting/customers-paginated` for very large datasets\n- Cache results locally and use incremental sync for regular updates\n- May return large datasets as it includes ALL customer types\n\n**Related Endpoints:**\n- `GET /reporting/customers-paginated` - Paginated version for large datasets\n- `GET /customer/customers` - Operational customer management endpoint\n\n**Important Notes:**\n- This endpoint returns ALL customers (wholesale and POS) and may return large datasets\n- Requires reporting authorization role for access\n- Use date filtering to improve performance with large customer bases", + "operationId": "ReportingCustomersGet", + "parameters": [ + { + "name": "fromLastModifiedDateUTC", + "in": "query", + "description": "Filter customers modified after this UTC date - Used for incremental sync", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "toLastModifiedDateUTC", + "in": "query", + "description": "Filter customers modified before this UTC date - Used for date range filtering", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "includeAnonymous", + "in": "query", + "description": "Include anonymous customers in results - Default: true", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of customer objects", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Customer" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for reporting access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reporting/customers-paginated": { + "get": { + "tags": ["Reporting"], + "summary": "Get Customers (Paginated, Reporting)", + "description": "**Purpose:** Retrieve paginated customer data optimized for reporting and analytics with enhanced performance for large-scale customer analysis.\n\n**Request Requirements:**\n- \"Reporting\" role authorization required for analytics data access\n- Optional query parameters for filtering and pagination control\n- No request body needed\n- Maximum page size of 10,000 customers for optimal performance\n\n**Response Data:**\n- Response format: `[{ Customer }, { Customer }, ...]`\n- Returns array of `Customer` objects for the requested page\n- Array contains up to PageSize customers (default 1000, max 10,000)\n- Returns empty array `[]` if no customers match criteria for the page (not null)\n- **No pagination metadata**: Response contains only customer data without total counts or page information\n- Includes primary and secondary qualifying conditions for medical customers\n- Contains customer profile data, contact information, and preferences\n- Results automatically filtered to authenticated location\n\n**Pagination Usage:**\n- **First Request**: Call with PageNumber=0 to get first page\n- **Subsequent Requests**: Increment PageNumber for each additional page\n- **End Detection**: Continue requesting pages until you receive an empty array `[]`\n- **Page Size Control**: Use PageSize parameter to control items per page (max 10,000)\n- **Example Flow**: Request PageNumber=0 → Process results → Increment PageNumber → Repeat until empty `[]` response\n\n**Key Differences from `/customer/customers-paginated`:**\n- **Authorization**: Requires \"Reporting\" role vs \"Customer\" role\n- **Purpose**: Optimized for reporting and analytics vs operational customer management\n- **Page Size**: Higher maximum page size limits for bulk reporting\n- **Profile Sharing**: Enhanced customer profile sharing logic for reporting\n- **Performance**: Designed for large-scale data export and analysis\n\n**Filtering Options:**\n- fromLastModifiedDateUTC: Returns customers modified after this date (incremental sync)\n- toLastModifiedDateUTC: Returns customers modified before this date (date range filtering)\n- includeAnonymous: Include anonymous customers in results (default: true)\n\n**Common Use Cases:**\n- Handle thousands of customers efficiently with paginated processing\n- Process customers in manageable chunks for batch operations\n- Avoid loading entire customer base at once for memory-conscious applications\n- Stream customer data for live reporting dashboards and analytics\n- Transfer customer data between systems in controlled batches\n\n**Performance & Limits:**\n- Maximum 10,000 customers per page for optimal performance\n- Start with PageNumber=0 and increment until no more data available\n- Use consistent PageSize throughout pagination sequence for efficiency\n- Monitor response times and adjust PageSize for optimal performance\n- Cache results locally to minimize API calls and improve responsiveness\n\n**Pagination Detection:**\n- **End of data detection**: Continue requesting pages until you receive an empty array `[]`\n- **No metadata provided**: Response does not include total counts, page counts, or hasNextPage indicators\n- **Sequential access**: Increment PageNumber from 0 until empty response indicates no more data\n\n**Related Endpoints:**\n- `GET /reporting/customers` - Non-paginated version for smaller datasets\n- `GET /customer/customers` - Operational customer management endpoint\n\n**Important Notes:**\n- **Pagination Required**: Large customer bases require multiple page requests\n- **Enhanced Profile Logic**: Uses advanced customer profile sharing based on LSP configuration\n- **Reporting Optimized**: Designed for analytics and large-scale data processing\n- **Location Scoped**: Results automatically filtered to authenticated location\n- **Page Size Validation**: Requests exceeding 10,000 customers per page will be rejected", + "operationId": "ReportingCustomers-paginatedGet", + "parameters": [ + { + "name": "fromLastModifiedDateUTC", + "in": "query", + "description": "Filter customers modified after this UTC date for incremental sync - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "toLastModifiedDateUTC", + "in": "query", + "description": "Filter customers modified before this UTC date for date range filtering - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "PageNumber", + "in": "query", + "description": "Page number for sequential pagination (integer, starts at 0) - Default: 0", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "PageSize", + "in": "query", + "description": "Number of items per page (integer) - Default: 1000, Maximum: 10000", + "schema": { + "type": "integer", + "format": "int32", + "default": 1000 + } + }, + { + "name": "includeAnonymous", + "in": "query", + "description": "Include anonymous customers in results - Default: true", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of customer objects for the requested page", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Customer" + } + } + } + } + }, + "400": { + "description": "Bad Request - `BadRequestResponse` object with `message` string field (check `propertyErrors`: null for simple message, array for field-specific errors)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for reporting access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reporting/register-adjustments": { + "get": { + "tags": ["Reporting"], + "summary": "Get Register Adjustments", + "description": "**Purpose:** Retrieve register adjustment transactions for cash management and reconciliation reporting with detailed audit trail information.\n\n**Request Requirements:**\n- \"Reporting\" role authorization required for financial data access\n- Optional query parameters for date range filtering\n- No request body needed\n\n**Response Data:**\n- Response format: `[{ RegisterAdjustment }, { RegisterAdjustment }, ...]`\n- Returns array of `RegisterAdjustment` objects with detailed transaction information\n- Array may contain 0 to 1,000+ adjustments depending on date range and activity\n- Returns empty array `[]` if no adjustments match criteria (not null)\n- Includes adjustment amounts, types, timestamps, and employee information\n- Contains reason codes and descriptions for each adjustment\n- Results automatically filtered to authenticated location\n\n**Transaction Types Included:**\n- **Adjustments**: Manual cash register corrections and balancing entries\n- **Close Outs**: End-of-shift register closing transactions\n- **Deposits**: Cash deposits made to the register\n- **Withdrawals**: Cash withdrawals from the register\n- **Cash Drops**: Safe drops and cash removal transactions\n\n**Filtering Options:**\n- fromLastModifiedDateUTC: Returns adjustments modified after this date (incremental sync)\n- toLastModifiedDateUTC: Returns adjustments modified before this date (date range filtering)\n\n**Common Use Cases:**\n- Track all register cash movements for balancing and reconciliation\n- Maintain detailed records of cash handling activities for audit trails\n- Generate end-of-shift cash management summaries and reports\n- Document cash handling for regulatory requirements and compliance\n- Analyze cash flow patterns and adjustment trends for financial analysis\n- Monitor unusual adjustment patterns or discrepancies for loss prevention\n\n**Performance & Limits:**\n- Use date range filtering to limit results to specific time periods for optimal performance\n- Combine with cash-summary endpoint for comprehensive cash reporting\n- Cache results locally and use incremental sync for regular updates\n- Optimized for financial reconciliation and audit trail workflows\n\n**Related Endpoints:**\n- `GET /reporting/register-transactions` - Complete register activity including sales\n- `GET /reporting/cash-summary` - Comprehensive cash reporting and summaries\n- `GET /reporting/closing-report` - Financial closing reports with cash details\n\n**Important Notes:**\n- **Adjustment Focus**: This endpoint focuses specifically on register adjustments only\n- **Complete Activity**: For complete register activity including sales, use register-transactions\n- **Audit Trail**: Maintains detailed records of all cash handling activities\n- **Location Scoped**: Results automatically filtered to authenticated location\n- **Employee Tracking**: Includes employee information for accountability and audit purposes", + "operationId": "ReportingRegister-adjustmentsGet", + "parameters": [ + { + "name": "fromLastModifiedDateUTC", + "in": "query", + "description": "Filter adjustments modified after this date for incremental sync - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "toLastModifiedDateUTC", + "in": "query", + "description": "Filter adjustments modified before this date for date range filtering - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of register adjustment objects", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RegisterAdjustment" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for reporting access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reporting/register-transactions": { + "get": { + "tags": ["Reporting"], + "summary": "Get Register Transactions (Comprehensive Transaction History)", + "description": "**Purpose:** Retrieve comprehensive register transaction history including sales, adjustments, cash management, and operational activities for complete financial reporting.\n\n**Request Requirements:**\n- \"Reporting\" role authorization required for financial transaction data access\n- Optional query parameters for date range filtering\n- No request body needed\n\n**Response Data:**\n- Response format: `[{ RegisterTransaction }, { RegisterTransaction }, ...]`\n- Returns array of `RegisterTransaction` objects with comprehensive transaction data\n- Array may contain 0 to 50,000+ transactions depending on date range and business volume\n- Returns empty array `[]` if no transactions match criteria (not null)\n- Includes financial details, customer information, product details, and employee tracking\n- Complete audit trail with timestamps, register context, and status information\n- Results automatically filtered to authenticated location\n\n**Transaction Types Included:**\n- **Sales Transactions**: Completed customer purchases and returns\n- **Register Adjustments**: Manual cash corrections and balance adjustments\n- **Cash Management**: Deposits, withdrawals, cash drops, and till operations\n- **Register Close-Outs**: End-of-shift register balancing and reconciliation\n- **Payment Processing**: Credit card, cash, and other payment method transactions\n- **Operational Activities**: Register opening, closing, and maintenance operations\n\n**Transaction Data Returned:**\n- **Financial Details**: Transaction amounts, payment methods, taxes, and fees\n- **Customer Information**: Customer IDs, types, and transaction associations\n- **Product Details**: Items sold, quantities, prices, and categories\n- **Employee Tracking**: Staff members who processed transactions\n- **Timestamps**: Creation, modification, and completion times\n- **Register Context**: Terminal/register identification and session information\n- **Status Information**: Transaction status, voiding, and modification history\n\n**Filtering Options:**\n- fromLastModifiedDateUTC: Returns transactions modified after this date (incremental sync)\n- toLastModifiedDateUTC: Returns transactions modified before this date (date range filtering)\n\n**Common Use Cases:**\n- Balance daily sales across all registers and payment methods for financial reconciliation\n- Generate comprehensive revenue reports and analytics for sales reporting\n- Maintain detailed transaction records for compliance and audit preparation\n- Track all cash movements and register balancing activities for cash management\n- Analyze sales patterns, employee performance, and business trends for performance analysis\n- Extract detailed tax information for regulatory compliance and tax reporting\n- Monitor transaction patterns for unusual activities and fraud prevention\n\n**Performance & Limits:**\n- Large datasets: This endpoint can return substantial amounts of transaction data\n- Use date range filtering to limit results for better performance\n- Use fromLastModifiedDateUTC for regular data synchronization and incremental sync\n- Schedule large data exports during low-traffic periods for optimal performance\n- Optimized for comprehensive financial reporting and audit trail requirements\n\n**Related Endpoints:**\n- `GET /reporting/register-adjustments` - Cash adjustments and corrections only\n- `GET /reporting/closing-report` - Summary financial reports for specific date ranges\n- `GET /reporting/cash-summary` - Cash-specific summaries and balancing information\n\n**Important Notes:**\n- **Comprehensive Data**: Returns ALL register activities, resulting in potentially large datasets\n- **Real-Time Updates**: Transaction data reflects current state and may include recent modifications\n- **Location Scoped**: Results automatically filtered to authenticated dispensary location\n- **Historical Accuracy**: Maintains complete audit trail for all register operations\n- **Complete Activity**: This is the most comprehensive endpoint for all register transaction types", + "operationId": "ReportingRegister-transactionsGet", + "parameters": [ + { + "name": "fromLastModifiedDateUTC", + "in": "query", + "description": "Filter transactions modified after this date for incremental sync - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "toLastModifiedDateUTC", + "in": "query", + "description": "Filter transactions modified before this date for date range filtering - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of RegisterTransaction objects with comprehensive transaction data", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RegisterTransaction" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for reporting access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reporting/cash-summary": { + "get": { + "tags": ["Reporting"], + "summary": "Get Cash Summary (Real-time Register Activity)", + "description": "**Purpose:** Retrieve real-time register cash activity summary with comprehensive financial reconciliation data for cash management and balancing.\n\n**Request Requirements:**\n- \"Reporting\" role authorization required for financial data access\n- Optional query parameters for date range filtering\n- Date range must be within the last 7 days for optimal performance\n- No request body needed\n\n**Response Data:**\n- Response format: `[{ RegisterCashSummary }, { RegisterCashSummary }, ...]`\n- Returns array of `RegisterCashSummary` objects with detailed cash flow information\n- Array may contain 1-50+ register summaries depending on number of active registers\n- Returns empty array `[]` if no cash activity matches criteria (not null)\n- Real-time data reflecting current register status and activities\n- Includes variance calculations and reconciliation details\n- Results automatically filtered to authenticated location\n\n**Summary Data Included:**\n- **Starting Balance**: Register opening cash amount for the period\n- **Ending Balance**: Current or closing register cash amount\n- **Sales**: Total cash sales transactions processed\n- **Returns**: Cash refunds and return transactions\n- **Deposits**: Cash deposits added to the register\n- **Adjustments**: Manual cash corrections and modifications\n- **Over/Short**: Cash variance from expected amounts\n\n**Filtering Options:**\n- fromLastModifiedDateUTC: Returns activity after this date (incremental sync, within 7 days)\n- toLastModifiedDateUTC: Returns activity before this date (date range filtering)\n\n**Common Use Cases:**\n- Track current register cash status throughout the day for real-time monitoring\n- Balance register cash at shift changes for reconciliation\n- Generate end-of-day cash summaries for closing procedures\n- Identify and investigate cash discrepancies for variance analysis\n- Create comprehensive cash flow reports for financial reporting\n- Maintain detailed cash handling records for audit preparation\n\n**Performance & Limits:**\n- Rate limited to 480 requests per minute (higher limit for frequent cash monitoring)\n- Date range restriction: fromLastModifiedDateUTC must be within the last 7 days\n- Use recent date ranges (within 7 days) for fastest response times\n- Combine with register-adjustments endpoint for detailed transaction breakdown\n- Cache results and refresh periodically for dashboard applications\n- Optimized for real-time cash monitoring and reconciliation workflows\n\n**Related Endpoints:**\n- `GET /reporting/register-adjustments` - Detailed transaction breakdown\n- `GET /reporting/register-transactions` - Complete register transaction history\n- `GET /reporting/closing-report` - Comprehensive financial closing reports\n\n**Important Notes:**\n- **Real-time Data**: Provides real-time data and may show different results than historical reports during active business hours\n- **7-Day Limit**: Date filtering restricted to last 7 days for optimal performance\n- **Active Business Hours**: Results may vary during active operations due to real-time updates\n- **Location Scoped**: Results automatically filtered to authenticated location\n- **Variance Tracking**: Includes over/short calculations for cash discrepancy identification", + "operationId": "ReportingCash-summaryGet", + "parameters": [ + { + "name": "fromLastModifiedDateUTC", + "in": "query", + "description": "Filter activity after this date (must be within last 7 days) - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "toLastModifiedDateUTC", + "in": "query", + "description": "Filter activity before this date for date range filtering - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of register cash summary objects", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RegisterCashSummary" + } + } + } + } + }, + "400": { + "description": "Bad Request - String error message (parse response body as plain text)", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for reporting access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reporting/loyalty-snapshot": { + "get": { + "tags": ["Reporting"], + "summary": "Get Loyalty Balance Snapshot (Daily)", + "description": "**Purpose:** Retrieve current loyalty point balances for all customers with nightly batch processing for comprehensive loyalty program reporting and analysis.\n\n**Request Requirements:**\n- \"Reporting\" role authorization required for loyalty data access\n- No query parameters required\n- No request body needed\n- Rate limited to 1 request per minute for system protection\n\n**Response Data:**\n- Response format: `[{ LoyaltySnapshot }, { LoyaltySnapshot }, ...]`\n- Returns array of `LoyaltySnapshot` objects with customer loyalty information\n- Array typically contains 100-10,000+ customers depending on loyalty program participation\n- Returns empty array `[]` if no customers have loyalty activity (not null)\n- Includes current point balances, loyalty tier information, and customer identifiers\n- Contains earned points, redeemed points, and available balance details\n- Results automatically filtered to authenticated location\n\n**Data Characteristics:**\n- **Update Frequency**: Nightly batch processing (updated once per day)\n- **Data Freshness**: Reflects loyalty activity through the previous business day\n- **Scope**: All customers with loyalty program participation\n- **Balance Types**: Current available points, earned points, redeemed points\n- **Configuration**: Uses either loyalty ledger service or database depending on system configuration\n\n**Common Use Cases:**\n- Generate end-of-day loyalty summaries for daily loyalty reports\n- Check customer loyalty balances and history for customer service\n- Identify customers by loyalty tier or balance ranges for marketing campaigns\n- Document loyalty program activity for audits and compliance reporting\n- Export loyalty data to external systems for data synchronization\n- Analyze loyalty program engagement and effectiveness for analytics\n\n**Consumption Guidelines:**\n- **Recommended Frequency**: Once per day (after nightly processing completes)\n- **Optimal Timing**: Early morning hours after batch processing\n- **Caching Strategy**: Cache results for 24 hours, refresh daily\n\n**Performance & Limits:**\n- Rate limited to 1 request per minute for system protection\n- Schedule automated calls during off-peak hours for optimal performance\n- Cache results locally to avoid repeated calls within the same day\n- Use for batch processing rather than real-time customer lookups\n- Optimized for daily loyalty program management and reporting workflows\n\n**Related Endpoints:**\n- `GET /reporting/customer-loyalty-snapshot` - Individual customer loyalty data\n- `GET /reporting/loyalty-transactions-paginated` - Detailed loyalty transaction history\n- `GET /reporting/national-loyalty-snapshot-paginated` - Cross-organization loyalty data\n\n**Important Notes:**\n- **Snapshot Data**: This is a snapshot of loyalty balances as of the last nightly processing\n- **Real-time Alternative**: For real-time loyalty transactions, use other loyalty endpoints\n- **Nightly Processing**: Data reflects activity through the previous business day\n- **Location Scoped**: Results filtered to authenticated location loyalty participants\n- **Rate Limited**: Maximum 1 request per minute to protect system resources", + "operationId": "ReportingLoyalty-snapshotGet", + "responses": { + "200": { + "description": "Success - Returns array of loyalty balance snapshot objects", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LoyaltySnapshot" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for reporting access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reporting/products": { + "get": { + "tags": ["Reporting"], + "summary": "Get Products (Master List, Reporting)", + "description": "**Purpose:** Retrieve the complete product master list with comprehensive product data for reporting and analytics, including all products regardless of API or online availability settings.\n\n**Request Requirements:**\n- \"Reporting\" role authorization required for comprehensive product data access\n- Optional query parameters for incremental sync filtering\n- No request body needed\n\n**Response Data:**\n- Response format: `[{ ProductDetail }, { ProductDetail }, ...]`\n- Returns array of `ProductDetail` objects with complete product information\n- Array typically contains 100-50,000+ products depending on catalog size\n- Returns empty array `[]` if no products exist or match criteria (not null)\n- Includes ALL products in the system (active and inactive)\n- Contains pricing, categories, strains, lab results, and inventory data\n- Results automatically filtered to authenticated location\n\n**Key Differences from `/products`:**\n- **No API Access Filter**: Returns ALL products, not just those enabled for API access\n- **No Online Filter**: Ignores online availability settings used by standard products endpoint\n- **Master Data Focus**: Designed for comprehensive product data exports and reporting\n- **Complete Dataset**: Includes inactive and non-public products for complete catalog view\n\n**Filtering Options:**\n- fromLastModifiedDateUTC: Returns products modified after this date (incremental sync)\n\n**Common Use Cases:**\n- Get complete product catalog for analysis and comprehensive reporting\n- Export all product data for external systems and data warehousing\n- Review all products regardless of API/online settings for inventory audits\n- Maintain complete product records for master data management\n- Generate reports including all products for compliance reporting\n\n**When to Use This vs `/products`:**\n- **Use `/reporting/products`**: For complete data exports, reporting, audits, and analytics\n- **Use `/products`**: For e-commerce, POS integration, and customer-facing applications\n\n**Performance & Limits:**\n- Large datasets: This endpoint can return substantial product catalogs\n- Use fromLastModifiedDateUTC for incremental sync to optimize performance\n- Optimized for comprehensive product reporting and analytics workflows\n- Consider pagination for very large product catalogs (50,000+ products)\n\n**Related Endpoints:**\n- `GET /products` - Customer-facing products with API and online filters\n- `GET /inventory` - Product inventory levels and availability\n- `GET /product-categories` - Product categorization data\n\n**Important Notes:**\n- **Complete Dataset**: Returns ALL products, including those not intended for public API access or online sales\n- **Master Data**: This is the authoritative source for complete product catalog data\n- **Reporting Focus**: Designed for analytics and reporting rather than customer-facing operations\n- **Location Scoped**: Results filtered to authenticated location product catalog\n- **Incremental Sync**: Use date filtering for efficient data synchronization", + "operationId": "ReportingProductsGet", + "parameters": [ + { + "name": "fromLastModifiedDateUTC", + "in": "query", + "description": "Filter products modified after this date for incremental sync - Optional", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProductDetail" + } + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/reporting/closing-report": { + "get": { + "tags": ["Reporting"], + "summary": "Get Closing Report (Comprehensive Financial Summary)", + "description": "**Purpose:** Retrieve comprehensive closing report with detailed financial summaries, payment breakdowns, and business analytics for specified date range reporting.\n\n**Request Requirements:**\n- \"Reporting\" role authorization required for financial data access\n- fromDateUTC and toDateUTC parameters required (both must be provided)\n- Date range must be between 12 hours and 31 days maximum\n- UTC datetime format required for all date parameters\n\n**Response Data:**\n- Response format: `{ ClosingReport }` or `{ ClosingReportV2 }` (structure varies by system configuration)\n- Returns `ClosingReport` or `ClosingReportV2` object with comprehensive financial data\n- Single object containing multi-dimensional analysis across all business aspects\n- Not an array - returns one comprehensive report object for the date range\n- Multi-dimensional analysis across payment methods, customer types, and product categories\n- Detailed tax calculations and compliance information\n- Payment processor-specific data and settlement details\n- Results automatically filtered to authenticated location\n\n**Date Range Restrictions:**\n- **Maximum Range**: 31 days or less\n- **Minimum Range**: Greater than 12 hours\n- **Format**: UTC datetime values\n- **Both Required**: fromDateUTC and toDateUTC must be provided\n\n**Report Sections Included:**\n- **Payment Summary**: Breakdown by payment method (cash, card, etc.)\n- **Customer Type Summary**: Sales analysis by customer categories\n- **Category Summary**: Revenue breakdown by product categories\n- **Tax Summary**: Detailed tax calculations and rates\n- **Order Source Summary**: Sales by channel (online, in-store, etc.)\n- **Order Type Summary**: Analysis by order types (delivery, pickup, etc.)\n- **Fees & Donations**: Processing fees and charitable donations (when enabled)\n- **Pay-by-Bank Details**: ACH transaction summaries and batch files (when enabled)\n\n**Response Version Determination:**\n- Response structure varies based on internal system configuration\n- **V1 (ClosingReport)**: Standard financial summaries without tips/fees\n- **V2 (ClosingReportV2)**: Enhanced with tips, fees, and Pay-by-Bank details\n- **API Consumer Guidance**: Both versions share common base fields, V2 extends V1 with additional properties\n- **Breaking Change Protection**: V2 is additive-only (safe to parse as V1 and ignore extra fields)\n\n**Handling Variable Response Types:**\n- **Recommended Approach**: Parse response for common fields first, then check for V2-specific properties\n- **Common Base Properties**: All versions include PaymentSummary, CustomerTypeSummary, CategorySummary, TaxSummary\n- **V2 Additional Properties**: TipsSummary, FeesSummary, PayByBankDetails (when present)\n\n**Common Use Cases:**\n- Generate end-of-period financial summaries for daily/weekly closing\n- Balance sales across all payment methods and channels for financial reconciliation\n- Extract detailed tax information for compliance and tax reporting\n- Analyze sales performance across multiple dimensions for business analytics\n- Reconcile payment processor settlements for payment processing\n- Generate comprehensive financial documentation for audit preparation\n\n**Performance & Limits:**\n- This report processes large amounts of transactional data\n- Longer date ranges may take additional time to generate\n- Use shorter date ranges for faster processing\n- Schedule report generation during off-peak hours for optimal performance\n- Cache results for frequently accessed date ranges\n\n**Related Endpoints:**\n- `GET /reporting/register-transactions` - Detailed transaction-level data\n- `GET /reporting/cash-summary` - Cash-specific summaries\n- `GET /reporting/register-adjustments` - Register adjustment details\n\n**Important Notes:**\n- **Processing Intensive**: This report processes large amounts of transactional data\n- **Date Range Validation**: Requests with invalid date ranges will be rejected\n- **Comprehensive Data**: Includes all financial aspects of business operations\n- **Location Scoped**: Results filtered to authenticated location financial data\n- **Version Dependent**: Response object type depends on system configuration and features enabled", + "operationId": "ReportingClosing-reportGet", + "parameters": [ + { + "name": "fromDateUTC", + "in": "query", + "description": "Start date for the report period (required) - Must be UTC datetime", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "toDateUTC", + "in": "query", + "description": "End date for the report period (required) - Must be UTC datetime", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns comprehensive closing report object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClosingReportV2" + } + } + } + }, + "400": { + "description": "Bad Request - String error message (parse response body as plain text)", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for reporting access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/reporting/discounts": { + "get": { + "tags": ["Reporting"], + "summary": "Get Discounts (Complete Discount Configuration)", + "description": "**Purpose:** Retrieve comprehensive discount configuration data for all discounts regardless of status, type, or activation state for promotional reporting and analysis.\n\n**Request Requirements:**\n- \"Reporting\" role authorization required for discount configuration data access\n- Optional query parameter for including deleted discounts\n- No request body needed\n\n**Response Data:**\n- Response format: `[{ ReportingDiscountDetail }, { ReportingDiscountDetail }, ...]`\n- Returns array of `ReportingDiscountDetail` objects with complete discount configurations\n- Array typically contains 5-500+ discounts depending on promotional activity\n- Returns empty array `[]` if no discounts exist (not null)\n- Includes all restriction types and eligibility criteria\n- Contains scheduling and recurrence information\n- Provides location-specific applicability data\n- Results automatically filtered to authenticated location\n\n**Unique Endpoint:** This is the only discounts endpoint in the Public API - there is no parallel non-reporting version.\n\n**Filtering Options:**\n- includeDeleted: Include deleted/archived discounts in results (default: false)\n\n**Discount Information Included:**\n- **Basic Details**: Discount names, descriptions, and identifiers\n- **Status Information**: Active/inactive status and deletion state\n- **Type Classification**: Manual vs automatic discount types\n- **Validity Periods**: Start and end dates (converted to UTC)\n- **Discount Groups**: Associated discount group memberships\n- **Product Restrictions**: Specific products eligible for the discount\n- **Category Restrictions**: Product categories covered by the discount\n- **Strain Restrictions**: Cannabis strain-specific discount rules\n- **Brand Restrictions**: Brand-specific discount applications\n- **Vendor Restrictions**: Vendor-specific discount configurations\n- **Weekly Recurrence**: Recurring discount schedule information\n- **Location Mapping**: Multi-location discount applicability\n\n**Common Use Cases:**\n- Analyze discount effectiveness and usage patterns for discount analysis\n- Export complete discount configurations for configuration backup\n- Document promotional activities for regulatory review and compliance reporting\n- Synchronize discount rules with external systems for system integration\n- Review existing promotions for campaign planning and marketing planning\n- Maintain comprehensive records of all promotional activities for audit preparation\n\n**Performance & Limits:**\n- Use includeDeleted=false for active discount analysis to optimize performance\n- Cache results locally as discount configurations change infrequently\n- Process restriction arrays to understand discount eligibility logic\n- Optimized for promotional reporting and marketing analysis workflows\n\n**Related Endpoints:**\n- `GET /reporting/closing-report` - Financial impact of discount usage\n- `GET /reporting/register-transactions` - Transaction-level discount application\n- `GET /products` - Products eligible for discount restrictions\n\n**Important Notes:**\n- **Complete Configuration**: Returns ALL discount configurations including inactive and deleted discounts when requested\n- **Use Filtering**: Use includeDeleted parameter appropriately for your use case\n- **UTC Conversion**: All validity periods are automatically converted to UTC\n- **Location Scoped**: Results filtered to authenticated location discount configurations\n- **Unique Endpoint**: This is the only public API endpoint for discount data access", + "operationId": "ReportingDiscountsGet", + "parameters": [ + { + "name": "includeDeleted", + "in": "query", + "description": "Include deleted/archived discounts in results - Default: false", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of comprehensive discount configuration objects", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReportingDiscountDetail" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for reporting access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/room/rooms": { + "get": { + "tags": ["Room"], + "summary": "Get Rooms", + "description": "**Purpose:** Retrieve cultivation rooms and facility areas configured for the location to support cultivation operations and facility management.\n\n**Request Requirements:**\n- \"Room\" role authorization required for room data access\n- Optional filtering parameters available for specific room lookup\n- Cultivation facility management permissions required\n\n**Response Data:**\n- Returns array of `Room` objects with room identification and type information\n- Array typically contains 5-50 rooms depending on cultivation facility size\n- Returns empty array `[]` if no rooms match criteria (not null)\n- Includes room identification, naming, and functional type flags\n- Results automatically filtered to authenticated location\n\n**Filtering Options:**\n- **roomId**: Optional integer parameter to retrieve specific room by ID\n- **roomName**: Optional string parameter to search rooms by name\n- **Combined Filtering**: Parameters can be used together for precise room lookup\n- **No Filters**: Returns all rooms when no parameters provided\n\n**Room Information Included:**\n- **RoomId**: Unique identifier for each cultivation room or facility area\n- **RoomName**: Human-readable name for room identification and management\n- **Location Information**: Facility location details (when integrator is Dutchie)\n- **Room Type Flags**: Boolean flags indicating room functionality (IsQuarantineRoom, IsVaultRoom, IsSalesFloor, etc.)\n\n**Common Use Cases:**\n- Populate room dropdown lists in cultivation management interfaces\n- Display available rooms for plant placement and cultivation tracking\n- Support cultivation facility room management and organization\n- Enable room-specific cultivation tracking and environmental monitoring\n- Facilitate cultivation workflow room assignments and plant movement\n\n**Performance & Limits:**\n- Efficient room lookup optimized for cultivation facility workflows\n- Optimized database queries for improved performance\n- Flexible filtering for specific room management needs\n- Results consistent across cultivation and facility management systems\n\n**Related Endpoints:**\n- `POST /room` - Create or update room configuration\n- `GET /plant` - View plants assigned to specific cultivation rooms\n- `GET /harvest` - Track harvest operations by cultivation room\n\n**Important Notes:**\n- **Cultivation Integration**: Essential for cultivation facility management and plant tracking\n- **Location Specific**: Results filtered to authenticated location facility setup\n- **Integrator Dependent**: Location information visibility controlled by integrator type\n- **Cultivation Ready**: Room data used throughout cultivation tracking workflows", + "operationId": "RoomRoomsGet", + "parameters": [ + { + "name": "roomId", + "in": "query", + "description": "Optional room ID for specific room lookup - integer", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "roomName", + "in": "query", + "description": "Optional room name for searching rooms by name - string", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of room objects: `[{ Room }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Room" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for room access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/room": { + "post": { + "tags": ["Room"], + "summary": "Create or Update Room", + "description": "**Purpose:** Create a new cultivation room or update an existing room configuration for cultivation facility management and plant tracking operations.\n\n**Request Requirements:**\n- \"Room\" role authorization required for room data modification\n- `Room` object in request body with room configuration details\n- Content-Type: application/json\n- Cultivation facility management permissions required\n\n**Response Data:**\n- Returns single `Room` object (not array) with updated room information\n- Includes assigned RoomId for new rooms or updated ID for existing rooms\n- Complete room information with all fields populated\n- Room identification, naming, and type flag information\n\n**Create vs Update Behavior:**\n- **CREATE**: When RoomId is null or 0, a new room record will be created\n- **UPDATE**: When RoomId is provided with a valid room ID, the existing room will be updated\n- **Identification**: Room existence determined by RoomId value\n- **Automatic Detection**: System automatically determines create vs update based on RoomId\n\n**Room Data Fields:**\n- **RoomId**: Unique identifier for room (null/0 for new rooms, specific ID for updates)\n- **RoomName**: Human-readable name for room identification and cultivation tracking\n- **Room Type Flags**: Boolean indicators for room functionality (IsQuarantineRoom, IsVaultRoom, etc.)\n\n**Common Use Cases:**\n- Add new cultivation rooms to facility management system\n- Update existing room names or configuration details\n- Modify room setup for cultivation facility reorganization\n- Create room assignments for cultivation tracking workflows\n- Support cultivation facility expansion and room management\n\n**Performance & Limits:**\n- Single room operation for targeted cultivation facility management\n- Immediate room configuration update reflected in cultivation systems\n- Optimized for cultivation facility management and plant tracking workflows\n- Changes reflected immediately in room assignment and cultivation systems\n\n**Related Endpoints:**\n- `GET /room/rooms` - Retrieve existing room configuration before updates\n- `GET /plant` - View plants assigned to cultivation rooms\n- `POST /plant/nonsts/update` - Update plant room assignments\n\n**Important Notes:**\n- **RoomId Assignment**: New rooms receive automatically generated RoomId\n- **Cultivation Integration**: Room configuration affects plant tracking and cultivation workflows\n- **Location Scoped**: Rooms automatically associated with authenticated location\n- **Cultivation Ready**: Room data immediately available for plant assignment operations\n- **Facility Management**: Supports cultivation facility organization and room tracking", + "operationId": "RoomPost", + "requestBody": { + "description": "Room information to create or update - Room object with RoomId, RoomName, and room type flags", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/Room" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Room" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Room" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Room" + } + } + }, + "x-bodyName": "room" + }, + "responses": { + "200": { + "description": "Success - Returns single room object: `{ Room }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Room" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for room modification" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/sizes": { + "get": { + "tags": ["Size"], + "summary": "Get Product Sizes", + "description": "**Purpose:** Retrieves the complete list of product sizes available for the authenticated organization for product configuration and inventory management.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of size objects: `[{ Size }, ...]`\n- Response format: `[{ Size }, { Size }, ...]`\n- Example: `[{ \"SizeId\": 1, \"SizeName\": \"1g\", \"Description\": \"One gram flower package\" }, { \"SizeId\": 2, \"SizeName\": \"3.5g\", \"Description\": \"Eighth ounce flower package\" }, ...]`\n- Array typically contains 15-40 product sizes per organization\n- Returns empty array `[]` if no sizes configured (rare)\n- Includes size ID, name, and measurement details\n- Standard product sizes (grams, ounces, units, etc.) for cannabis products\n- Results filtered to authenticated organization level\n\n**Common Use Cases:**\n- Populate product size dropdown lists in product creation forms\n- Configure product variants with different size options\n- Support inventory management with size-based tracking\n- Generate size-specific pricing and inventory reports\n- Enable e-commerce product configuration with size selections\n\n**Performance & Limits:**\n- Lightweight reference data optimized for frequent access\n- Small dataset suitable for client-side caching\n- No pagination needed due to limited number of standard sizes\n- Results consistent across all locations within organization\n\n**Related Endpoints:**\n- `GET /products` - Get products that use these size configurations\n- `POST /product` - Create products with size assignments\n- `GET /inventory` - Get inventory levels by product size\n\n**Important Notes:**\n- Sizes are defined at organization level (LSP) not location level\n- Standard cannabis industry size configurations for consistency\n- Used for product configuration and inventory tracking\n- Essential reference data for product and pricing management\n- Supports both weight-based and unit-based product sizing", + "operationId": "SizesGet", + "responses": { + "200": { + "description": "Success - Returns array of size objects: `[{ Size }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Size" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/strains": { + "post": { + "tags": ["Strains"], + "operationId": "StrainsPost", + "requestBody": { + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/UpdateStrain" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStrain" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStrain" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdateStrain" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StrainDetail" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "get": { + "tags": ["Strains"], + "summary": "Get Strains", + "description": "**Purpose:** Retrieves all cannabis strains available for the authenticated location with genetic and classification information.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for strain data access\n- No query parameters or request body needed\n\n**Response Data:**\n- Response format: `[{ StrainDetail }, { StrainDetail }, ...]`\n- Array typically contains 10-100 strains per location\n- Returns empty array `[]` if no strains configured for location\n- Results automatically filtered to authenticated location\n- See `StrainDetail` model for complete field descriptions\n\n**Data Filtering:**\n- Results are automatically scoped to the authenticated location\n- Only active strains are included in the response\n- Strain types include full classification information for categorization\n\n**Common Use Cases:**\n- Populate strain dropdown lists in product creation and editing forms\n- Display available strain genetics for product categorization and filtering\n- Synchronize strain catalog with external inventory management systems\n- Generate strain-specific compliance reports and analytics\n- Support product menu organization by genetic type and characteristics\n- Cache strain data for offline product creation workflows\n\n**Performance & Limits:**\n- Lightweight data optimized for frequent access and caching\n- Typically small dataset (10-100 strains) suitable for client-side storage\n- No pagination needed due to manageable strain catalog sizes per location\n- Response time typically under 50ms for standard strain catalogs\n- Safe for frequent polling (recommended: cache for 5-10 minutes)\n\n**Integration Patterns:**\n- **UI Dropdowns**: Cache response locally for form population\n- **Product Creation**: Use strain IDs for product categorization\n- **External Sync**: Compare ExternalId values for third-party integration\n- **Menu Display**: Filter products by strain type and characteristics\n\n**Related Endpoints:**\n- `POST /strains` - Create or update strain information in this catalog\n- `GET /strains/types` - Get valid strain type classifications for filtering\n\n**Important Notes:**\n- Strain catalog is location-specific and varies by dispensary\n- External ID values enable synchronization with cultivation management systems\n- Strain information directly affects product categorization and compliance reporting", + "operationId": "StrainsGet", + "responses": { + "200": { + "description": "Success - Returns array of strain objects: `[{ StrainDetail }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StrainDetail" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for inventory access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/strains/types": { + "get": { + "tags": ["Strains"], + "summary": "Get Strain Types", + "description": "**Purpose:** Retrieves the list of valid strain type classifications for cannabis strain categorization.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for strain data access\n- No query parameters or request body needed\n\n**Response Data:**\n- Response format: `[string, string, string, string]`\n- Example: `[\"Indica\", \"Sativa\", \"Hybrid\", \"CBD\"]`\n- Returns available strain type classifications\n- Includes standard classifications: Indica, Sativa, Hybrid, CBD\n- Reference data for strain type validation\n\n**Common Use Cases:**\n- Validate strain type values before creating or updating strains\n- Populate strain type dropdown lists in user interfaces\n- Reference data for strain classification validation\n- Support product categorization by genetic type\n- Ensure consistency in strain type terminology\n\n**Performance & Limits:**\n- Reference data with immediate response\n- Small dataset suitable for frequent caching\n- No location filtering needed for standard classifications\n- Consistent across all locations and organizations\n\n**Related Endpoints:**\n- `POST /strains` - Create or update strains (validates against these types)\n- `GET /strains` - Get all strains with their assigned types\n\n**Important Notes:**\n- These are the only valid values accepted for strain type in strain creation/updates\n- Values are case-sensitive when used in strain operations\n- Standard cannabis industry classifications for genetic types\n- Used for product menu organization and customer filtering", + "operationId": "StrainsTypesGet", + "responses": { + "200": { + "description": "Success - Returns array of strings with strain type names: `[\"Indica\", \"Sativa\", \"Hybrid\", \"CBD\"]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for inventory access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/table/tables": { + "get": { + "tags": ["Table"], + "summary": "Get Tables", + "description": "**Purpose:** Retrieve dining tables or seating areas configured for the location to support hospitality operations and table management.\n\n**Request Requirements:**\n- \"Room\" role authorization required for table data access\n- Optional filtering parameters available for specific table lookup\n- Table management permissions for hospitality operations\n\n**Response Data:**\n- Returns array of `Table` objects with table identification details\n- Array typically contains 10-100 tables depending on hospitality operation size\n- Returns empty array `[]` if no tables match criteria (not null)\n- Includes table identification and naming information (TableId, TableName)\n- Results automatically filtered to authenticated location\n\n**Filtering Options:**\n- **tableId**: Optional integer parameter to retrieve specific table by ID\n- **tableName**: Optional string parameter to search tables by name\n- **Combined Filtering**: Parameters can be used together for precise table lookup\n- **No Filters**: Returns all tables when no parameters provided\n\n**Table Information Included:**\n- **TableId**: Unique identifier for each dining table or seating area\n- **TableName**: Human-readable name for table identification and assignment\n\n**Common Use Cases:**\n- Populate table dropdown lists in reservation and seating management\n- Display available tables for customer seating assignments\n- Support hospitality operation table management and configuration\n- Enable table-specific service tracking and order management\n- Facilitate dining room management and table allocation workflows\n\n**Performance & Limits:**\n- Efficient table lookup optimized for hospitality operation workflows\n- Flexible filtering for specific table management needs\n- No pagination needed for typical table counts per location\n- Results consistent across hospitality and service management systems\n\n**Related Endpoints:**\n- `POST /table` - Create or update table configuration\n- `GET /guest-list` - View guest check-ins by table assignments\n- `POST /transaction` - Process transactions linked to table service\n\n**Important Notes:**\n- **Hospitality Integration**: Essential for dining room management and table service\n- **Table Management**: Supports table configuration and seating assignments\n- **Location Specific**: Results filtered to authenticated location table setup\n- **Service Ready**: Table data used throughout hospitality service workflows\n- **Flexible Lookup**: Multiple filtering options for precise table management", + "operationId": "TableTablesGet", + "parameters": [ + { + "name": "tableId", + "in": "query", + "description": "Optional table ID for specific table lookup - integer", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "tableName", + "in": "query", + "description": "Optional table name for searching tables by name - string", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of table objects: `[{ Table }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Table" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for table access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/table": { + "post": { + "tags": ["Table"], + "summary": "Create or Update Table", + "description": "**Purpose:** Create a new dining table or update an existing table configuration for hospitality operations and seating management.\n\n**Request Requirements:**\n- \"Room\" role authorization required for table data modification\n- `Table` object in request body with table information\n- Content-Type: application/json\n- Table management permissions for hospitality operations\n\n**Response Data:**\n- Returns single `Table` object (not array) with updated table information\n- Includes assigned TableId for new tables or updated ID for existing tables\n- Complete table information with all fields populated (TableId, TableName)\n- Table identification and naming information\n\n**Create vs Update Behavior:**\n- **CREATE**: When TableId is null or 0, a new table record will be created\n- **UPDATE**: When TableId is provided with a positive integer, the existing table will be updated\n- **Identification**: Table existence determined by TableId value (null/0 = create, positive = update)\n- **Automatic Detection**: System automatically determines create vs update based on TableId\n\n**Table Data Fields:**\n- **TableId**: Unique identifier for table (null/0 for new tables, positive integer for updates)\n- **TableName**: Human-readable name for table identification and assignment\n\n**Common Use Cases:**\n- Add new dining tables to hospitality seating configuration\n- Update existing table names or configuration details\n- Modify table setup for dining room reorganization\n- Create table assignments for hospitality service workflows\n- Support dining room management and table allocation systems\n\n**Performance & Limits:**\n- Single table operation for targeted table management\n- Immediate table configuration update reflected in hospitality systems\n- Optimized for dining room management and seating workflows\n- Changes reflected immediately in table assignment and service systems\n\n**Related Endpoints:**\n- `GET /table/tables` - Retrieve existing table configuration before updates\n- `GET /guest-list` - View guest check-ins that use table assignments\n- `POST /transaction` - Process transactions linked to table service\n\n**Important Notes:**\n- **TableId Assignment**: New tables receive automatically generated TableId\n- **Hospitality Integration**: Table configuration affects seating and service workflows\n- **Location Scoped**: Tables automatically associated with authenticated location\n- **Service Ready**: Table data immediately available for hospitality operations\n- **Configuration Management**: Supports dining room setup and table organization", + "operationId": "TablePost", + "requestBody": { + "description": "Table information to create or update - Table object with TableId and TableName fields", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/Table" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Table" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Table" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Table" + } + } + }, + "x-bodyName": "table" + }, + "responses": { + "200": { + "description": "Success - Returns single table object: `{ Table }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Table" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for table modification" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/tag": { + "get": { + "tags": ["Tag"], + "summary": "Get Tags", + "description": "**Purpose:** Retrieve all inventory tracking tags available for the location to support inventory management and regulatory compliance tracking.\n\n**Request Requirements:**\n- \"Inventory\" role authorization required for tag data access\n- No query parameters or request body needed\n- Inventory management permissions for tag tracking operations\n\n**Response Data:**\n- Returns array of `Tag` objects with tag identification information\n- Array typically contains 100-10,000 tags depending on facility operation size\n- Returns empty array `[]` if no tags are available (not null)\n- Includes tag names and unique identifiers for inventory assignment\n- Results automatically filtered to authenticated service provider level\n\n**Tag Information Included:**\n- **TagId**: Unique numeric identifier for each tag\n- **TagName**: Human-readable name or label for the tag\n- **Assignment Ready**: Tag information available for inventory assignment operations\n\n**Common Use Cases:**\n- Populate tag dropdown lists in inventory management interfaces\n- Display available tags for plant and package assignment workflows\n- Support inventory tracking and regulatory compliance operations\n- Enable tag allocation and assignment for cultivation and retail workflows\n- Facilitate state system integration and regulatory reporting requirements\n\n**Performance & Limits:**\n- Comprehensive tag data retrieval for inventory management\n- Service provider level tag access for facility operations\n- Optimized for inventory tracking and compliance workflows\n- Results include all available tags for assignment and tracking\n\n**Related Endpoints:**\n- `POST /package/set-tags` - Assign tags to inventory packages\n- `POST /package/add-tags` - Add additional tags to packages\n- `POST /package/remove-tags` - Remove tags from inventory packages\n\n**Important Notes:**\n- **Compliance Critical**: Essential for regulatory compliance and state system integration\n- **Inventory Integration**: Tag data used throughout inventory tracking workflows\n- **Service Provider Scoped**: Tags filtered to authenticated service provider level\n- **Assignment Ready**: Tag data immediately available for inventory assignment operations\n- **Regulatory Tracking**: Tags support state system compliance and audit requirements", + "operationId": "TagGet", + "responses": { + "200": { + "description": "Success - Returns array of tag objects: `[{ Tag }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Tag" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for inventory access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/terminals": { + "get": { + "tags": ["Terminals"], + "summary": "Get Terminals", + "description": "**Purpose:** Retrieve all point-of-sale terminals configured for the location to support transaction processing and retail operations.\n\n**Request Requirements:**\n- Valid API key authentication required for terminal data access\n- No specific role restrictions beyond authentication\n- No query parameters or request body needed\n\n**Response Data:**\n- Returns array of `Terminal` objects with terminal identification information\n- Response format: `[{ Terminal }, { Terminal }, ...]`\n- Array typically contains 1-10 terminals depending on retail operation size\n- Returns empty array `[]` if no terminals are configured (not null)\n- Includes terminal identification and naming information only\n- Results automatically filtered to authenticated location\n\n**Terminal Information Included:**\n- **TerminalId**: Unique numeric identifier for each point-of-sale terminal\n- **TerminalName**: Human-readable name for terminal identification\n\n**Common Use Cases:**\n- Populate terminal dropdown lists in transaction processing interfaces\n- Display available terminals for cashier assignment and management\n- Support point-of-sale system configuration and setup\n- Enable terminal-specific transaction tracking and reporting\n- Facilitate retail operation management and terminal allocation\n\n**Performance & Limits:**\n- Lightweight operation optimized for frequent terminal lookups\n- Small dataset suitable for real-time retail operation workflows\n- No pagination needed due to limited terminal counts per location\n- Results consistent across point-of-sale and transaction systems\n\n**Related Endpoints:**\n- `POST /transaction` - Process transactions using configured terminals\n- `GET /reporting/register-transactions` - View terminal-specific transaction history\n- `GET /reporting/cash-summary` - Terminal cash management and reconciliation\n\n**Important Notes:**\n- **Retail Integration**: Essential for point-of-sale operations and transaction processing\n- **Terminal Management**: Supports retail terminal configuration and assignment\n- **Location Specific**: Results filtered to authenticated location terminal setup\n- **Real-time Access**: Current terminal availability and configuration information\n- **Transaction Ready**: Terminal data used throughout retail transaction workflows", + "operationId": "TerminalsGet", + "responses": { + "200": { + "description": "Success - Returns array of terminal objects: `[{ Terminal }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Terminal" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/transaction/create-anonymous": { + "post": { + "tags": ["Transaction"], + "summary": "Create Anonymous Customer Transaction", + "description": "**Purpose:** Create an anonymous customer profile and automatically check them into the dispensary guest list for pickup or service.\n\n**Request Requirements:**\n- \"PreOrder\" role authorization required for transaction creation\n- `CreateAnonymousTransactionRequest` object in request body\n- Content-Type: application/json\n- Optional transaction reference for internal tracking\n\n**Response Data:**\n- Returns anonymous transaction object: `{ AnonymousTransaction }`\n- CustomerId: Temporary customer identifier for this session\n- TransactionId: Transaction identifier for order processing and tracking\n- UniqueId: System-generated unique identifier for customer lookup\n\n**Process Flow:**\n1. Anonymous profile creation: Generate temporary customer record with unique identifier\n2. Guest list check-in: Automatically add customer to dispensary queue/guest list\n3. Transaction setup: Create transaction record for order processing\n4. Unique tracking: Assign unique ID for following up on order status\n\n**Common Use Cases:**\n- Process walk-in customers without pre-existing accounts\n- Provide quick service for customers who prefer not to create full accounts\n- Handle one-time or occasional customers efficiently\n- Accommodate privacy-focused customers who prefer minimal data collection\n- Bridge anonymous sales with customer tracking systems for POS integration\n\n**Performance & Limits:**\n- Immediate customer profile and transaction creation\n- Automatic guest list integration for streamlined workflow\n- Temporary records designed for single-session use\n- Optimized for high-volume walk-in customer processing\n\n**Related Endpoints:**\n- `POST /preorder/submit` - Create orders for existing customers with full profiles\n- `GET /guest-list` - View current guest list including anonymous customers\n\n**Important Notes:**\n- Anonymous customer profiles are temporary and session-based\n- Customer automatically appears in dispensary queue/guest list\n- Optional transaction reference field for external system correlation\n- Each anonymous customer gets a unique system identifier\n- Minimal data collection while maintaining operational requirements\n- Choose this for walk-ins who don't want accounts; use preorder endpoints for existing customers", + "operationId": "TransactionCreate-anonymousPost", + "requestBody": { + "description": "Anonymous transaction request with optional transaction reference - CreateAnonymousTransactionRequest object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/CreateAnonymousTransactionRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAnonymousTransactionRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/CreateAnonymousTransactionRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/CreateAnonymousTransactionRequest" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "Success - Returns anonymous transaction object: `{ AnonymousTransaction }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnonymousTransaction" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for transaction creation" + }, + "500": { + "description": "Internal Server Error - Server error occurred during transaction creation" + } + } + } + }, + "/util/AuthorizationHeader/{apiKey}": { + "get": { + "tags": ["Util"], + "summary": "Generate Authorization Header", + "description": "**Purpose:** Convert an API key into a properly formatted authorization header for initial API client setup and testing.\n\n**Intended Use:** This utility endpoint is designed for initial setup and testing workflows. For production applications, consider encoding headers client-side using Base64: `Basic {base64(api_key:)}`\n\n**Request Requirements:**\n- No authentication required - public utility endpoint\n- API key provided as URL path parameter\n- Utility function for API client development and testing\n\n**Response Data:**\n- Returns single string value (not array) with formatted authorization header\n- Basic authentication header format: \"Basic [base64-encoded-api-key]\"\n- Ready-to-use authorization header value for HTTP clients\n- Base64 encoded API key in standard HTTP Basic authentication format\n\n**Authorization Header Format:**\n- **Encoding**: API key converted to Base64 ASCII encoding\n- **Format**: \"Basic {base64-encoded-key}\" format for HTTP Authorization header\n- **Standards Compliant**: Follows HTTP Basic Authentication specification\n- **Client Ready**: Direct usage in HTTP client authorization headers\n\n**Common Use Cases:**\n- Initial API client setup and configuration\n- Development and testing workflows\n- Manual header generation for API testing tools\n- Integration development and troubleshooting\n\n**Related Endpoints:**\n- `GET /whoami` - Verify API key validity and location access\n- `GET /health` - Test basic API connectivity\n- All other endpoints that require the generated authorization header\n\n**Important Notes:**\n- **Public Utility**: No authentication required for this utility endpoint\n- **Developer Tool**: Designed for API client development and testing support\n- **Header Generation**: Produces standard HTTP Basic authentication headers\n- **Standards Compliant**: Follows HTTP Basic Authentication formatting requirements", + "operationId": "UtilAuthorizationHeaderByApiKeyGet", + "parameters": [ + { + "name": "apiKey", + "in": "path", + "description": "API key to convert into authorization header format - string", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns formatted authorization header string: \"Basic {base64-encoded-key}\"", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/vehicles": { + "get": { + "tags": ["Vehicles"], + "summary": "Get Vehicles", + "description": "**Purpose:** Retrieve all vehicles available for delivery and transportation operations to support logistics and compliance tracking.\n\n**Request Requirements:**\n- \"Reporting\" or \"Deliveries\" role authorization required for vehicle data access\n- No query parameters or request body needed\n\n**Response Data:**\n- Response format: `[{ VehicleDetail }, { VehicleDetail }, ...]`\n- Array typically contains 1-20 vehicles depending on delivery operation size\n- Returns empty array `[]` if no vehicles are configured (not null)\n- Includes vehicle identification, specifications, and operational details\n- License plate numbers, make/model information, and registration data\n- Results automatically filtered to authenticated location\n\n**Vehicle Information Included:**\n- **Identification**: Vehicle ID, license plate, VIN numbers\n- **Specifications**: Make, model, year, color, and vehicle type\n- **Registration**: Registration status and compliance information\n- **Operational**: Availability status and assignment details\n\n**Common Use Cases:**\n- Populate vehicle dropdown lists in delivery assignment forms\n- Display vehicle fleet information for logistics management\n- Support delivery route planning and vehicle allocation\n- Maintain vehicle records for compliance and regulatory requirements\n- Generate vehicle utilization reports for operational analysis\n\n**Performance & Limits:**\n- Lightweight operation optimized for frequent vehicle lookups\n- Small dataset suitable for real-time delivery assignment workflows\n- No pagination needed due to limited fleet sizes\n- Results consistent across delivery management operations\n\n**Related Endpoints:**\n- `POST /vehicles` - Create or update vehicle information\n- `GET /drivers` - Get drivers who can operate vehicles\n- `POST /deliveries/set-route-detail` - Assign vehicles to delivery routes\n\n**Important Notes:**\n- **Fleet Management**: Essential for delivery operations and logistics coordination\n- **Compliance Ready**: Vehicle data supports regulatory compliance and tracking\n- **Location Specific**: Results filtered to authenticated location vehicle fleet\n- **Real-time Access**: Current vehicle availability and status information\n- **Delivery Integration**: Vehicle data used throughout delivery assignment workflows", + "operationId": "VehiclesGet", + "responses": { + "200": { + "description": "Success - Returns array of vehicle objects: `[{ VehicleDetail }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VehicleDetail" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for vehicle access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + }, + "post": { + "tags": ["Vehicles"], + "summary": "Create or Update Vehicle", + "description": "**Purpose:** Create a new vehicle or update an existing vehicle with comprehensive fleet information for delivery operations and compliance tracking.\n\n**Request Requirements:**\n- \"Reporting\" or \"Deliveries\" role authorization required for vehicle data modification\n- `VehicleDetail` object in request body with vehicle information\n- Content-Type: application/json\n- Validation performed on vehicle data before processing\n\n**Response Data:**\n- Response format: `200 OK` (no response body)\n- No data returned - operation confirmation only\n- Returns HTTP 400 with validation errors if request data is invalid\n\n**Create vs Update Behavior:**\n- **CREATE**: When VehicleId is null, 0, or omitted, a new vehicle record will be created\n- **UPDATE**: When VehicleId is provided with a valid vehicle ID, the existing vehicle will be updated\n- **Identification**: Vehicle existence determined by VehicleId value\n- **Automatic Detection**: System automatically determines create vs update based on vehicle data\n\n**Sparse Update Behavior:**\n- **Validation Required**: All provided vehicle data must pass validation checks\n- **Field Updates**: Provided fields will update existing vehicle information\n- **Data Integrity**: Validation ensures vehicle data meets operational requirements\n- **Fleet Consistency**: Updates maintain fleet data consistency and compliance standards\n\n**Vehicle Data Fields:**\n- **Identification**: License plate, VIN, vehicle ID\n- **Specifications**: Make, model, year, color, vehicle type\n- **Registration**: Registration information and compliance data\n- **Operational**: Status, availability, and assignment details\n\n**Common Use Cases:**\n- Add new vehicles to delivery fleet for expanded operations\n- Update existing vehicle information when details change\n- Maintain vehicle registration and compliance records\n- Support fleet management and vehicle tracking requirements\n- Ensure accurate vehicle data for delivery route assignments\n\n**Performance & Limits:**\n- Single vehicle operation for targeted fleet management\n- Comprehensive validation performed before any changes\n- Changes reflected immediately in delivery assignment systems\n- Optimized for fleet management and compliance workflows\n\n**Related Endpoints:**\n- `GET /vehicles` - Retrieve existing vehicle data before updates\n- `GET /drivers` - Manage driver assignments for vehicles\n- `POST /deliveries/set-route-detail` - Assign updated vehicles to delivery routes\n\n**Important Notes:**\n- **Validation Critical**: All vehicle data must pass validation before processing\n- **Fleet Integration**: Vehicle updates affect delivery assignment and logistics systems\n- **Compliance Essential**: Vehicle data must meet regulatory requirements for delivery operations\n- **Location Scoped**: Vehicles automatically associated with authenticated location\n- **Operation Confirmation**: Success indicated by HTTP 200 status (no response body)", + "operationId": "VehiclesPost", + "requestBody": { + "description": "Vehicle information to create or update - VehicleDetail object with fleet details", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/VehicleDetail" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/VehicleDetail" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/VehicleDetail" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/VehicleDetail" + } + } + }, + "x-bodyName": "vehicle" + }, + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request - `ValidationResult` object with `isValid` boolean, `errors` array, and `ruleSetsExecuted` array", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResult" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/vendor/vendors": { + "get": { + "tags": ["Vendor"], + "summary": "Get Vendors", + "description": "**Purpose:** Retrieves a list of vendors with optional filtering by vendor ID or name for procurement and inventory management.\n\n**Request Requirements:**\n- \"Vendor\" role authorization required for vendor data access\n- Optional query parameters for filtering results\n- No request body needed\n\n**Response Data:**\n- Response format: `[{ Vendor }, { Vendor }, ...]`\n- Array typically contains 5-50 vendors per location\n- Returns empty array `[]` if no vendors configured or match filtering criteria\n- Includes contact details, address, and license information\n- Results are automatically filtered by the authenticated user's location\n- Vendor ID, name, and contact information included\n\n**Filtering Options:**\n- No parameters: Returns all vendors for the location\n- vendorId: Returns specific vendor by ID\n- vendorName: Filters vendors by name with partial matching support\n- Both parameters: Can be used together for more specific filtering\n\n**Common Use Cases:**\n- Populate vendor dropdown lists in purchase order creation forms\n- Search for specific vendors by name or ID for quick lookup\n- Synchronize vendor data with external inventory management systems\n- Display vendor contact information for procurement and purchasing\n- Maintain vendor databases for supply chain management\n\n**Performance & Limits:**\n- Rate limiting disabled for this endpoint to support frequent lookups\n- Lightweight response for fast vendor list population\n- Efficient filtering for large vendor databases\n- Results cached for improved performance\n\n**Related Endpoints:**\n- `POST /vendor` - Create or update vendor information\n\n**Important Notes:**\n- Results are automatically filtered to the authenticated user's location\n- Vendor name filtering supports partial matching for flexible search\n- Both filtering parameters can be used simultaneously for precise results\n- No rate limiting applied to support frequent vendor lookups", + "operationId": "VendorVendorsGet", + "parameters": [ + { + "name": "vendorId", + "in": "query", + "description": "Optional vendor ID to filter by specific vendor - Returns exact match", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "vendorName", + "in": "query", + "description": "Optional vendor name to filter by - Supports partial matching for flexible search", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success - Returns array of vendor objects: `[{ Vendor }, ...]`", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Vendor" + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for vendor access" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + }, + "/vendor": { + "post": { + "tags": ["Vendor"], + "summary": "Create or Update Vendor", + "description": "**Purpose:** Create a new vendor or update an existing vendor with comprehensive supplier information for procurement and inventory management.\n\n**Request Requirements:**\n- \"Vendor\" role authorization required for vendor data modification\n- `Vendor` object in request body with vendor details\n- Content-Type: application/json\n- All vendor fields are optional (no validation performed)\n\n**Response Data:**\n- Response format: `{ Vendor }`\n- Returns single `Vendor` object (not array) with updated vendor information\n- Includes assigned VendorId for new vendors or updated ID for existing vendors\n- Complete vendor information with all fields populated\n- Contact details, address, and license information included\n\n**Create vs Update Behavior:**\n- **CREATE**: When VendorId is null, 0, or omitted, a new vendor record will be created\n- **UPDATE**: When VendorId is provided with a valid vendor ID, the existing vendor will be updated\n- **Identification**: Vendor existence determined by VendorId value\n- **Automatic Detection**: System automatically determines create vs update based on VendorId\n\n**Sparse Update Behavior:**\n- **No Required Fields**: All fields are optional\n- **Optional Fields**: Address, contact, and license fields can be omitted to preserve existing values\n- **Null Handling**: Null values will overwrite existing data (use with caution)\n- **Field Independence**: Each field can be updated independently\n\n**Required Fields:**\n- **None**: No validation is performed on any fields\n\n**Optional Fields:**\n- **Address, City, State, PostalCode**: Physical address information for shipping and contact\n- **LicenseNumber**: Vendor's business license number for compliance tracking\n- **ContactName, ContactEmail, ContactPhone**: Primary contact information for procurement\n\n**Common Use Cases:**\n- Add new suppliers to the vendor database for procurement management\n- Update existing vendor contact information when details change\n- Maintain vendor address and license details for compliance\n- Establish vendor relationships for purchase orders and inventory management\n- Synchronize vendor data with external procurement systems\n\n**Performance & Limits:**\n- Single vendor operation for targeted supplier management\n- Immediate validation and response with complete vendor data\n- Changes reflected immediately in vendor catalogs and purchase order systems\n- Optimized for vendor relationship management workflows\n\n**Related Endpoints:**\n- `GET /vendor/vendors` - Retrieve existing vendor data before updates\n- `POST /purchase-orders` - Create purchase orders using vendor relationships\n- `GET /inventory` - View inventory from specific vendors\n\n**Important Notes:**\n- **VendorId Assignment**: New vendors receive automatically generated VendorId\n- **No Validation**: No validation is performed before creation/update\n- **Supplier Relationships**: Vendor data used throughout procurement and inventory systems\n- **Location Scoped**: Vendors automatically associated with authenticated location\n- **Contact Management**: Maintain accurate contact information for effective supplier communication", + "operationId": "VendorPost", + "requestBody": { + "description": "Vendor information to create or update - Vendor object with supplier details", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/Vendor" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Vendor" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Vendor" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Vendor" + } + } + }, + "x-bodyName": "vendor" + }, + "responses": { + "200": { + "description": "Success - Returns vendor object: `{ Vendor }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Vendor" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - Account not authorized for vendor management" + }, + "500": { + "description": "Internal Server Error - Server error occurred during vendor operation" + } + } + } + }, + "/waste": { + "get": { + "tags": ["Waste"], + "summary": "Get Waste Records", + "description": "**Purpose:** Retrieve comprehensive waste disposal records for cultivation and compliance tracking to support regulatory reporting and facility management.\n\n**Request Requirements:**\n- \"CultivationWrite\" role authorization required for waste data access\n- No query parameters or request body needed\n- Waste tracking permissions essential for compliance operations\n\n**Response Data:**\n- Returns single `WasteSummary` object (not array) with comprehensive waste information\n- Response format: `{ WasteSummary }`\n- Includes categorized waste records by type and source\n- Contains room waste, harvest waste, and plant waste details\n- Waste disposal tracking and compliance documentation\n- Results automatically filtered to authenticated location\n\n**Waste Categories Included:**\n- **Room Waste**: General cultivation room waste disposal records\n- **Harvest Waste**: Plant material disposal from harvest operations\n- **Plant Waste**: Individual plant disposal and destruction records\n\n**Common Use Cases:**\n- Generate regulatory compliance reports for waste disposal\n- Track cultivation facility waste management and disposal\n- Support compliance audits and regulatory inspections\n- Monitor waste disposal efficiency and facility operations\n- Maintain cultivation facility waste tracking for legal requirements\n\n**Performance & Limits:**\n- Comprehensive waste data retrieval for facility management\n- Location-specific waste records for compliance tracking\n- Optimized for regulatory reporting and compliance workflows\n- Results include all waste categories and disposal records\n\n**Related Endpoints:**\n- `GET /harvest` - View harvest operations that generate waste\n- `GET /plant` - Track plants before waste disposal\n- `POST /plant/harvest` - Harvest operations that create waste records\n\n**Important Notes:**\n- **Compliance Critical**: Essential for regulatory compliance and waste tracking\n- **Cultivation Focus**: Specific to cultivation facility waste management\n- **Location Scoped**: Waste records filtered to authenticated location\n- **Regulatory Ready**: Data formatted for compliance reporting requirements\n- **Disposal Tracking**: Comprehensive waste disposal and destruction records", + "operationId": "WasteGet", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WasteSummary" + } + } + } + }, + "401": { + "description": "Invalid API Key" + }, + "403": { + "description": "Account not authorized" + }, + "500": { + "description": "Something went wrong." + } + } + } + }, + "/waste/HarvestWaste": { + "post": { + "tags": ["Waste"], + "operationId": "WasteHarvestWastePost", + "requestBody": { + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/HarvestWasteDetailWaste" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/HarvestWasteDetailWaste" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/HarvestWasteDetailWaste" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/HarvestWasteDetailWaste" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/waste/PlantWaste": { + "post": { + "tags": ["Waste"], + "operationId": "WastePlantWastePost", + "requestBody": { + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/PlantWasteDetailWaste" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlantWasteDetailWaste" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PlantWasteDetailWaste" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/PlantWasteDetailWaste" + } + } + }, + "x-bodyName": "req" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/whoami": { + "get": { + "tags": ["WhoAmI"], + "summary": "Verify API key and get location identity information", + "description": "**Purpose:** Verifies your API key is valid and returns detailed information about the location/store it's associated with.\n\n**Request Requirements:**\n- Any authenticated role authorization (no specific role required)\n- No query parameters or request body needed\n\n**Response Data:**\n- Response format: `{ LocationIdentity }`\n- Returns location identity object with complete location and company information\n- Location details including name, address, license number, and business information\n- Parent company (LSP) details and global identifiers\n- Configuration settings like customer profile sharing preferences\n- Regional data for compliance and routing\n\n**Common Use Cases:**\n- Confirm your API key is working correctly for API key validation\n- Identify which store/location your API key accesses for location discovery\n- Determine current location context for multi-location applications\n- Get location details for application initialization and configuration setup\n- Troubleshoot authentication and location access issues during debugging\n\n**Performance & Limits:**\n- Lightweight operation with immediate response\n- No rate limiting typically applied to identity verification\n- Recommended as first call when setting up API integration\n- Cached results can be used for session duration\n\n**Related Endpoints:**\n- No direct related endpoints - this is a foundational identity endpoint\n\n**Important Notes:**\n- Call this endpoint first when setting up API integration\n- Verify authentication and understand your location context before other calls\n- Response includes both location-specific and company-wide identifiers\n- Regional information helps with compliance and API routing decisions\n\n**Response Fields:**\n- `LocationId` / `LocationName` for store identification\n- `LspId` / `LspName` for parent company information\n- `Address`, `City`, `State`, `PostalCode` for physical location\n- `LicenseNumber` for business license and compliance\n- `ShareCustomerProfiles` for customer data sharing configuration\n- `LocationGlobalId` / `LspGlobalId` for global unique identifiers", + "operationId": "WhoamiGet", + "responses": { + "200": { + "description": "Success - Returns location identity object: `{ LocationIdentity }`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LocationIdentity" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "403": { + "description": "Forbidden - API key doesn't have access to this location" + }, + "404": { + "description": "Not Found - Location not found for the authenticated API key" + }, + "500": { + "description": "Internal Server Error - Server error occurred" + } + } + } + } + }, + "components": { + "schemas": { + "Address": { + "type": "object", + "properties": { + "addressId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "customerId": { + "type": "integer", + "format": "int32" + }, + "street": { + "type": "string", + "nullable": true + }, + "street2": { + "type": "string", + "nullable": true + }, + "city": { + "type": "string", + "nullable": true + }, + "state": { + "type": "string", + "nullable": true + }, + "postal_code": { + "type": "string", + "nullable": true + }, + "country_Code": { + "type": "string", + "nullable": true + }, + "latitude": { + "type": "number", + "format": "double", + "nullable": true + }, + "longitude": { + "type": "number", + "format": "double", + "nullable": true + }, + "county": { + "type": "string", + "nullable": true + }, + "additionalStateIdentifiers": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AllocatedDeliveryItem": { + "type": "object", + "properties": { + "transactionId": { + "type": "integer", + "format": "int32" + }, + "productName": { + "type": "string", + "nullable": true + }, + "quantity": { + "type": "number", + "format": "double" + }, + "totalPrice": { + "type": "number", + "format": "double" + }, + "totalDiscount": { + "type": "number", + "format": "double" + }, + "totalTax": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "AllocatedPreOrderItem": { + "type": "object", + "properties": { + "productName": { + "type": "string", + "nullable": true + }, + "quantity": { + "type": "number", + "format": "double" + }, + "totalPrice": { + "type": "number", + "format": "double" + }, + "totalDiscount": { + "type": "number", + "format": "double" + }, + "totalTax": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "AnonymousTransaction": { + "type": "object", + "properties": { + "customerId": { + "type": "integer", + "description": "Unique identifier for the customer record associated with this anonymous transaction.", + "format": "int32" + }, + "transactionId": { + "type": "integer", + "description": "Unique identifier for the transaction record.", + "format": "int32" + }, + "uniqueId": { + "type": "string", + "description": "String representation of the unique identifier for API responses.", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Anonymous transaction response model containing transaction identifiers for guest checkout operations." + }, + "AppliedDiscount": { + "type": "object", + "properties": { + "discountId": { + "type": "integer", + "description": "Unique identifier for the discount program or campaign applied.", + "format": "int32" + }, + "discountName": { + "type": "string", + "description": "Display name of the discount for customer receipts and reporting.", + "nullable": true + }, + "discountReason": { + "type": "string", + "description": "Reason or justification for the discount application (e.g., \"Loyalty Reward\", \"Medical Patient\").", + "nullable": true + }, + "amount": { + "type": "number", + "description": "Discount amount applied to the transaction item (in USD, positive value represents savings).", + "format": "double" + }, + "transactionItemId": { + "type": "integer", + "description": "Reference identifier linking this discount back to the specific transaction line item.\nNot guaranteed to be unique outside of a single transaction.", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Discount information applied to a specific transaction item in cannabis retail operations." + }, + "AssignPlantsToGroupRequest": { + "type": "object", + "properties": { + "plantGroupName": { + "type": "string", + "description": "Name of target plant group for batch organization and cultivation tracking", + "nullable": true + }, + "plantSerialNumbers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Collection of plant serial numbers to assign to the specified plant group", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for assigning existing cannabis plants to a specific plant group for batch management and cultivation workflow organization.\n\n**Plant Group Assignment:**\n- Assigns existing plants to target plant group using serial numbers\n- Supports batch organization for cultivation workflow management\n- Plants identified by serial numbers for precise assignment\n- Validates target plant group exists before assignment\n\n**Serial Number Identification:**\n- Plants identified by their unique serial numbers rather than IDs\n- All serial numbers must correspond to existing plants in the facility\n- Plants must be accessible to the authenticated location\n- Serial numbers must match exact plant tracking identifiers\n\n**Batch Management:**\n- Plant groups enable batch-based cultivation tracking and compliance\n- Supports harvest planning and cultivation scheduling optimization\n- Facilitates cultivation management and operational efficiency" + }, + "BadRequestPropertyError": { + "type": "object", + "properties": { + "propertyName": { + "type": "string", + "description": "Name of the property that failed validation.", + "nullable": true + }, + "propertyError": { + "type": "string", + "description": "Description of the validation error for the specified property.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Field-specific validation error details for BadRequest responses." + }, + "BadRequestResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "General error message describing the nature of the bad request.", + "nullable": true + }, + "propertyErrors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BadRequestPropertyError" + }, + "description": "Collection of field-specific validation errors for detailed feedback.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Standardized error response model for HTTP 400 Bad Request responses across the API." + }, + "BatchDetails": { + "type": "object", + "properties": { + "batchName": { + "type": "string", + "description": "Display name for the immature plant batch for identification and organization.", + "nullable": true + }, + "plantType": { + "type": "string", + "description": "Plant type designation for the batch (e.g., \"Seedling\", \"Clone\", \"Cutting\").", + "nullable": true + }, + "plantCount": { + "type": "integer", + "description": "Number of plants in the immature batch for inventory tracking and compliance.", + "format": "int32" + }, + "strainId": { + "type": "integer", + "description": "Strain identifier for the cannabis strain being cultivated in this batch.", + "format": "int32" + }, + "roomId": { + "type": "integer", + "description": "Room identifier for the immature batch location assignment.", + "format": "int32" + }, + "tableId": { + "type": "integer", + "description": "Table identifier within the room for precise location tracking (optional).", + "format": "int32", + "nullable": true + }, + "motherPlantId": { + "type": "integer", + "description": "Mother plant identifier for tracking genetic lineage (required for clone batches).", + "format": "int32", + "nullable": true + }, + "dateCreated": { + "type": "string", + "description": "Date when the immature batch was created for cultivation timeline documentation.", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Detailed specification for creating individual immature plant batches with cultivation and compliance information." + }, + "BooleanNullableOptional": { + "type": "boolean", + "additionalProperties": false + }, + "BooleanOptional": { + "type": "boolean", + "additionalProperties": false + }, + "Brand": { + "type": "object", + "properties": { + "brandId": { + "type": "integer", + "format": "int32" + }, + "brandName": { + "type": "string", + "nullable": true + }, + "brandCatalogBrandId": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "BrandEditRequest": { + "type": "object", + "properties": { + "brandId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "brandName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "BroadcastedResponses": { + "type": "object", + "properties": { + "responses": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationResponse" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "BulkCreateOrUpdateHarvest": { + "type": "object", + "properties": { + "harvests": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BulkHarvestDetail" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "BulkCreateOrUpdateHarvestResponse": { + "type": "object", + "properties": { + "createdHarvestIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "updatedHarvestIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "BulkHarvestDetail": { + "type": "object", + "properties": { + "harvestId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "harvestName": { + "type": "string", + "nullable": true + }, + "harvestRoomId": { + "type": "integer", + "format": "int32" + }, + "harvestDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "strainId": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "CalculationMethod": { + "enum": [1, 2, 3, 4, 5, 6, 15], + "type": "integer", + "format": "int32" + }, + "CancelPreorderRequest": { + "type": "object", + "properties": { + "orderId": { + "type": "integer", + "description": "Unique identifier of the pre-order to be canceled.", + "format": "int32" + }, + "cancellationReason": { + "type": "string", + "description": "Required reason for canceling the order (used for business analytics and customer service).", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for canceling existing customer pre-orders before fulfillment." + }, + "CannabinoidTerpeneValue": { + "required": ["labResultName", "labResultUnitId", "value"], + "type": "object", + "properties": { + "labResultName": { + "minLength": 1, + "type": "string", + "description": "Name of the laboratory test result (e.g., \"THC\", \"CBD\", \"Limonene\") - must match predefined compound list." + }, + "value": { + "type": "number", + "description": "Measured value of the compound in the cannabis sample (decimal precision for accurate reporting).", + "format": "double" + }, + "labResultUnitId": { + "type": "integer", + "description": "Unit identifier for the measurement (references LabResultUnit enum - mg/g, percentage, etc.).", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Laboratory test result value model for cannabinoid and terpene measurements in cannabis products." + }, + "CartItemPrice": { + "type": "object", + "properties": { + "productName": { + "type": "string", + "nullable": true + }, + "productId": { + "type": "integer", + "format": "int32" + }, + "quantity": { + "type": "number", + "format": "double" + }, + "subtotal": { + "type": "number", + "format": "double" + }, + "pricingTierAdjustment": { + "type": "number", + "format": "double", + "nullable": true + }, + "discounts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Discount" + }, + "nullable": true + }, + "tax": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "CartPrice": { + "type": "object", + "properties": { + "cartItemPrices": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CartItemPrice" + }, + "nullable": true + }, + "subTotal": { + "type": "number", + "format": "double" + }, + "taxes": { + "type": "number", + "format": "double" + }, + "discount": { + "type": "number", + "format": "double" + }, + "total": { + "type": "number", + "format": "double" + }, + "originalTotal": { + "type": "number", + "format": "double" + }, + "roundedDifference": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "ChangeGrowthPhaseRequest": { + "type": "object", + "properties": { + "plantIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Collection of LeafLogix plant IDs to update to the new growth phase", + "nullable": true + }, + "growthPhase": { + "type": "string", + "description": "Target cultivation growth phase. Must be one of: `Propagation`, `Vegetative`, `Flowering`", + "nullable": true + }, + "phaseStartDate": { + "type": "string", + "description": "Date when new growth phase begins (optional, defaults to current UTC time if not specified)", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for updating the cultivation growth phase of cannabis plants to track development stages.\n\n**Growth Phase Management:**\n- Updates plant cultivation phase for proper development tracking\n- Supports bulk processing of multiple plants in single operation\n- Validates growth phase against allowed phase values\n- Automatically sets phase start date if not provided\n\n**Valid Growth Phases:**\n- `Propagation`: Initial plant development and cloning phase\n- `Vegetative`: Active vegetative growth before flowering initiation\n- `Flowering`: Reproductive growth phase leading to harvest\n\n**Phase Transition Rules:**\n- Phase start date defaults to current UTC time if not specified\n- Phase changes are logged for cultivation timeline tracking\n- Integration with external cultivation systems for environmental control" + }, + "ClosingReportCategorySummary": { + "type": "object", + "properties": { + "category": { + "type": "string", + "description": "Product category name (e.g., \"Flower\", \"Edibles\", \"Concentrates\").", + "nullable": true + }, + "categoryTotal": { + "type": "number", + "description": "Total net sales for the category (calculated property returning CategoryNetTotal).", + "format": "double", + "readOnly": true + }, + "categoryGrossTotal": { + "type": "number", + "description": "Gross sales total for the category before discounts (in USD).", + "format": "double" + }, + "categoryDiscountTotal": { + "type": "number", + "description": "Total discount amount applied to products in this category (in USD).", + "format": "double" + }, + "categoryNetTotal": { + "type": "number", + "description": "Net sales total for the category after discounts (in USD).", + "format": "double" + }, + "categoryCost": { + "type": "number", + "description": "Total cost of goods sold for products in this category (in USD).", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Product category sales summary for cannabis retail closing reports and financial analysis." + }, + "ClosingReportCustomerTypeSummary": { + "type": "object", + "properties": { + "customerType": { + "type": "string", + "description": "Customer type classification (e.g., \"Recreational\", \"Medical\", \"Industry\").", + "nullable": true + }, + "total": { + "type": "number", + "description": "Total net sales for this customer type (calculated property returning NetTotal).", + "format": "double", + "readOnly": true + }, + "grossTotal": { + "type": "number", + "description": "Gross sales total for this customer type before discounts (in USD).", + "format": "double" + }, + "netTotal": { + "type": "number", + "description": "Net sales total for this customer type after discounts (in USD).", + "format": "double" + }, + "discountTotal": { + "type": "number", + "description": "Total discount amount applied to this customer type (in USD).", + "format": "double" + }, + "customerTypeCost": { + "type": "number", + "description": "Total cost of goods sold for this customer type (in USD).", + "format": "double" + }, + "cannabisSales": { + "type": "number", + "description": "Cannabis product sales total for this customer type (in USD).", + "format": "double" + }, + "nonCannabisSales": { + "type": "number", + "description": "Non-cannabis product sales total for this customer type (accessories, etc.) (in USD).", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Customer type sales summary for cannabis retail closing reports and customer segment analysis." + }, + "ClosingReportOrderSourceSummary": { + "type": "object", + "properties": { + "orderSource": { + "type": "string", + "description": "Order origination source (e.g., \"Website\", \"Mobile App\", \"Weedmaps\", \"Walk-In\").", + "nullable": true + }, + "total": { + "type": "number", + "description": "Total net sales for this order source (calculated property returning NetTotal).", + "format": "double", + "readOnly": true + }, + "grossTotal": { + "type": "number", + "description": "Gross sales total for this order source before discounts (in USD).", + "format": "double" + }, + "netTotal": { + "type": "number", + "description": "Net sales total for this order source after discounts (in USD).", + "format": "double" + }, + "discountTotal": { + "type": "number", + "description": "Total discount amount applied to this order source (in USD).", + "format": "double" + }, + "orderSourceCost": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Order source sales summary for cannabis retail closing reports and marketing channel analysis." + }, + "ClosingReportOrderTypeSummary": { + "type": "object", + "properties": { + "orderType": { + "type": "string", + "description": "Order fulfillment type (e.g., \"In-Store\", \"Pickup\", \"Delivery\", \"Curbside\").", + "nullable": true + }, + "total": { + "type": "number", + "description": "Total net sales for this order type (calculated property returning NetTotal).", + "format": "double", + "readOnly": true + }, + "grossTotal": { + "type": "number", + "description": "Gross sales total for this order type before discounts (in USD).", + "format": "double" + }, + "netTotal": { + "type": "number", + "description": "Net sales total for this order type after discounts (in USD).", + "format": "double" + }, + "discountTotal": { + "type": "number", + "description": "Total discount amount applied to this order type (in USD).", + "format": "double" + }, + "orderTypeCost": { + "type": "number", + "description": "Total cost of goods sold for this order type (in USD).", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Order type sales summary for cannabis retail closing reports and fulfillment channel analysis." + }, + "ClosingReportPayByBankBatchFileSums": { + "type": "object", + "properties": { + "batchFileName": { + "type": "string", + "description": "Batch file name for payment processor identification and tracking.", + "nullable": true + }, + "payByBankBatchFileAdjustmentAmount": { + "type": "number", + "description": "Adjustment amount for the batch file for financial reconciliation.", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Pay-by-Bank batch file summary for cannabis payment processing reconciliation." + }, + "ClosingReportPaymentSummary": { + "type": "object", + "properties": { + "paymentType": { + "type": "string", + "description": "Payment method type (e.g., \"Cash\", \"Credit Card\", \"CanPay\", \"Hypur\").", + "nullable": true + }, + "totalPaid": { + "type": "number", + "description": "Total amount paid using this payment method (in USD).", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Payment method summary for cannabis retail closing reports and financial reconciliation." + }, + "ClosingReportTaxRateSummary": { + "type": "object", + "properties": { + "taxRate": { + "type": "string", + "description": "Tax rate name or type (e.g., \"State Excise Tax\", \"City Cannabis Tax\", \"Sales Tax\").", + "nullable": true + }, + "totalTax": { + "type": "number", + "description": "Total tax amount collected for this tax rate (in USD).", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Tax rate summary for cannabis retail closing reports and tax liability tracking." + }, + "ClosingReportV2": { + "type": "object", + "properties": { + "totalTips": { + "type": "number", + "description": "Total tips aggregated for the closing period for staff distribution.", + "format": "double", + "nullable": true, + "readOnly": true + }, + "payByBankTips": { + "type": "number", + "description": "Tips processed through Pay-by-Bank system for electronic tip distribution.", + "format": "double" + }, + "payByBankTransactionFees": { + "type": "number", + "description": "Transaction fees charged by Pay-by-Bank system for cost accounting.", + "format": "double" + }, + "payByBankBatchFile": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClosingReportPayByBankBatchFileSums" + }, + "description": "Batch file summaries for Pay-by-Bank transaction reconciliation.", + "nullable": true + }, + "feesDonations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FeeDonation" + }, + "description": "Fees and donations collected during the closing period for compliance reporting.", + "nullable": true + }, + "dutchiePayTips": { + "type": "number", + "description": "DutchiePay tips processed for cannabis payment integration.", + "format": "double", + "nullable": true, + "readOnly": true + }, + "dutchiePayTotalAdjustmentAmount": { + "type": "number", + "description": "DutchiePay transaction adjustments for cannabis payment processing.", + "format": "double", + "nullable": true, + "readOnly": true + }, + "dutchiePayBatchFileSums": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClosingReportPayByBankBatchFileSums" + }, + "description": "DutchiePay batch file summaries for cannabis payment reconciliation.", + "nullable": true, + "readOnly": true + }, + "grossSales": { + "type": "number", + "format": "double", + "nullable": true + }, + "discount": { + "type": "number", + "format": "double", + "nullable": true + }, + "loyalty": { + "type": "number", + "format": "double", + "nullable": true + }, + "totalTax": { + "type": "number", + "format": "double", + "nullable": true + }, + "cost": { + "type": "number", + "format": "double", + "nullable": true + }, + "coupons": { + "type": "number", + "format": "double", + "nullable": true + }, + "itemTotal": { + "type": "number", + "format": "double", + "nullable": true + }, + "transactionCount": { + "type": "integer", + "format": "int32" + }, + "itemCount": { + "type": "integer", + "format": "int32" + }, + "customerCount": { + "type": "integer", + "format": "int32" + }, + "newCustomerCount": { + "type": "integer", + "format": "int32" + }, + "voidCount": { + "type": "integer", + "format": "int32" + }, + "voidTotal": { + "type": "number", + "format": "double", + "nullable": true + }, + "returnTotal": { + "type": "number", + "format": "double", + "nullable": true + }, + "startingBalance": { + "type": "number", + "format": "double", + "nullable": true + }, + "endingBalance": { + "type": "number", + "format": "double", + "nullable": true + }, + "deposits": { + "type": "number", + "format": "double", + "nullable": true + }, + "adjustments": { + "type": "number", + "format": "double", + "nullable": true + }, + "totalPayments": { + "type": "number", + "format": "double", + "nullable": true + }, + "invoiceTotal": { + "type": "number", + "format": "double", + "nullable": true + }, + "cannabisSales": { + "type": "number", + "format": "double", + "nullable": true + }, + "nonCannabisSales": { + "type": "number", + "format": "double", + "nullable": true + }, + "netSales": { + "type": "number", + "format": "double", + "nullable": true + }, + "revenueFeesDonations": { + "type": "number", + "format": "double", + "nullable": true + }, + "nonRevenueFeesDonations": { + "type": "number", + "format": "double", + "nullable": true + }, + "rounding": { + "type": "number", + "format": "double", + "nullable": true + }, + "totalIncome": { + "type": "number", + "format": "double", + "nullable": true + }, + "averageCartNetSales": { + "type": "number", + "format": "double", + "nullable": true + }, + "overShort": { + "type": "number", + "format": "double", + "nullable": true, + "readOnly": true + }, + "categorySummary": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClosingReportCategorySummary" + }, + "nullable": true + }, + "paymentSummary": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClosingReportPaymentSummary" + }, + "nullable": true + }, + "taxSummary": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClosingReportTaxRateSummary" + }, + "nullable": true + }, + "customerTypeSummary": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClosingReportCustomerTypeSummary" + }, + "nullable": true + }, + "orderTypeSummary": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClosingReportOrderTypeSummary" + }, + "nullable": true + }, + "orderSourceSummary": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClosingReportOrderSourceSummary" + }, + "nullable": true + } + }, + "additionalProperties": false, + "description": "Enhanced closing report model for cannabis dispensary daily financial operations with payment processing integration." + }, + "ConvertBatchDetails": { + "type": "object", + "properties": { + "batchId": { + "type": "integer", + "description": "Batch identifier for the plant batch being converted to mature growth phase.", + "format": "int32" + }, + "serialNumbers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Collection of individual plant serial numbers within the batch for state tracking compliance.", + "nullable": true + }, + "batchStage": { + "type": "string", + "description": "Target growth stage for the batch conversion (e.g., \"Vegetative\", \"Flowering\").", + "nullable": true + }, + "roomId": { + "type": "integer", + "description": "Destination room identifier for the converted batch location tracking.", + "format": "int32" + }, + "tableId": { + "type": "integer", + "description": "Destination table identifier within the room for precise location tracking (optional).", + "format": "int32", + "nullable": true + }, + "dateCreated": { + "type": "string", + "description": "Date when the batch conversion was performed for cultivation timeline documentation.", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Detailed specification for converting individual plant batches during cultivation growth phase transitions." + }, + "ConvertImmatureBatchRequest": { + "type": "object", + "properties": { + "batches": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConvertBatchDetails" + }, + "description": "Collection of plant batches to be converted from immature to mature growth phases.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for converting immature plant batches to mature growth phases in cannabis cultivation operations." + }, + "ConvertImmaturePlantResponse": { + "type": "object", + "properties": { + "convertedPlants": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreatedMaturePlant" + }, + "description": "Collection of mature plants created from immature batch conversion.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Response model for immature plant batch conversion operations containing converted mature plant identifiers." + }, + "ConvertImmaturePlantResponseApiResult": { + "type": "object", + "properties": { + "result": { + "type": "boolean" + }, + "message": { + "type": "string", + "nullable": true + }, + "data": { + "$ref": "#/components/schemas/ConvertImmaturePlantResponse" + } + }, + "additionalProperties": false + }, + "CreateAnonymousTransactionRequest": { + "type": "object", + "properties": { + "transactionReference": { + "type": "string", + "description": "Optional reference identifier for the transaction (for external system integration).", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for creating anonymous transactions for guest customer operations." + }, + "CreateImmaturePlantBatchResponse": { + "type": "object", + "properties": { + "batches": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreatedImmaturePlantBatch" + }, + "description": "Collection of created immature plant batches with associated plant identifiers.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Response model for immature plant batch creation operations containing created batch and plant identifiers." + }, + "CreateImmaturePlantBatchResponseApiResult": { + "type": "object", + "properties": { + "result": { + "type": "boolean" + }, + "message": { + "type": "string", + "nullable": true + }, + "data": { + "$ref": "#/components/schemas/CreateImmaturePlantBatchResponse" + } + }, + "additionalProperties": false + }, + "CreateJournalEntryRequest": { + "required": ["body", "customerId", "date", "subject"], + "type": "object", + "properties": { + "customerId": { + "type": "integer", + "description": "The customer ID to create the journal entry for.", + "format": "int32" + }, + "subject": { + "minLength": 1, + "type": "string", + "description": "Brief title or summary of the journal entry." + }, + "body": { + "minLength": 1, + "type": "string", + "description": "Detailed content and notes for the journal entry." + }, + "date": { + "type": "string", + "description": "Date and time when the journal entry should be dated.", + "format": "date-time" + } + }, + "additionalProperties": false, + "description": "Request model for creating new customer journal entries with interaction details and notes." + }, + "CreateMatureBatchRequest": { + "type": "object", + "properties": { + "batches": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MatureBatchDetails" + }, + "description": "Collection of mature plant batch specifications for bulk batch creation operations.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for creating mature plant batches in cannabis cultivation operations." + }, + "CreateMaturePlantsResponse": { + "type": "object", + "properties": { + "createdPlants": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreatedMaturePlant" + }, + "description": "Collection of mature plants created ready for flowering phase cultivation.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Response model for mature plant batch creation operations containing created mature plant identifiers." + }, + "CreateMaturePlantsResponseApiResult": { + "type": "object", + "properties": { + "result": { + "type": "boolean" + }, + "message": { + "type": "string", + "nullable": true + }, + "data": { + "$ref": "#/components/schemas/CreateMaturePlantsResponse" + } + }, + "additionalProperties": false + }, + "CreateOrUpdateHarvest": { + "type": "object", + "properties": { + "harvestId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "harvestName": { + "type": "string", + "nullable": true + }, + "strainName": { + "type": "string", + "nullable": true + }, + "harvestRoomId": { + "type": "integer", + "format": "int32" + }, + "harvestDate": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "CreatePlantRequest": { + "type": "object", + "properties": { + "serialNumber": { + "type": "string", + "nullable": true + }, + "plantGroupName": { + "type": "string", + "nullable": true + }, + "growthPhase": { + "type": "string", + "nullable": true + }, + "phaseStartDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "dateCreated": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "bornDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "strain": { + "type": "string", + "nullable": true + }, + "room": { + "type": "string", + "nullable": true + }, + "table": { + "type": "string", + "nullable": true + }, + "isMother": { + "type": "boolean" + }, + "bypassStateIntegration": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "CreatePreOrderRequest": { + "required": ["customerId"], + "type": "object", + "properties": { + "customerId": { + "type": "integer", + "format": "int32" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PreOrderItem" + }, + "nullable": true + }, + "redemptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PreOrderRedemption" + }, + "nullable": true + }, + "isDelivery": { + "type": "boolean" + }, + "orderSource": { + "type": "string", + "nullable": true, + "deprecated": true + }, + "orderType": { + "type": "string", + "nullable": true + }, + "deliveryStreet": { + "type": "string", + "nullable": true + }, + "deliveryStreet2": { + "type": "string", + "nullable": true + }, + "deliveryCity": { + "type": "string", + "nullable": true + }, + "deliveryState": { + "type": "string", + "nullable": true + }, + "deliveryPostalCode": { + "type": "string", + "nullable": true + }, + "idempotencyKey": { + "type": "string", + "nullable": true + }, + "notes": { + "type": "string", + "nullable": true + }, + "status": { + "type": "string", + "nullable": true + }, + "transactionReference": { + "type": "string", + "nullable": true + }, + "timeWindowStartDateUtc": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "timeWindowEndDateUtc": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "deliveryScheduleId": { + "$ref": "#/components/schemas/DeliveryScheduleType" + } + }, + "additionalProperties": false + }, + "CreateUpdatePurchaseOrderItemRequest": { + "type": "object", + "properties": { + "productId": { + "type": "integer", + "format": "int32" + }, + "unitId": { + "$ref": "#/components/schemas/Int32NullableOptional" + }, + "quantity": { + "$ref": "#/components/schemas/Int32NullableOptional" + }, + "subtotal": { + "$ref": "#/components/schemas/DecimalNullableOptional" + }, + "tax": { + "$ref": "#/components/schemas/DecimalNullableOptional" + } + }, + "additionalProperties": false + }, + "CreateUpdatePurchaseOrderRequest": { + "type": "object", + "properties": { + "purchaseOrderId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "expectedArrivalDate": { + "$ref": "#/components/schemas/DateTimeNullableOptional" + }, + "title": { + "$ref": "#/components/schemas/StringOptional" + }, + "dateReceived": { + "$ref": "#/components/schemas/DateTimeNullableOptional" + }, + "shippingInformation": { + "$ref": "#/components/schemas/StringOptional" + }, + "vendorContact": { + "$ref": "#/components/schemas/StringOptional" + }, + "status": { + "$ref": "#/components/schemas/StringOptional" + }, + "vendorId": { + "$ref": "#/components/schemas/Int32NullableOptional" + }, + "purchaseOrderNumber": { + "$ref": "#/components/schemas/Int32NullableOptional" + }, + "purchaseOrderItems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreateUpdatePurchaseOrderItemRequest" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "CreateUpdatePurchaseOrderResponse": { + "type": "object", + "properties": { + "createdPurchaseOrderIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "updatedPurchaseOrderIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "CreateUpdatePurchaseOrdersRequest": { + "type": "object", + "properties": { + "purchaseOrders": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CreateUpdatePurchaseOrderRequest" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "CreatedImmaturePlantBatch": { + "type": "object", + "properties": { + "batchId": { + "type": "integer", + "description": "Unique identifier assigned to the created immature plant batch.", + "format": "int32" + }, + "plantIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Collection of unique plant identifiers created within this batch.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Individual created immature plant batch containing batch identifier and associated plant IDs." + }, + "CreatedMaturePlant": { + "type": "object", + "properties": { + "batchId": { + "type": "integer", + "format": "int32" + }, + "plantId": { + "type": "integer", + "format": "int32" + }, + "plantSerialNumber": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Customer": { + "type": "object", + "properties": { + "customerId": { + "type": "integer", + "description": "Unique internal identifier for the customer record.", + "format": "int32" + }, + "uniqueId": { + "type": "string", + "description": "String representation of UniqueId for external API consumption.", + "nullable": true, + "readOnly": true + }, + "name": { + "type": "string", + "description": "Deprecated name field (use FirstName and LastName instead).", + "nullable": true, + "deprecated": true + }, + "firstName": { + "type": "string", + "description": "Customer's first name.", + "nullable": true + }, + "lastName": { + "type": "string", + "description": "Customer's last name.", + "nullable": true + }, + "middleName": { + "type": "string", + "description": "Customer's middle name.", + "nullable": true + }, + "nameSuffix": { + "type": "string", + "description": "Name suffix (Jr., Sr., III, etc.).", + "nullable": true + }, + "namePrefix": { + "type": "string", + "description": "Name prefix (Mr., Mrs., Dr., etc.).", + "nullable": true + }, + "address1": { + "type": "string", + "description": "Primary street address line.", + "nullable": true + }, + "address2": { + "type": "string", + "description": "Secondary address line (apartment, suite, etc.).", + "nullable": true + }, + "city": { + "type": "string", + "description": "City name.", + "nullable": true + }, + "state": { + "type": "string", + "description": "State or province.", + "nullable": true + }, + "postalCode": { + "type": "string", + "description": "Postal or ZIP code.", + "nullable": true + }, + "phone": { + "type": "string", + "description": "Primary phone number.", + "nullable": true + }, + "cellPhone": { + "type": "string", + "description": "Cell phone number.", + "nullable": true + }, + "emailAddress": { + "type": "string", + "description": "Email address.", + "nullable": true + }, + "status": { + "type": "string", + "description": "Customer account status.", + "nullable": true + }, + "mmjidNumber": { + "type": "string", + "description": "Medical marijuana identification number.", + "nullable": true + }, + "mmjidExpirationDate": { + "type": "string", + "description": "Medical marijuana ID expiration date.", + "format": "date-time", + "nullable": true + }, + "lastModifiedDateUTC": { + "type": "string", + "description": "Last modification timestamp in UTC format.", + "nullable": true + }, + "creationDate": { + "type": "string", + "description": "Customer record creation date.", + "format": "date-time", + "nullable": true + }, + "customerType": { + "type": "string", + "description": "Customer type classification.", + "nullable": true + }, + "gender": { + "type": "string", + "description": "Customer's gender.", + "nullable": true + }, + "driversLicenseHash": { + "type": "string", + "description": "SHA2_256 hash of the Driver License ID", + "nullable": true + }, + "dateOfBirth": { + "type": "string", + "description": "Customer's date of birth.", + "format": "date-time", + "nullable": true + }, + "externalCustomerId": { + "type": "string", + "description": "External system customer identifier.", + "nullable": true + }, + "createdByIntegrator": { + "type": "string", + "description": "Name of the integration system that created this customer.", + "nullable": true + }, + "isAnonymous": { + "type": "boolean", + "description": "Indicates if this is an anonymous customer record." + }, + "referralSource": { + "type": "string", + "description": "How the customer heard about the dispensary.", + "nullable": true + }, + "otherReferralSource": { + "type": "string", + "description": "Additional details about referral source when \"Other\" is selected.", + "nullable": true + }, + "springBigMemberId": { + "type": "integer", + "description": "SpringBig loyalty system member identifier.", + "format": "int32" + }, + "customIdentifier": { + "type": "string", + "description": "Custom identifier for external system integration.", + "nullable": true + }, + "discountGroups": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Collection of active discount groups for this customer.", + "nullable": true, + "readOnly": true + }, + "createdAtLocation": { + "type": "string", + "description": "Location where this customer record was created.", + "nullable": true + }, + "notes": { + "type": "string", + "description": "Additional notes about the customer.", + "nullable": true + }, + "isLoyaltyMember": { + "type": "boolean", + "description": "Indicates if customer is enrolled in loyalty program.", + "nullable": true + }, + "primaryQualifyingCondition": { + "type": "string", + "description": "Primary medical condition for medical marijuana patients.", + "nullable": true + }, + "secondaryQualifyingConditions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Additional medical conditions for medical marijuana patients.", + "nullable": true + }, + "mergedIntoCustomerId": { + "type": "integer", + "description": "Customer ID this record was merged into (if applicable).", + "format": "int32", + "nullable": true + }, + "optedIntoMarketing": { + "type": "boolean", + "description": "Customer's marketing communication preference.", + "nullable": true + }, + "loyaltyTier": { + "type": "string", + "description": "Customer's current loyalty program tier.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Represents a customer profile with personal information, contact details, and cannabis compliance data." + }, + "CustomerSearchRequest": { + "type": "object", + "properties": { + "lastName": { + "type": "string", + "description": "Customer's last name for name-based search matching.", + "nullable": true + }, + "dateOfBirth": { + "type": "string", + "description": "Customer's date of birth for identity verification and precise matching.", + "format": "date-time", + "nullable": true + }, + "phone": { + "type": "string", + "description": "Customer's phone number for contact-based search matching.", + "nullable": true + }, + "emailAddress": { + "type": "string", + "description": "Customer's email address for account-based search matching.", + "nullable": true + }, + "mmjidNumber": { + "type": "string", + "description": "Medical marijuana identification number for regulatory compliance search.", + "nullable": true + }, + "driversLicenseId": { + "type": "string", + "description": "Driver's license identifier for government ID-based search matching.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Search criteria model for customer lookup operations with flexible matching options." + }, + "CustomerSearchResult": { + "type": "object", + "properties": { + "matchType": { + "type": "string", + "description": "Indicates how the customer record was matched during the search operation.", + "nullable": true + }, + "customerId": { + "type": "integer", + "description": "Unique internal identifier for the customer record.", + "format": "int32" + }, + "uniqueId": { + "type": "string", + "description": "String representation of UniqueId for external API consumption.", + "nullable": true, + "readOnly": true + }, + "name": { + "type": "string", + "description": "Deprecated name field (use FirstName and LastName instead).", + "nullable": true, + "deprecated": true + }, + "firstName": { + "type": "string", + "description": "Customer's first name.", + "nullable": true + }, + "lastName": { + "type": "string", + "description": "Customer's last name.", + "nullable": true + }, + "middleName": { + "type": "string", + "description": "Customer's middle name.", + "nullable": true + }, + "nameSuffix": { + "type": "string", + "description": "Name suffix (Jr., Sr., III, etc.).", + "nullable": true + }, + "namePrefix": { + "type": "string", + "description": "Name prefix (Mr., Mrs., Dr., etc.).", + "nullable": true + }, + "address1": { + "type": "string", + "description": "Primary street address line.", + "nullable": true + }, + "address2": { + "type": "string", + "description": "Secondary address line (apartment, suite, etc.).", + "nullable": true + }, + "city": { + "type": "string", + "description": "City name.", + "nullable": true + }, + "state": { + "type": "string", + "description": "State or province.", + "nullable": true + }, + "postalCode": { + "type": "string", + "description": "Postal or ZIP code.", + "nullable": true + }, + "phone": { + "type": "string", + "description": "Primary phone number.", + "nullable": true + }, + "cellPhone": { + "type": "string", + "description": "Cell phone number.", + "nullable": true + }, + "emailAddress": { + "type": "string", + "description": "Email address.", + "nullable": true + }, + "status": { + "type": "string", + "description": "Customer account status.", + "nullable": true + }, + "mmjidNumber": { + "type": "string", + "description": "Medical marijuana identification number.", + "nullable": true + }, + "mmjidExpirationDate": { + "type": "string", + "description": "Medical marijuana ID expiration date.", + "format": "date-time", + "nullable": true + }, + "lastModifiedDateUTC": { + "type": "string", + "description": "Last modification timestamp in UTC format.", + "nullable": true + }, + "creationDate": { + "type": "string", + "description": "Customer record creation date.", + "format": "date-time", + "nullable": true + }, + "customerType": { + "type": "string", + "description": "Customer type classification.", + "nullable": true + }, + "gender": { + "type": "string", + "description": "Customer's gender.", + "nullable": true + }, + "driversLicenseHash": { + "type": "string", + "description": "SHA2_256 hash of the Driver License ID", + "nullable": true + }, + "dateOfBirth": { + "type": "string", + "description": "Customer's date of birth.", + "format": "date-time", + "nullable": true + }, + "externalCustomerId": { + "type": "string", + "description": "External system customer identifier.", + "nullable": true + }, + "createdByIntegrator": { + "type": "string", + "description": "Name of the integration system that created this customer.", + "nullable": true + }, + "isAnonymous": { + "type": "boolean", + "description": "Indicates if this is an anonymous customer record." + }, + "referralSource": { + "type": "string", + "description": "How the customer heard about the dispensary.", + "nullable": true + }, + "otherReferralSource": { + "type": "string", + "description": "Additional details about referral source when \"Other\" is selected.", + "nullable": true + }, + "springBigMemberId": { + "type": "integer", + "description": "SpringBig loyalty system member identifier.", + "format": "int32" + }, + "customIdentifier": { + "type": "string", + "description": "Custom identifier for external system integration.", + "nullable": true + }, + "discountGroups": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Collection of active discount groups for this customer.", + "nullable": true, + "readOnly": true + }, + "createdAtLocation": { + "type": "string", + "description": "Location where this customer record was created.", + "nullable": true + }, + "notes": { + "type": "string", + "description": "Additional notes about the customer.", + "nullable": true + }, + "isLoyaltyMember": { + "type": "boolean", + "description": "Indicates if customer is enrolled in loyalty program.", + "nullable": true + }, + "primaryQualifyingCondition": { + "type": "string", + "description": "Primary medical condition for medical marijuana patients.", + "nullable": true + }, + "secondaryQualifyingConditions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Additional medical conditions for medical marijuana patients.", + "nullable": true + }, + "mergedIntoCustomerId": { + "type": "integer", + "description": "Customer ID this record was merged into (if applicable).", + "format": "int32", + "nullable": true + }, + "optedIntoMarketing": { + "type": "boolean", + "description": "Customer's marketing communication preference.", + "nullable": true + }, + "loyaltyTier": { + "type": "string", + "description": "Customer's current loyalty program tier.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Extended customer model that includes search match type information for customer lookup operations." + }, + "CustomerType": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Unique identifier for the customer type.", + "format": "int32" + }, + "name": { + "type": "string", + "description": "Display name of the customer type.", + "nullable": true + }, + "isMedical": { + "type": "boolean", + "description": "Indicates whether this customer type is for medical marijuana patients." + }, + "isRetail": { + "type": "boolean", + "description": "Indicates whether this customer type is for retail (adult-use) customers." + } + }, + "additionalProperties": false, + "description": "Represents a customer type classification for cannabis dispensary operations and compliance." + }, + "DateTimeNullableOptional": { + "type": "string", + "additionalProperties": false + }, + "DecimalNullableOptional": { + "type": "number", + "additionalProperties": false + }, + "DeleteImageRequest": { + "required": ["imageId", "productId"], + "type": "object", + "properties": { + "productId": { + "type": "integer", + "description": "The unique identifier of the product that owns the image to be deleted.", + "format": "int32" + }, + "imageId": { + "type": "integer", + "description": "The unique identifier of the specific image to be deleted from the product.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Request model for deleting a product image through the product image management API." + }, + "DeliveryOrderStatus": { + "type": "object", + "properties": { + "preOrderId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "transactionId": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string", + "nullable": true + }, + "orderDate": { + "type": "string", + "format": "date-time" + }, + "customerFirstName": { + "type": "string", + "nullable": true + }, + "customerLastName": { + "type": "string", + "nullable": true + }, + "customerId": { + "type": "integer", + "format": "int32" + }, + "orderType": { + "type": "string", + "nullable": true + }, + "orderSource": { + "type": "string", + "nullable": true + }, + "rejectedReason": { + "type": "string", + "nullable": true + }, + "total": { + "type": "number", + "format": "double", + "nullable": true + }, + "subTotal": { + "type": "number", + "format": "double", + "nullable": true + }, + "totalTax": { + "type": "number", + "format": "double", + "nullable": true + }, + "streetAddress1": { + "type": "string", + "nullable": true + }, + "streetAddress2": { + "type": "string", + "nullable": true + }, + "city": { + "type": "string", + "nullable": true + }, + "deliveryState": { + "type": "string", + "nullable": true + }, + "postalCode": { + "type": "string", + "nullable": true + }, + "customerPhone": { + "type": "string", + "nullable": true + }, + "customerExpectedTimeStart": { + "type": "string", + "format": "date-time" + }, + "customerExpectedTimeEnd": { + "type": "string", + "format": "date-time" + }, + "dispatchDepartTime": { + "type": "string", + "format": "date-time" + }, + "dispatchArriveTime": { + "type": "string", + "format": "date-time" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AllocatedDeliveryItem" + }, + "nullable": true + }, + "payments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeliveryPayment" + }, + "nullable": true + }, + "deliveryStatus": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DeliveryPayment": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "amount": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "DeliveryScheduleType": { + "enum": [1, 2], + "type": "integer", + "format": "int32" + }, + "Discount": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "amount": { + "type": "number", + "format": "double" + }, + "discountId": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "DiscountApiResponse": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "externalId": { + "type": "string", + "nullable": true + }, + "validDateFrom": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "validDateTo": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "maxRedemptions": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "redemptionLimit": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "firstTimeCustomerOnly": { + "$ref": "#/components/schemas/DiscountFirstTimeCustomer" + }, + "discountDescription": { + "type": "string", + "nullable": true + }, + "discountCode": { + "type": "string", + "nullable": true + }, + "applicationMethodId": { + "$ref": "#/components/schemas/DiscountApplicationMethod" + }, + "applicationMethod": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "canStackAutomatically": { + "type": "boolean" + }, + "onlineName": { + "type": "string", + "nullable": true + }, + "locationRestrictions": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "restrictToGroupIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "startTime": { + "type": "object", + "nullable": true + }, + "endTime": { + "type": "object", + "nullable": true + }, + "monday": { + "type": "boolean", + "nullable": true + }, + "tuesday": { + "type": "boolean", + "nullable": true + }, + "wednesday": { + "type": "boolean", + "nullable": true + }, + "thursday": { + "type": "boolean", + "nullable": true + }, + "friday": { + "type": "boolean", + "nullable": true + }, + "saturday": { + "type": "boolean", + "nullable": true + }, + "sunday": { + "type": "boolean", + "nullable": true + }, + "isActive": { + "type": "boolean" + }, + "isBundledDiscount": { + "type": "boolean" + }, + "constraints": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiscountConstraintAPIResponse" + }, + "nullable": true + }, + "reward": { + "$ref": "#/components/schemas/DiscountRewardAPIResponse" + }, + "menuDisplay": { + "$ref": "#/components/schemas/DiscountMenuDisplayAPIResponse" + }, + "paymentRestrictions": { + "$ref": "#/components/schemas/DiscountPaymentRestrictionAPIResponse" + } + }, + "additionalProperties": false + }, + "DiscountApplicationMethod": { + "enum": [1, 2, 3, 4, 5, 6], + "type": "integer", + "format": "int32" + }, + "DiscountConstraintAPIResponse": { + "type": "object", + "properties": { + "discountConstraintId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "discountId": { + "type": "integer", + "format": "int32" + }, + "thresholdMin": { + "type": "number", + "format": "double", + "nullable": true + }, + "includeNonCannabis": { + "type": "boolean" + }, + "thresholdTypeId": { + "$ref": "#/components/schemas/DiscountThresholdType" + }, + "thresholdType": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "hasThreshold": { + "type": "boolean", + "readOnly": true + }, + "discountItemGroupTypeId": { + "$ref": "#/components/schemas/DiscountItemGroupType" + }, + "itemGroupType": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "restrictions": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/IRestrictionAPIResponse" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "DiscountFirstTimeCustomer": { + "enum": [0, 1, 2], + "type": "integer", + "format": "int32" + }, + "DiscountGroup": { + "type": "object", + "properties": { + "discountGroupId": { + "type": "integer", + "description": "Unique identifier for the discount group.", + "format": "int32" + }, + "discountGroupName": { + "type": "string", + "description": "Display name of the discount group for management and organization.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Discount group model for organizing and categorizing related discounts." + }, + "DiscountItemGroupType": { + "enum": [5, 6], + "type": "integer", + "format": "int32" + }, + "DiscountMenuDisplayAPIResponse": { + "type": "object", + "properties": { + "menuDisplayDescription": { + "type": "string", + "nullable": true + }, + "menuDisplayImageUrl": { + "type": "string", + "nullable": true + }, + "menuDisplayName": { + "type": "string", + "nullable": true + }, + "menuDisplayRank": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "DiscountPaymentRestrictionAPIResponse": { + "type": "object", + "properties": { + "payByBankSignupIncentive": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DiscountRestriction": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Collection of entity identifiers subject to the restriction rule.", + "nullable": true + }, + "isExclusion": { + "type": "boolean", + "description": "Indicates if this is an exclusion rule (true) or inclusion rule (false)." + } + }, + "additionalProperties": false, + "description": "Discount restriction model defining entity inclusion or exclusion rules for discount application." + }, + "DiscountRewardAPIResponse": { + "type": "object", + "properties": { + "discountRewardId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "discountId": { + "type": "integer", + "format": "int32" + }, + "calculationMethodId": { + "$ref": "#/components/schemas/CalculationMethod" + }, + "calculationMethod": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "discountValue": { + "type": "number", + "format": "double" + }, + "includeNonCannabis": { + "type": "boolean" + }, + "highestOrLowest": { + "type": "string", + "nullable": true + }, + "thresholdTypeId": { + "$ref": "#/components/schemas/DiscountThresholdType" + }, + "thresholdType": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "hasThreshold": { + "type": "boolean", + "readOnly": true + }, + "itemGroupTypeId": { + "$ref": "#/components/schemas/DiscountItemGroupType" + }, + "itemGroupType": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "thresholdMin": { + "type": "number", + "format": "double", + "nullable": true + }, + "thresholdMax": { + "type": "number", + "format": "double", + "nullable": true + }, + "applyToOnlyOneItem": { + "type": "boolean" + }, + "restrictions": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/IRestrictionAPIResponse" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "DiscountThresholdType": { + "enum": [1, 2, 3], + "type": "integer", + "format": "int32" + }, + "DriverDetail": { + "type": "object", + "properties": { + "driverId": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string", + "nullable": true + }, + "stateId": { + "type": "string", + "nullable": true + }, + "driversLicense": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "EcomCustomerEdit": { + "required": [ + "address1", + "city", + "customerType", + "firstName", + "postalCode", + "state", + "status" + ], + "type": "object", + "properties": { + "customerId": { + "type": "integer", + "description": "When specified, it updates the record, if the ID exists\nnull / unspecified will create a new customer", + "format": "int32", + "nullable": true + }, + "uniqueId": { + "type": "string", + "description": "Unique identifier for external system integration.", + "nullable": true + }, + "name": { + "type": "string", + "description": "Deprecated full name field (use FirstName and LastName instead).", + "nullable": true, + "deprecated": true + }, + "firstName": { + "minLength": 1, + "type": "string", + "description": "Customer's first name (required)." + }, + "lastName": { + "type": "string", + "description": "Customer's last name.", + "nullable": true + }, + "middleName": { + "type": "string", + "description": "Customer's middle name.", + "nullable": true + }, + "nameSuffix": { + "type": "string", + "description": "Name suffix (Jr., Sr., III, etc.).", + "nullable": true + }, + "namePrefix": { + "type": "string", + "description": "Name prefix (Mr., Mrs., Dr., etc.).", + "nullable": true + }, + "address1": { + "minLength": 1, + "type": "string", + "description": "Primary street address line (required)." + }, + "address2": { + "type": "string", + "description": "Secondary address line (apartment, suite, etc.).", + "nullable": true + }, + "city": { + "minLength": 1, + "type": "string", + "description": "City name (required)." + }, + "state": { + "minLength": 1, + "type": "string", + "description": "State or province (required)." + }, + "postalCode": { + "minLength": 1, + "type": "string", + "description": "Postal or ZIP code (required)." + }, + "phone": { + "type": "string", + "description": "Phone number.", + "nullable": true + }, + "emailAddress": { + "type": "string", + "description": "Email address.", + "nullable": true + }, + "status": { + "minLength": 1, + "type": "string", + "description": "Active; Cancelled; Hold; Banned" + }, + "mmjidNumber": { + "type": "string", + "description": "Medical marijuana identification number.", + "nullable": true + }, + "driversLicenseID": { + "type": "string", + "description": "Driver's license ID.", + "nullable": true + }, + "driversLicenseExpiration": { + "type": "string", + "description": "Driver's license expiration date.", + "format": "date-time", + "nullable": true + }, + "mmjidExpirationDate": { + "type": "string", + "description": "Medical marijuana ID expiration date.", + "format": "date-time", + "nullable": true + }, + "customerType": { + "minLength": 1, + "type": "string", + "description": "Customer type classification (required). Use CustomerTypes endpoint to retrieve active customer types for a given location." + }, + "dateOfBirth": { + "type": "string", + "description": "Customer's date of birth.", + "format": "date-time", + "nullable": true + }, + "externalCustomerId": { + "type": "string", + "description": "External system customer identifier.", + "nullable": true + }, + "gender": { + "type": "string", + "description": "Customer's gender.", + "nullable": true + }, + "idempotencyKey": { + "type": "string", + "description": "Optional idempotency key for duplicate prevention. When provided with a ConsumerKey header, ensures the same customer creation request is not processed multiple times.", + "nullable": true + }, + "referralSource": { + "type": "string", + "description": "How the customer heard about the dispensary. Use ReferralSources endpoint to retrieve values.", + "nullable": true + }, + "customIdentifier": { + "type": "string", + "description": "Custom identifier for external system integration.", + "nullable": true + }, + "notes": { + "type": "string", + "description": "Additional notes about the customer.", + "nullable": true + }, + "isLoyaltyMember": { + "type": "boolean", + "description": "Indicates if customer is enrolled in loyalty program.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "E-commerce customer data model for creating or updating customer profiles via API integration." + }, + "Employee": { + "type": "object", + "properties": { + "userId": { + "type": "integer", + "format": "int32" + }, + "loginId": { + "type": "string", + "nullable": true + }, + "fullName": { + "type": "string", + "nullable": true + }, + "defaultLocation": { + "type": "string", + "nullable": true + }, + "status": { + "type": "string", + "nullable": true + }, + "stateId": { + "type": "string", + "nullable": true + }, + "mmjExpiration": { + "type": "string", + "format": "date-time" + }, + "permissionsLocation": { + "type": "string", + "nullable": true + }, + "groups": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "FeeDonation": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the fee or donation for identification and reporting purposes.", + "nullable": true + }, + "cashValue": { + "type": "number", + "description": "Cash value of the fee or donation for financial accounting.", + "format": "double" + }, + "isRevenue": { + "type": "boolean", + "description": "Flag indicating whether the fee or donation counts as revenue for accounting purposes." + } + }, + "additionalProperties": false, + "description": "Fee and donation tracking model for cannabis dispensary compliance and accounting." + }, + "FeeDonationInfo": { + "type": "object", + "properties": { + "feeDonationId": { + "type": "integer", + "description": "Unique identifier for the specific fee or donation program.", + "format": "int32" + }, + "description": { + "type": "string", + "description": "Description of the fee or donation for customer receipts and reporting.", + "nullable": true + }, + "amount": { + "type": "number", + "description": "Amount of the fee or donation (in USD).", + "format": "double" + }, + "isRevenue": { + "type": "boolean", + "description": "Indicates whether this fee counts as business revenue for accounting purposes." + } + }, + "additionalProperties": false, + "description": "Fee and donation information associated with cannabis retail transactions." + }, + "FinishOrUnfinishBatchDetails": { + "type": "object", + "properties": { + "batchId": { + "type": "integer", + "format": "int32" + }, + "harvestCompletedOn": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "GuestListEntry": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "checkinDateUTC": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string", + "nullable": true + }, + "customerId": { + "type": "integer", + "format": "int32" + }, + "transactionId": { + "type": "integer", + "format": "int32" + }, + "transactionReferenceNumber": { + "type": "string", + "nullable": true + }, + "terminalName": { + "type": "string", + "nullable": true + }, + "customerType": { + "type": "string", + "nullable": true + }, + "phone": { + "type": "string", + "nullable": true + }, + "cellPhone": { + "type": "string", + "nullable": true + }, + "preOrderSource": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Harvest": { + "type": "object", + "properties": { + "harvestId": { + "type": "integer", + "format": "int32" + }, + "harvestName": { + "type": "string", + "nullable": true + }, + "harvestDate": { + "type": "string", + "format": "date-time" + }, + "harvestRoom": { + "type": "string", + "nullable": true + }, + "plantCount": { + "type": "integer", + "format": "int32" + }, + "plantWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "wetWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "wetWaste": { + "type": "number", + "format": "double", + "nullable": true + }, + "dryBudWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "dryShakeWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "dryWaste": { + "type": "number", + "format": "double", + "nullable": true + }, + "packageCount": { + "type": "integer", + "format": "int32" + }, + "packagedWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "lastModifiedDateUTC": { + "type": "string", + "format": "date-time" + }, + "strainName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "HarvestPlantRequest": { + "type": "object", + "properties": { + "plants": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HarvestedPlant" + }, + "description": "Collection of plants to be harvested with optional weight measurements", + "nullable": true + }, + "harvestId": { + "type": "integer", + "description": "Target harvest record ID for associating harvested plants", + "format": "int32" + }, + "harvestedOn": { + "type": "string", + "description": "Date and time when harvest occurred (optional, defaults to current UTC time if not specified)", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for moving cannabis plants from cultivation to harvest status with optional weight tracking.\n\n**Request Behavior:**\n- Moves specified plants from cultivation status to harvesting status\n- Supports bulk processing of multiple plants in single operation\n- Optional weight tracking for harvest yield management\n- Integrates with external cultivation systems when configured\n\n**Validation:**\n- All plant IDs must exist and be accessible to the authenticated location\n- Plants must be in valid status for harvesting (typically Active status)\n- Harvest ID must correspond to existing harvest record" + }, + "HarvestWasteDetail": { + "type": "object", + "properties": { + "harvestId": { + "type": "integer", + "description": "Identifier for the harvest batch generating this waste.", + "format": "int32" + }, + "wasteType": { + "type": "string", + "description": "Type or category of waste material from the harvest.", + "nullable": true + }, + "wasteAmount": { + "type": "number", + "description": "Quantity of waste material generated from the harvest.", + "format": "double" + }, + "unitId": { + "type": "integer", + "description": "Unit of measurement identifier for the waste amount.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Harvest waste detail model for tracking waste generated from specific harvest operations." + }, + "HarvestWasteDetailWaste": { + "type": "object", + "properties": { + "wasteId": { + "type": "integer", + "description": "Unique identifier for the waste record (null for new waste creation).", + "format": "int32", + "nullable": true + }, + "referenceNo": { + "type": "string", + "description": "Reference number for waste tracking and documentation.", + "nullable": true + }, + "comments": { + "type": "string", + "description": "Additional comments or notes about the waste disposal.", + "nullable": true + }, + "wasteDate": { + "type": "string", + "description": "Date when the waste disposal occurred.", + "format": "date-time", + "nullable": true + }, + "wasteDetail": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HarvestWasteDetail" + }, + "description": "Collection of waste detail records containing specific item information.", + "nullable": true + }, + "lspId": { + "type": "integer", + "description": "Licensed Service Provider identifier (internal use only).", + "format": "int32", + "nullable": true + }, + "locId": { + "type": "integer", + "description": "Location identifier (internal use only).", + "format": "int32", + "nullable": true + }, + "roomRequired": { + "type": "boolean", + "description": "Indicates if room identification is required for this waste type (internal use only).", + "nullable": true + }, + "isBioTrack": { + "type": "boolean", + "description": "Indicates if this waste integrates with BioTrack system (internal use only).", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Generic waste record model containing waste disposal information and associated detail records for cannabis compliance and waste tracking." + }, + "HarvestedPlant": { + "type": "object", + "properties": { + "plantId": { + "type": "integer", + "description": "Unique LeafLogix plant identifier for the plant being harvested", + "format": "int32" + }, + "weight": { + "type": "number", + "description": "Optional harvest weight measurement (typically wet weight in grams)", + "format": "double", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Individual plant harvest information with optional weight tracking for yield management.\n\n**Weight Tracking:**\n- Weight is optional but recommended for harvest yield analysis\n- Typically represents wet weight at time of harvest\n- Used for compliance reporting and operational analytics" + }, + "IRestrictionAPIResponse": { + "type": "object", + "properties": { + "isExclusion": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "Int32IEnumerableOptional": { + "type": "array", + "additionalProperties": false + }, + "Int32NullableOptional": { + "type": "integer", + "additionalProperties": false + }, + "IntegratedPayment": { + "type": "object", + "properties": { + "integrationType": { + "type": "string", + "description": "Type of integrated payment processor used for the transaction (e.g., \"CreditCard\", \"CanPay\", \"ACH\").", + "nullable": true + }, + "integratedPaid": { + "type": "number", + "description": "Amount paid through the integrated payment system (in USD).", + "format": "double" + }, + "externalPaymentId": { + "type": "string", + "description": "External payment identifier from the integrated payment processor for transaction tracking.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Integrated payment processing information for cannabis transactions processed through connected payment systems." + }, + "InventoryDiscrepancy": { + "type": "object", + "properties": { + "inventoryId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "packageId": { + "type": "string", + "nullable": true + }, + "quantity": { + "type": "number", + "format": "double" + }, + "roomId": { + "type": "integer", + "format": "int32" + }, + "unitId": { + "type": "integer", + "format": "int32" + }, + "externalQuantity": { + "type": "number", + "format": "double" + }, + "externalUnitId": { + "type": "integer", + "format": "int32" + }, + "equivalentExternalQuantity": { + "type": "number", + "format": "double", + "nullable": true + }, + "difference": { + "type": "number", + "format": "double", + "readOnly": true + }, + "productName": { + "type": "string", + "nullable": true + }, + "room": { + "type": "string", + "nullable": true + }, + "externalRoom": { + "type": "string", + "nullable": true + }, + "batchModeQuantity": { + "type": "number", + "format": "double", + "nullable": true + }, + "bioTrackCategoryName": { + "type": "string", + "nullable": true + }, + "externalBioTrackCategoryName": { + "type": "string", + "nullable": true + }, + "sku": { + "type": "string", + "nullable": true + }, + "unitErrorMsg": { + "type": "string", + "nullable": true + }, + "rooms": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "serialNumber": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "InventoryIntegrationReconResponse": { + "type": "object", + "properties": { + "lastUpdated": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "discrepancies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InventoryDiscrepancy" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "InventoryItem": { + "type": "object", + "properties": { + "unitWeightUnit": { + "type": "string", + "description": "Unit of measurement for unit weight, always \"g\" (grams).", + "nullable": true + }, + "inventoryId": { + "type": "integer", + "description": "Unique inventory record identifier for this specific inventory item.", + "format": "int32" + }, + "productId": { + "type": "integer", + "description": "Product identifier linking this inventory to the product catalog.", + "format": "int32" + }, + "sku": { + "type": "string", + "description": "Stock Keeping Unit (SKU) code for inventory tracking and identification.", + "nullable": true + }, + "productName": { + "type": "string", + "description": "Display name of the product for customer-facing applications.", + "nullable": true + }, + "description": { + "type": "string", + "description": "Detailed product description including effects, characteristics, and usage information.", + "nullable": true + }, + "categoryId": { + "type": "integer", + "description": "Category identifier for product classification (optional).", + "format": "int32", + "nullable": true + }, + "category": { + "type": "string", + "description": "Category name for product classification and filtering.", + "nullable": true + }, + "imageUrl": { + "type": "string", + "description": "URL path to product image for display purposes.", + "nullable": true + }, + "quantityAvailable": { + "type": "number", + "description": "Current available quantity for sale or transfer.", + "format": "double" + }, + "quantityUnits": { + "type": "string", + "description": "Unit of measurement for the available quantity (e.g., \"g\", \"mg\", \"ea\").", + "nullable": true + }, + "unitWeight": { + "type": "number", + "description": "Weight per unit in grams for dosing and compliance calculations.", + "format": "double" + }, + "flowerEquivalent": { + "type": "number", + "description": "Flower equivalent amount in grams for compliance tracking.", + "format": "double" + }, + "recFlowerEquivalent": { + "type": "number", + "description": "Recreational flower equivalent amount in grams (optional).", + "format": "double", + "nullable": true + }, + "flowerEquivalentUnits": { + "type": "string", + "description": "Unit of measurement for flower equivalent, always \"g\" (grams).", + "nullable": true, + "readOnly": true + }, + "batchId": { + "type": "integer", + "description": "Batch identifier for lot tracking and quality control.", + "format": "int32" + }, + "batchName": { + "type": "string", + "description": "Human-readable batch name or lot number for tracking.", + "nullable": true + }, + "packageId": { + "type": "string", + "description": "Package identifier for compliance tracking and traceability.", + "nullable": true + }, + "packageStatus": { + "type": "string", + "description": "Current status of the package (e.g., \"Active\", \"Testing\", \"Quarantine\").", + "nullable": true + }, + "unitPrice": { + "type": "number", + "description": "Base unit price for retail sales.", + "format": "double" + }, + "medUnitPrice": { + "type": "number", + "description": "Medical program pricing (optional, different from retail).", + "format": "double", + "nullable": true + }, + "recUnitPrice": { + "type": "number", + "description": "Recreational program pricing (optional, different from medical).", + "format": "double", + "nullable": true + }, + "strainId": { + "type": "integer", + "description": "Strain identifier for cannabis products (optional).", + "format": "int32", + "nullable": true + }, + "strain": { + "type": "string", + "description": "Strain name for cannabis products.", + "nullable": true + }, + "strainType": { + "type": "string", + "description": "Cannabis strain classification (Hybrid, Indica, Sativa, CBD).", + "nullable": true + }, + "size": { + "type": "string", + "description": "Product size designation for packaging and dosing information.", + "nullable": true + }, + "labResults": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LabResult" + }, + "description": "Collection of laboratory test results for this batch (included when includeLabResults=true).", + "nullable": true + }, + "testedDate": { + "type": "string", + "description": "Date when laboratory testing was completed (optional).", + "format": "date-time", + "nullable": true + }, + "sampleDate": { + "type": "string", + "description": "Date when sample was collected for laboratory testing (optional).", + "format": "date-time", + "nullable": true + }, + "packagedDate": { + "type": "string", + "description": "Date when product was packaged for distribution (optional).", + "format": "date-time", + "nullable": true + }, + "manufacturingDate": { + "type": "string", + "description": "Date when product was manufactured or produced (optional).", + "format": "date-time", + "nullable": true + }, + "lastModifiedDateUtc": { + "type": "string", + "description": "Last modification timestamp in UTC for data synchronization.", + "format": "date-time", + "nullable": true + }, + "labTestStatus": { + "type": "string", + "description": "Current status of laboratory testing (e.g., \"Passed\", \"Failed\", \"Pending\").", + "nullable": true + }, + "vendorId": { + "type": "integer", + "description": "Vendor identifier for the supplier of this inventory (optional).", + "format": "int32", + "nullable": true + }, + "vendor": { + "type": "string", + "description": "Vendor name for the supplier of this inventory.", + "nullable": true + }, + "expirationDate": { + "type": "string", + "description": "Product expiration date for compliance and quality control (optional).", + "format": "date-time", + "nullable": true + }, + "roomQuantities": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InventoryRoomQuantity" + }, + "description": "Quantity breakdown by storage room/location (included when includeRoomQuantities=true).", + "nullable": true + }, + "pricingTierName": { + "type": "string", + "description": "Pricing tier classification for bulk pricing strategies.", + "nullable": true + }, + "alternateName": { + "type": "string", + "description": "Alternative product name for display purposes.", + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InventoryTag" + }, + "description": "Collection of compliance tags associated with this inventory package.", + "nullable": true + }, + "brandId": { + "type": "integer", + "description": "Brand identifier for branded products (optional).", + "format": "int32", + "nullable": true + }, + "brandName": { + "type": "string", + "description": "Brand name for branded products.", + "nullable": true + }, + "medicalOnly": { + "type": "boolean", + "description": "Indicates if product is restricted to medical program only." + }, + "externalPackageId": { + "type": "string", + "description": "External compliance system ID (METRC or BioTrack) for regulatory tracking.", + "nullable": true + }, + "producer": { + "type": "string", + "description": "Producer name for cultivation and manufacturing tracking.", + "nullable": true + }, + "producerId": { + "type": "integer", + "description": "Producer identifier for cultivation and manufacturing tracking (optional).", + "format": "int32", + "nullable": true + }, + "lineage": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageLineage" + }, + "description": "Package lineage information for traceability and compliance tracking.", + "nullable": true + }, + "potencyIndicator": { + "type": "string", + "description": "Potency classification indicator for dosing guidance.", + "nullable": true + }, + "masterCategory": { + "type": "string", + "description": "Master category classification for product grouping.", + "nullable": true + }, + "effectivePotencyMg": { + "type": "number", + "description": "Effective potency in milligrams for dosing calculations (optional).", + "format": "double", + "nullable": true + }, + "isCannabis": { + "type": "boolean", + "description": "Indicates if product contains cannabis or is cannabis-related." + }, + "packageNDC": { + "type": "string", + "description": "National Drug Code for pharmaceutical tracking (optional).", + "nullable": true + }, + "labResultUrl": { + "type": "string", + "description": "URL to certificate of analysis or lab testing document.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Inventory item model representing current stock and product details for available inventory." + }, + "InventoryRoomQuantity": { + "type": "object", + "properties": { + "roomId": { + "type": "integer", + "description": "Room identifier for the storage location.", + "format": "int32" + }, + "room": { + "type": "string", + "description": "Room name or description for the storage location.", + "nullable": true + }, + "quantityAvailable": { + "type": "number", + "description": "Quantity of cannabis product available in this specific room location.", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Cannabis inventory quantity tracking model by room location for facility management and compliance." + }, + "InventorySnapshot": { + "required": [ + "inventoryId", + "packageId", + "product", + "productId", + "quantity", + "room", + "roomId", + "sku", + "snapshotDate", + "unit", + "unitId" + ], + "type": "object", + "properties": { + "sku": { + "minLength": 1, + "type": "string", + "description": "Stock Keeping Unit (SKU) code for product identification." + }, + "product": { + "minLength": 1, + "type": "string", + "description": "Product name as it existed at the snapshot date." + }, + "productId": { + "type": "integer", + "description": "Product identifier linking to the product catalog.", + "format": "int32" + }, + "room": { + "minLength": 1, + "type": "string", + "description": "Storage room name where inventory was located at snapshot time." + }, + "roomId": { + "type": "integer", + "description": "Storage room identifier for location tracking.", + "format": "int32" + }, + "vendor": { + "type": "string", + "description": "Vendor name for the supplier of this inventory (optional).", + "nullable": true + }, + "packageId": { + "minLength": 1, + "type": "string", + "description": "Package identifier for compliance tracking and traceability." + }, + "batchName": { + "type": "string", + "description": "Batch name or lot number for quality tracking (optional).", + "nullable": true + }, + "batchId": { + "type": "integer", + "description": "Batch identifier for lot tracking (optional).", + "format": "int32", + "nullable": true + }, + "quantity": { + "type": "number", + "description": "Inventory quantity as it existed at the snapshot date.", + "format": "double" + }, + "totalCost": { + "type": "number", + "description": "Total cost value of the inventory quantity (optional).", + "format": "double", + "nullable": true + }, + "unit": { + "minLength": 1, + "type": "string", + "description": "Unit of measurement for the quantity." + }, + "unitId": { + "type": "integer", + "description": "Unit identifier for the measurement type.", + "format": "int32" + }, + "status": { + "type": "string", + "description": "Inventory status at the time of snapshot (e.g., \"Active\", \"Quarantine\").", + "nullable": true + }, + "snapshotDate": { + "type": "string", + "description": "Date and time when this inventory snapshot was captured.", + "format": "date-time" + }, + "inventoryId": { + "type": "integer", + "description": "Inventory record identifier linking to the specific inventory item.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Historical inventory snapshot model representing inventory levels at a specific point in time." + }, + "InventoryTag": { + "type": "object", + "properties": { + "tagId": { + "type": "integer", + "format": "int32" + }, + "tagName": { + "type": "string", + "nullable": true + }, + "packageId": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "InventoryTransaction": { + "required": ["inventoryTransactionId"], + "type": "object", + "properties": { + "inventoryTransactionId": { + "type": "integer", + "description": "Unique identifier for the inventory transaction record.", + "format": "int32" + }, + "transactionType": { + "type": "string", + "description": "Type of inventory transaction performed.\n**Options**: Move, Convert, Adjust, Combine, Receive, Change Product, Discontinue, Detail Update, Reconciliation, Create Package", + "nullable": true + }, + "product": { + "type": "string", + "description": "Product name at the time of transaction.", + "nullable": true + }, + "sku": { + "type": "string", + "description": "Stock Keeping Unit (SKU) code for the product.", + "nullable": true + }, + "productId": { + "type": "integer", + "description": "Product identifier linking to the product catalog.", + "format": "int32" + }, + "unit": { + "type": "string", + "description": "Unit of measurement for the transaction quantities.", + "nullable": true + }, + "packageId": { + "type": "string", + "description": "Package identifier for compliance tracking and traceability.", + "nullable": true + }, + "externalPackageId": { + "type": "string", + "description": "External package identifier from integrated compliance systems.", + "nullable": true + }, + "batchId": { + "type": "integer", + "description": "Batch identifier for lot tracking (optional).", + "format": "int32", + "nullable": true + }, + "batchName": { + "type": "string", + "description": "Batch name or lot number for quality tracking (optional).", + "nullable": true + }, + "quantity": { + "type": "number", + "description": "Transaction quantity for non-adjustment operations (Move, Convert, Receive, etc.).", + "format": "double", + "nullable": true + }, + "fromQuantity": { + "type": "number", + "description": "Original quantity before adjustment (used for Adjust transaction type).", + "format": "double", + "nullable": true + }, + "toQuantity": { + "type": "number", + "description": "New quantity after adjustment (used for Adjust transaction type).", + "format": "double", + "nullable": true + }, + "reason": { + "type": "string", + "description": "Reason for adjustment (used for Adjust transaction type).", + "nullable": true + }, + "receiveInventoryHistoryId": { + "type": "integer", + "description": "Receive inventory history identifier for received inventory linkage (optional).", + "format": "int32", + "nullable": true + }, + "fromLocation": { + "type": "string", + "description": "Source location name for Move transactions.", + "nullable": true + }, + "fromRoom": { + "type": "string", + "description": "Source room name for Move transactions.", + "nullable": true + }, + "toLocation": { + "type": "string", + "description": "Destination location name for Move transactions.", + "nullable": true + }, + "toRoom": { + "type": "string", + "description": "Destination room name for Move transactions.", + "nullable": true + }, + "conversionTransactionID": { + "type": "integer", + "description": "Conversion transaction identifier for Convert operations (optional).", + "format": "int32", + "nullable": true + }, + "transactionBy": { + "type": "string", + "description": "Username or identifier of the person who performed the transaction.", + "nullable": true + }, + "transactionDate": { + "type": "string", + "description": "Date and time when the transaction was performed.", + "format": "date-time" + }, + "unitCost": { + "type": "number", + "description": "Unit cost of the package at the time of transaction (optional).", + "format": "double", + "nullable": true + }, + "purchaseOrderId": { + "type": "integer", + "description": "Purchase order identifier for received inventory linkage (optional).", + "format": "int32", + "nullable": true + }, + "inventoryId": { + "type": "integer", + "description": "Unique inventory item identifier affected by this transaction.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Inventory transaction record model representing historical inventory movement and modification operations." + }, + "JournalEntry": { + "type": "object", + "properties": { + "journalEntryId": { + "type": "integer", + "description": "Unique identifier for the journal entry.", + "format": "int32" + }, + "subject": { + "type": "string", + "description": "Brief title or summary of the journal entry.", + "nullable": true + }, + "body": { + "type": "string", + "description": "Detailed content and notes for the journal entry.", + "nullable": true + }, + "date": { + "type": "string", + "description": "Date and time when the journal entry was created or should be dated.", + "format": "date-time" + } + }, + "additionalProperties": false, + "description": "Represents a customer journal entry containing notes and interaction history for customer service tracking." + }, + "LabResult": { + "type": "object", + "properties": { + "labTest": { + "type": "string", + "description": "Name of the laboratory test performed (e.g., \"THC\", \"CBD\", \"Myrcene\", \"Total Aerobic Count\").", + "nullable": true + }, + "value": { + "type": "number", + "description": "Numeric test result value (null if not detected or not applicable).", + "format": "double", + "nullable": true + }, + "labResultUnitId": { + "$ref": "#/components/schemas/LabResultUnit" + }, + "labResultUnit": { + "type": "string", + "description": "Human-readable unit name corresponding to the LabResultUnitId.", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Laboratory testing result model for cannabis and cannabis product analysis." + }, + "LabResultUnit": { + "enum": [1, 2, 3, 4, 5, 6], + "type": "integer", + "format": "int32" + }, + "LabResultUnitData": { + "type": "object", + "properties": { + "labResultUnitId": { + "type": "integer", + "description": "Unique identifier for the lab result unit type.", + "format": "int32" + }, + "labResultUnit": { + "type": "string", + "description": "Display name of the lab result unit (e.g., \"mg\", \"%\", \"mg/g\", \"ND\", \"LOQ\", \"Pass/Fail\").", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Laboratory result unit data model for cannabis testing measurements and reporting." + }, + "LineItemTaxInfo": { + "type": "object", + "properties": { + "rateName": { + "type": "string", + "description": "Name of the tax rate applied (e.g., \"State Excise Tax\", \"City Cannabis Tax\", \"Sales Tax\").", + "nullable": true + }, + "rate": { + "type": "number", + "description": "Tax rate as a decimal percentage (e.g., 0.0875 for 8.75% tax rate).", + "format": "double" + }, + "amount": { + "type": "number", + "description": "Calculated tax amount applied to the line item (in USD).", + "format": "double" + }, + "transactionItemId": { + "type": "integer", + "description": "Reference identifier linking this tax information back to the specific transaction line item.\nNot guaranteed to be unique outside of a single transaction.", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Tax information applied to individual transaction line items in cannabis retail operations." + }, + "Lineage": { + "type": "object", + "properties": { + "lineageId": { + "type": "integer", + "description": "Unique identifier for the genetic lineage.", + "format": "int32" + }, + "lineageName": { + "type": "string", + "description": "Display name for the genetic lineage (e.g., \"Indica\", \"Sativa\", \"Hybrid\").", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Cannabis genetic lineage model containing hereditary classification information for product categorization and genetic tracking." + }, + "LocationIdentity": { + "type": "object", + "properties": { + "locationId": { + "type": "integer", + "description": "Unique identifier for the cannabis dispensary location.", + "format": "int32" + }, + "lspId": { + "type": "integer", + "description": "Unique identifier for the parent company (LSP - Licensed Service Provider).", + "format": "int32" + }, + "locationName": { + "type": "string", + "description": "Business name of the cannabis dispensary location.", + "nullable": true + }, + "lspName": { + "type": "string", + "description": "Company name of the parent organization (Licensed Service Provider).", + "nullable": true + }, + "address": { + "type": "string", + "description": "Primary street address of the dispensary location.", + "nullable": true + }, + "address2": { + "type": "string", + "description": "Secondary address line (suite, unit, etc.) if applicable.", + "nullable": true + }, + "city": { + "type": "string", + "description": "City where the dispensary is located.", + "nullable": true + }, + "state": { + "type": "string", + "description": "State or province where the dispensary is licensed to operate.", + "nullable": true + }, + "postalCode": { + "type": "string", + "description": "Postal code (ZIP code) for the dispensary location.", + "nullable": true + }, + "licenseNumber": { + "type": "string", + "description": "State-issued cannabis business license number for regulatory compliance.", + "nullable": true + }, + "doingBusinessAs": { + "type": "string", + "description": "\"Doing Business As\" name if different from the legal business name.", + "nullable": true + }, + "shareCustomerProfiles": { + "type": "boolean", + "description": "Indicates whether customer profiles are shared across locations within the organization." + }, + "globalId": { + "type": "string", + "description": "Legacy global unique identifier for the location (deprecated).", + "format": "uuid", + "nullable": true, + "deprecated": true + }, + "locationGlobalId": { + "type": "string", + "description": "Global unique identifier for the location across all systems and integrations.", + "format": "uuid", + "nullable": true + }, + "lspGlobalId": { + "type": "string", + "description": "Global unique identifier for the parent company (LSP) across all systems.", + "format": "uuid", + "nullable": true + }, + "region": { + "type": "string", + "description": "Regional identifier for compliance and API routing (internal use only).", + "nullable": true + }, + "regionId": { + "type": "string", + "description": "Base64-encoded SHA256 hash of the region identifier for secure regional routing.", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Location identity model containing complete location and parent company information for API key verification and context identification." + }, + "LocationMapping": { + "type": "object", + "properties": { + "locationName": { + "type": "string", + "description": "Name of the location where the discount applies.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Location mapping model for associating discounts with specific business locations." + }, + "LocationProductOverride": { + "type": "object", + "properties": { + "productId": { + "type": "integer", + "format": "int32" + }, + "price": { + "type": "number", + "format": "double", + "nullable": true + }, + "recPrice": { + "type": "number", + "format": "double", + "nullable": true + }, + "cost": { + "type": "number", + "format": "double", + "nullable": true + }, + "onlineAvailable": { + "type": "boolean", + "nullable": true + }, + "posAvailable": { + "type": "boolean", + "nullable": true + }, + "maxPurchasable": { + "type": "number", + "format": "double", + "nullable": true + }, + "lowInventoryThreshold": { + "type": "number", + "format": "double", + "nullable": true + }, + "customMetadata": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LocationProductOverrideRequest": { + "type": "object", + "properties": { + "productId": { + "type": "integer", + "description": "Product identifier for the product being configured with location-specific overrides.", + "format": "int32" + }, + "price": { + "$ref": "#/components/schemas/DecimalNullableOptional" + }, + "recPrice": { + "$ref": "#/components/schemas/DecimalNullableOptional" + }, + "cost": { + "$ref": "#/components/schemas/DecimalNullableOptional" + }, + "onlineAvailable": { + "$ref": "#/components/schemas/BooleanNullableOptional" + }, + "posAvailable": { + "$ref": "#/components/schemas/BooleanNullableOptional" + }, + "maxPurchasable": { + "$ref": "#/components/schemas/DecimalNullableOptional" + }, + "lowInventoryThreshold": { + "$ref": "#/components/schemas/DecimalNullableOptional" + }, + "customMetadata": { + "$ref": "#/components/schemas/StringOptional" + } + }, + "additionalProperties": false + }, + "LocationResponse": { + "type": "object", + "properties": { + "locationName": { + "type": "string", + "nullable": true + }, + "locId": { + "type": "integer", + "format": "int32" + }, + "licenseNumber": { + "type": "string", + "nullable": true + }, + "outcome": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "outcomeId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "broadcastedTo": { + "type": "string", + "nullable": true + }, + "errorDetail": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "LoyaltySnapshot": { + "type": "object", + "properties": { + "customerId": { + "type": "integer", + "description": "Unique identifier for the customer in the loyalty program.\nLinks this loyalty snapshot to the specific customer account.", + "format": "int32" + }, + "loyaltyBalance": { + "type": "number", + "description": "Current available loyalty points balance for the customer.\nRepresents points that can be redeemed for rewards or discounts.", + "format": "double" + }, + "loyaltySpent": { + "type": "number", + "description": "Total loyalty points redeemed/spent by the customer over their lifetime.\nHistorical record of all point redemptions and rewards claimed.", + "format": "double" + }, + "loyaltyEarned": { + "type": "number", + "description": "Total loyalty points earned by the customer over their lifetime.\nHistorical record of all points awarded through purchases and activities.", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Represents a customer's loyalty program balance and activity snapshot for reporting purposes.\n\nContains current point balances and historical activity for individual customers within the\nloyalty program. Used for daily balance reporting, customer service inquiries, and loyalty\nprogram analytics. Data reflects nightly batch processing and may not include real-time changes." + }, + "ManualPayment": { + "type": "object", + "properties": { + "manualPaymentProcessorName": { + "type": "string", + "description": "Name of the manual payment processor or handling method (e.g., \"Cash\", \"Check\", \"Money Order\").", + "nullable": true + }, + "manualPaid": { + "type": "number", + "description": "Amount paid through the manual payment method (in USD).", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Manual payment information for cannabis transactions processed outside integrated payment systems." + }, + "MatureBatchDetails": { + "type": "object", + "properties": { + "batchId": { + "type": "integer", + "description": "Batch identifier for the mature plant batch being created.", + "format": "int32" + }, + "serialNumbers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Collection of individual plant serial numbers within the mature batch for state tracking compliance.", + "nullable": true + }, + "batchStage": { + "type": "string", + "description": "Growth stage designation for the mature batch (e.g., \"Vegetative\", \"Flowering\").", + "nullable": true + }, + "roomId": { + "type": "integer", + "description": "Room identifier for the mature batch location assignment.", + "format": "int32" + }, + "tableId": { + "type": "integer", + "description": "Table identifier within the room for precise location tracking (optional).", + "format": "int32", + "nullable": true + }, + "dateCreated": { + "type": "string", + "description": "Date when the mature batch was created for cultivation timeline documentation.", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Detailed specification for creating individual mature plant batches with compliance tracking information." + }, + "MovePlantRequest": { + "type": "object", + "properties": { + "plantIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Collection of LeafLogix plant IDs to move to the target room", + "nullable": true + }, + "roomId": { + "type": "integer", + "description": "Target cultivation room ID within the same facility where plants will be moved", + "format": "int32" + }, + "tableId": { + "type": "integer", + "description": "Optional table ID within the target room for precise plant positioning (optional)", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for moving cannabis plants to a different cultivation room or table within the same facility.\n\n**Movement Behavior:**\n- Moves specified plants to target room within same facility\n- Optional table assignment for precise cultivation area management\n- Validates target room belongs to same facility for security\n- Automatically updates plant cultivation stage if room has associated stage\n\n**Facility Restrictions:**\n- Target room must belong to same facility as requesting user\n- Cross-facility plant movements are prohibited for security and compliance\n- All plant IDs must be accessible to the authenticated location\n\n**Integration:**\n- Movement synchronized with external cultivation systems when configured\n- Supports cultivation workflow automation and environmental optimization" + }, + "ObjectWaste": { + "type": "object", + "properties": { + "wasteId": { + "type": "integer", + "description": "Unique identifier for the waste record (null for new waste creation).", + "format": "int32", + "nullable": true + }, + "referenceNo": { + "type": "string", + "description": "Reference number for waste tracking and documentation.", + "nullable": true + }, + "comments": { + "type": "string", + "description": "Additional comments or notes about the waste disposal.", + "nullable": true + }, + "wasteDate": { + "type": "string", + "description": "Date when the waste disposal occurred.", + "format": "date-time", + "nullable": true + }, + "wasteDetail": { + "type": "array", + "items": { + "type": "object" + }, + "description": "Collection of waste detail records containing specific item information.", + "nullable": true + }, + "lspId": { + "type": "integer", + "description": "Licensed Service Provider identifier (internal use only).", + "format": "int32", + "nullable": true + }, + "locId": { + "type": "integer", + "description": "Location identifier (internal use only).", + "format": "int32", + "nullable": true + }, + "roomRequired": { + "type": "boolean", + "description": "Indicates if room identification is required for this waste type (internal use only).", + "nullable": true + }, + "isBioTrack": { + "type": "boolean", + "description": "Indicates if this waste integrates with BioTrack system (internal use only).", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Generic waste record model containing waste disposal information and associated detail records for cannabis compliance and waste tracking." + }, + "PackageLineage": { + "type": "object", + "properties": { + "packageId": { + "type": "string", + "description": "Package identifier for the current package in the lineage chain.", + "nullable": true + }, + "antecedentPackageDistance": { + "type": "integer", + "description": "Number of generations between current package and antecedent package in the lineage chain.", + "format": "int32" + }, + "antecedentIsHarvest": { + "type": "boolean", + "description": "Flag indicating whether the antecedent package originated from a harvest operation." + }, + "batchName": { + "type": "string", + "description": "Batch name for the current package for lot tracking and quality control.", + "nullable": true + }, + "antecedentBatchName": { + "type": "string", + "description": "Batch name of the antecedent package for lineage and quality tracking.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Package lineage tracking model for cannabis product traceability and regulatory compliance." + }, + "Plant": { + "type": "object", + "properties": { + "plantId": { + "type": "integer", + "format": "int32" + }, + "serialNumber": { + "type": "string", + "nullable": true + }, + "growthPhase": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "harvestedWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "status": { + "type": "string", + "nullable": true + }, + "plantCount": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "isMother": { + "type": "boolean" + }, + "motherPlantId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "plantedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "addedToHarvestOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "harvestDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "destroyedDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "plantGroupName": { + "type": "string", + "nullable": true + }, + "strain": { + "type": "string", + "nullable": true + }, + "room": { + "type": "string", + "nullable": true + }, + "table": { + "type": "string", + "nullable": true + }, + "vegetationStartedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "vegetationEndedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "floweringStartedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "floweringEndedOn": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "currentPhaseStartDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "lastModifiedDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "daysInCurrentPhase": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "floweringRoom": { + "type": "string", + "nullable": true + }, + "floweringTable": { + "type": "string", + "nullable": true + }, + "vegetationRoom": { + "type": "string", + "nullable": true + }, + "vegetationTable": { + "type": "string", + "nullable": true + }, + "daysInFlowering": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "daysInVegetation": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "batchId": { + "type": "integer", + "format": "int32" + }, + "harvestId": { + "type": "integer", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false + }, + "PlantWasteDetail": { + "type": "object", + "properties": { + "plantId": { + "type": "integer", + "description": "Identifier for the plant generating this waste.", + "format": "int32" + }, + "wasteType": { + "type": "string", + "description": "Type or category of waste material from the plant.", + "nullable": true + }, + "wasteAmount": { + "type": "number", + "description": "Quantity of waste material generated from the plant.", + "format": "double" + }, + "unitId": { + "type": "integer", + "description": "Unit of measurement identifier for the waste amount.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Plant waste detail model for tracking waste generated from specific plant disposal operations." + }, + "PlantWasteDetailWaste": { + "type": "object", + "properties": { + "wasteId": { + "type": "integer", + "description": "Unique identifier for the waste record (null for new waste creation).", + "format": "int32", + "nullable": true + }, + "referenceNo": { + "type": "string", + "description": "Reference number for waste tracking and documentation.", + "nullable": true + }, + "comments": { + "type": "string", + "description": "Additional comments or notes about the waste disposal.", + "nullable": true + }, + "wasteDate": { + "type": "string", + "description": "Date when the waste disposal occurred.", + "format": "date-time", + "nullable": true + }, + "wasteDetail": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PlantWasteDetail" + }, + "description": "Collection of waste detail records containing specific item information.", + "nullable": true + }, + "lspId": { + "type": "integer", + "description": "Licensed Service Provider identifier (internal use only).", + "format": "int32", + "nullable": true + }, + "locId": { + "type": "integer", + "description": "Location identifier (internal use only).", + "format": "int32", + "nullable": true + }, + "roomRequired": { + "type": "boolean", + "description": "Indicates if room identification is required for this waste type (internal use only).", + "nullable": true + }, + "isBioTrack": { + "type": "boolean", + "description": "Indicates if this waste integrates with BioTrack system (internal use only).", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Generic waste record model containing waste disposal information and associated detail records for cannabis compliance and waste tracking." + }, + "PostImmatureBatchRequest": { + "type": "object", + "properties": { + "batches": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BatchDetails" + }, + "description": "Collection of immature plant batch specifications for bulk batch creation operations.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for creating immature plant batches in cannabis cultivation operations." + }, + "PreOrderItem": { + "required": ["productId", "quantity"], + "type": "object", + "properties": { + "productId": { + "type": "integer", + "format": "int32" + }, + "quantity": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "PreOrderRedemption": { + "required": ["redemptionId", "redemptionType"], + "type": "object", + "properties": { + "productId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "redemptionType": { + "minLength": 1, + "type": "string" + }, + "redemptionId": { + "minLength": 1, + "type": "string" + }, + "redemptionDescription": { + "type": "string", + "nullable": true + }, + "redemptionCallbackUrl": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PreOrderRedemptionIEnumerableOptional": { + "type": "array", + "additionalProperties": false + }, + "PreOrderStatus": { + "type": "object", + "properties": { + "preOrderId": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string", + "nullable": true + }, + "transactionId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "orderDate": { + "type": "string", + "format": "date-time" + }, + "customerFirstName": { + "type": "string", + "nullable": true + }, + "customerLastName": { + "type": "string", + "nullable": true + }, + "customerId": { + "type": "integer", + "format": "int32" + }, + "orderType": { + "type": "string", + "nullable": true + }, + "orderSource": { + "type": "string", + "nullable": true + }, + "rejectedReason": { + "type": "string", + "nullable": true + }, + "isCancellable": { + "type": "boolean" + }, + "isUpdateable": { + "type": "boolean" + }, + "total": { + "type": "number", + "format": "double", + "nullable": true + }, + "subTotal": { + "type": "number", + "format": "double", + "nullable": true + }, + "totalTax": { + "type": "number", + "format": "double", + "nullable": true + }, + "sourceSystem": { + "type": "string", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AllocatedPreOrderItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PrecartItem": { + "type": "object", + "properties": { + "productId": { + "type": "integer", + "format": "int32" + }, + "quantity": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "PriceCartRequest": { + "type": "object", + "properties": { + "cart": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PrecartItem" + }, + "description": "Collection of products in the customer's shopping cart with quantities and specifications.", + "nullable": true + }, + "customerTypeId": { + "type": "integer", + "description": "Customer type identifier for pricing tier and discount eligibility (e.g., medical, recreational).", + "format": "int32", + "nullable": true + }, + "customerId": { + "type": "integer", + "description": "Unique customer identifier for personalized pricing and loyalty program benefits.", + "format": "int32", + "nullable": true + }, + "deliveryStreet": { + "type": "string", + "description": "Primary street address for delivery orders (used for tax calculation and delivery fee estimation).", + "nullable": true + }, + "deliveryStreet2": { + "type": "string", + "description": "Secondary address information (apartment, suite, unit number) for delivery orders.", + "nullable": true + }, + "deliveryCity": { + "type": "string", + "description": "City name for delivery address (used for tax jurisdiction determination).", + "nullable": true + }, + "deliveryState": { + "type": "string", + "description": "State or province for delivery address (used for tax calculation and compliance verification).", + "nullable": true + }, + "deliveryPostalCode": { + "type": "string", + "description": "Postal or ZIP code for delivery address (used for precise tax calculation and delivery zones).", + "nullable": true + }, + "isDelivery": { + "type": "boolean", + "description": "Indicates whether this is a delivery order (true) or pickup order (false) for tax and fee calculation." + } + }, + "additionalProperties": false, + "description": "Request model for calculating pricing, taxes, and discounts for a customer's shopping cart before creating a pre-order." + }, + "PriceEstimates": { + "type": "object", + "properties": { + "discountAmount": { + "type": "number", + "format": "double" + }, + "taxAmount": { + "type": "number", + "format": "double" + }, + "feeAmount": { + "type": "number", + "format": "double" + }, + "subtotal": { + "type": "number", + "format": "double" + }, + "grandTotal": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "PricingDetail": { + "type": "object", + "properties": { + "medPrice": { + "type": "number", + "description": "Medical cannabis patient pricing (typically lower due to tax benefits and patient programs).", + "format": "double", + "nullable": true + }, + "recPrice": { + "type": "number", + "description": "Recreational adult-use cannabis pricing (standard retail pricing with full taxes).", + "format": "double", + "nullable": true + }, + "pricingTierName": { + "type": "string", + "description": "Pricing tier name for customer segmentation (e.g., \"Standard\", \"VIP\", \"Bulk\", \"Employee\").", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Pricing detail information for cannabis products with medical and recreational pricing tiers." + }, + "PricingTier": { + "type": "object", + "properties": { + "pricingTierId": { + "type": "integer", + "format": "int32" + }, + "pricingTierName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PricingTierData": { + "type": "object", + "properties": { + "startWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "endWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "price": { + "type": "number", + "format": "double" + }, + "medicalPrice": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "Producer": { + "type": "object", + "properties": { + "producerId": { + "type": "integer", + "description": "Unique identifier for the producer.", + "format": "int32" + }, + "producerName": { + "type": "string", + "description": "Display name of the producer for product attribution and branding.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Producer identification model containing basic producer information for product attribution and reference data needs." + }, + "ProductCategory": { + "type": "object", + "properties": { + "productCategoryId": { + "type": "integer", + "description": "Unique identifier for the product category.", + "format": "int32" + }, + "productCategoryName": { + "type": "string", + "description": "Display name of the product category (e.g., \"Flower\", \"Edibles\", \"Concentrates\").", + "nullable": true + }, + "masterCategory": { + "type": "string", + "description": "Higher-level master category classification for broader product grouping.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Product category model containing cannabis product classification information for menu organization and product management." + }, + "ProductDetail": { + "type": "object", + "properties": { + "productId": { + "type": "integer", + "format": "int32" + }, + "sku": { + "type": "string", + "nullable": true + }, + "internalName": { + "type": "string", + "nullable": true + }, + "productName": { + "type": "string", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "masterCategory": { + "type": "string", + "nullable": true + }, + "categoryId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "category": { + "type": "string", + "nullable": true + }, + "imageUrl": { + "type": "string", + "nullable": true + }, + "imageUrls": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "strainId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "strain": { + "type": "string", + "nullable": true + }, + "strainType": { + "type": "string", + "nullable": true + }, + "size": { + "type": "string", + "nullable": true + }, + "netWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "netWeightUnitId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "netWeightUnit": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "brandId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "brandName": { + "type": "string", + "nullable": true + }, + "vendorId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "vendorName": { + "type": "string", + "nullable": true + }, + "isCannabis": { + "type": "boolean" + }, + "isActive": { + "type": "boolean" + }, + "isCoupon": { + "type": "boolean" + }, + "thcContent": { + "type": "number", + "format": "double", + "nullable": true + }, + "thcContentUnit": { + "type": "string", + "nullable": true + }, + "cbdContent": { + "type": "number", + "format": "double", + "nullable": true + }, + "cbdContentUnit": { + "type": "string", + "nullable": true + }, + "productGrams": { + "type": "number", + "format": "double", + "nullable": true + }, + "flowerEquivalent": { + "type": "number", + "format": "double", + "nullable": true + }, + "recFlowerEquivalent": { + "type": "number", + "format": "double", + "nullable": true + }, + "price": { + "type": "number", + "format": "double", + "nullable": true + }, + "medPrice": { + "type": "number", + "format": "double", + "nullable": true + }, + "recPrice": { + "type": "number", + "format": "double", + "nullable": true + }, + "unitCost": { + "type": "number", + "format": "double", + "nullable": true + }, + "unitType": { + "type": "string", + "nullable": true + }, + "onlineTitle": { + "type": "string", + "nullable": true + }, + "onlineDescription": { + "type": "string", + "nullable": true + }, + "onlineProduct": { + "type": "boolean", + "nullable": true, + "readOnly": true + }, + "posProducts": { + "type": "boolean", + "nullable": true + }, + "pricingTier": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "onlineAvailable": { + "type": "boolean", + "nullable": true + }, + "lowInventoryThreshold": { + "type": "number", + "format": "double", + "nullable": true + }, + "pricingTierName": { + "type": "string", + "nullable": true + }, + "pricingTierDescription": { + "type": "string", + "nullable": true + }, + "pricingTierData": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PricingTierData" + }, + "nullable": true + }, + "flavor": { + "type": "string", + "nullable": true + }, + "alternateName": { + "type": "string", + "nullable": true + }, + "lineageName": { + "type": "string", + "nullable": true + }, + "distillationName": { + "type": "string", + "nullable": true + }, + "maxPurchaseablePerTransaction": { + "type": "number", + "format": "double", + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProductTag" + }, + "nullable": true + }, + "effects": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProductEffect" + }, + "nullable": true + }, + "dosage": { + "type": "string", + "nullable": true + }, + "instructions": { + "type": "string", + "nullable": true + }, + "allergens": { + "type": "string", + "nullable": true + }, + "standardAllergens": { + "$ref": "#/components/schemas/StandardAllergensDetails" + }, + "defaultUnit": { + "type": "string", + "nullable": true + }, + "producerId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "producerName": { + "type": "string", + "nullable": true + }, + "createdDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "isMedicalOnly": { + "type": "boolean" + }, + "lastModifiedDateUTC": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "grossWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "isTaxable": { + "type": "boolean", + "nullable": true + }, + "taxCategories": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "upc": { + "type": "string", + "nullable": true + }, + "regulatoryCategory": { + "type": "string", + "nullable": true + }, + "ndc": { + "type": "string", + "nullable": true + }, + "daysSupply": { + "type": "number", + "format": "double", + "nullable": true + }, + "illinoisTaxCategory": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "externalCategory": { + "type": "string", + "nullable": true + }, + "externalId": { + "type": "string", + "nullable": true + }, + "syncExternally": { + "type": "boolean" + }, + "regulatoryName": { + "type": "string", + "nullable": true + }, + "broadcastedResponses": { + "$ref": "#/components/schemas/BroadcastedResponses" + }, + "administrationMethod": { + "type": "string", + "nullable": true + }, + "unitCBDContentDose": { + "type": "number", + "format": "double", + "nullable": true + }, + "unitTHCContentDose": { + "type": "number", + "format": "double", + "nullable": true + }, + "oilVolume": { + "type": "number", + "format": "double", + "nullable": true + }, + "ingredientList": { + "type": "string", + "nullable": true + }, + "expirationDays": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "abbreviation": { + "type": "string", + "nullable": true + }, + "isTestProduct": { + "type": "boolean" + }, + "isFinished": { + "type": "boolean" + }, + "allowAutomaticDiscounts": { + "type": "boolean" + }, + "servingSize": { + "type": "string", + "nullable": true + }, + "servingSizePerUnit": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "isNutrient": { + "type": "boolean" + }, + "approvalDateUTC": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "ecomCategory": { + "type": "string", + "nullable": true + }, + "ecomSubcategory": { + "type": "string", + "nullable": true + }, + "customMetadata": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ProductDetailUpload": { + "required": ["productName", "sku"], + "type": "object", + "properties": { + "productId": { + "type": "integer", + "description": "The unique identifier for a product in the system.\n\n**IMPORTANT**: This field determines whether a product is created or updated:\n- To CREATE a new product: Omit this field or set to null\n- To UPDATE an existing product: You MUST provide the ProductId of the existing product", + "format": "int32", + "nullable": true + }, + "sku": { + "minLength": 1, + "type": "string", + "description": "Product SKU - REQUIRED for CREATE operations" + }, + "productName": { + "minLength": 1, + "type": "string", + "description": "Product Name - REQUIRED for CREATE operations" + }, + "description": { + "type": "string", + "description": "Deprecated in favor of AlternateName", + "nullable": true + }, + "alternateName": { + "type": "string", + "nullable": true + }, + "masterCategory": { + "type": "string", + "nullable": true + }, + "category": { + "type": "string", + "nullable": true + }, + "strain": { + "type": "string", + "nullable": true + }, + "strainType": { + "type": "string", + "description": "Strain type of the specified strain.\nUsed to disambiguate strains, if duplicates exist.\nIf no duplicates exist in the location's strain list, this field is not useful.\nIf duplicates DO exist and this field is not specified, the strain will be chosen by the first one created.", + "nullable": true, + "example": "123" + }, + "size": { + "type": "string", + "nullable": true + }, + "netWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "netWeightUnit": { + "type": "string", + "description": "Optional. Abbreviation of the unit of the product's net weight.", + "nullable": true + }, + "grossWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "brandName": { + "type": "string", + "nullable": true + }, + "vendorName": { + "type": "string", + "nullable": true + }, + "isCannabis": { + "type": "boolean" + }, + "isActive": { + "type": "boolean" + }, + "thcContent": { + "type": "number", + "format": "double", + "nullable": true + }, + "thcContentUnit": { + "type": "string", + "description": "mg; %; mg/g; n.d.", + "nullable": true + }, + "cbdContent": { + "type": "number", + "format": "double", + "nullable": true + }, + "cbdContentUnit": { + "type": "string", + "description": "mg; %; mg/g; n.d.", + "nullable": true + }, + "productGrams": { + "type": "number", + "format": "double", + "nullable": true + }, + "flowerEquivalent": { + "type": "number", + "format": "double", + "nullable": true + }, + "recFlowerEquivalent": { + "type": "number", + "format": "double", + "nullable": true + }, + "price": { + "type": "number", + "format": "double", + "nullable": true + }, + "unitCost": { + "type": "number", + "format": "double", + "nullable": true + }, + "unitType": { + "type": "string", + "nullable": true + }, + "onlineTitle": { + "type": "string", + "nullable": true + }, + "onlineDescription": { + "type": "string", + "nullable": true + }, + "onlineProduct": { + "type": "boolean", + "nullable": true + }, + "posProducts": { + "type": "boolean", + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "defaultUnit": { + "type": "string", + "nullable": true + }, + "isMedicalOnly": { + "type": "boolean", + "nullable": true + }, + "isTaxable": { + "type": "boolean", + "nullable": true + }, + "regulatoryCategory": { + "type": "string", + "nullable": true + }, + "ndc": { + "type": "string", + "nullable": true + }, + "daysSupply": { + "type": "number", + "format": "double", + "nullable": true + }, + "illinoisTaxCategory": { + "type": "string", + "nullable": true + }, + "externalCategory": { + "type": "string", + "nullable": true + }, + "externalId": { + "$ref": "#/components/schemas/StringOptional" + }, + "syncExternally": { + "type": "boolean", + "nullable": true + }, + "bypassExternalUpdate": { + "type": "boolean", + "nullable": true + }, + "administrationMethod": { + "$ref": "#/components/schemas/StringOptional" + }, + "unitCBDContentDose": { + "$ref": "#/components/schemas/DecimalNullableOptional" + }, + "unitTHCContentDose": { + "$ref": "#/components/schemas/DecimalNullableOptional" + }, + "oilVolume": { + "$ref": "#/components/schemas/DecimalNullableOptional" + }, + "ingredientList": { + "$ref": "#/components/schemas/StringOptional" + }, + "expirationDays": { + "$ref": "#/components/schemas/Int32NullableOptional" + }, + "abbreviation": { + "$ref": "#/components/schemas/StringOptional" + }, + "isTestProduct": { + "$ref": "#/components/schemas/BooleanOptional" + }, + "isFinished": { + "$ref": "#/components/schemas/BooleanOptional" + }, + "allowAutomaticDiscounts": { + "$ref": "#/components/schemas/BooleanOptional" + }, + "servingSize": { + "$ref": "#/components/schemas/StringOptional" + }, + "servingSizePerUnit": { + "$ref": "#/components/schemas/Int32NullableOptional" + }, + "isNutrient": { + "$ref": "#/components/schemas/BooleanOptional" + }, + "approvalDateUTC": { + "$ref": "#/components/schemas/DateTimeNullableOptional" + }, + "customMetadata": { + "$ref": "#/components/schemas/StringOptional" + }, + "taxCategories": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of strings of tax categories that the product belongs to.", + "nullable": true + }, + "pricingDetails": { + "$ref": "#/components/schemas/PricingDetail" + }, + "userName": { + "type": "string", + "description": "UserName of the user making the product change\nThis will be used when authorizing with traceability systems (METRC/BioTrack) - if not included or NULL is specified, the traceability integration's \"master key\" will be used, if possible.\nThis field is only relevant if the request is setting SyncExternally to true", + "nullable": true + }, + "instructions": { + "type": "string", + "nullable": true + }, + "upc": { + "type": "string", + "nullable": true + }, + "regulatoryName": { + "$ref": "#/components/schemas/StringOptional" + }, + "broadcast": { + "$ref": "#/components/schemas/BooleanOptional" + } + }, + "additionalProperties": false, + "description": "Product upload model for creating and updating products.\n\n⚠️ **DATA LOSS WARNING**: Most fields will be overwritten with null/zero if not provided.\n**RECOMMENDED**: Use GET /products first, modify needed fields, then POST the complete object." + }, + "ProductEffect": { + "type": "object", + "properties": { + "effectId": { + "type": "integer", + "format": "int32" + }, + "effectName": { + "type": "string", + "nullable": true + }, + "productId": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "ProductTag": { + "type": "object", + "properties": { + "tagId": { + "type": "integer", + "format": "int32" + }, + "tagName": { + "type": "string", + "nullable": true + }, + "productId": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "PublishedDiscount": { + "type": "object", + "properties": { + "discountId": { + "type": "integer", + "description": "Unique identifier for the discount.", + "format": "int32" + }, + "discountName": { + "type": "string", + "description": "Display name of the discount for customer-facing applications.", + "nullable": true + }, + "discountAmount": { + "type": "number", + "description": "Monetary discount amount or percentage value.", + "format": "double" + }, + "discountCode": { + "type": "string", + "description": "Promotional code required to apply the discount (optional).", + "nullable": true + }, + "discountType": { + "type": "string", + "description": "Type classification of the discount (e.g., percentage, fixed amount).", + "nullable": true + }, + "discountMethod": { + "type": "string", + "description": "Method used to apply the discount (e.g., automatic, code required).", + "nullable": true + }, + "isActive": { + "type": "boolean", + "description": "Indicates if the discount is currently active and available." + }, + "validFrom": { + "type": "string", + "description": "Start date and time when discount becomes valid (UTC converted from Eastern Time).", + "format": "date-time", + "nullable": true + }, + "validUntil": { + "type": "string", + "description": "End date and time when discount expires (UTC converted from Eastern Time).", + "format": "date-time", + "nullable": true + }, + "thresholdType": { + "type": "string", + "description": "Type of threshold requirement for discount eligibility (optional).", + "nullable": true + }, + "minimumItemsRequired": { + "type": "number", + "description": "Minimum number of qualifying items required for discount application (optional).", + "format": "double", + "nullable": true + }, + "maximumItemsAllowed": { + "type": "number", + "description": "Maximum number of items that can receive the discount (optional).", + "format": "double", + "nullable": true + }, + "maximumUsageCount": { + "type": "number", + "description": "Maximum number of times this discount can be used (optional).", + "format": "double", + "nullable": true + }, + "includeNonCannabis": { + "type": "boolean", + "description": "Indicates if discount applies to non-cannabis products." + }, + "firstTimeCustomerOnly": { + "type": "boolean", + "description": "Indicates if discount is restricted to first-time customers only." + }, + "stackOnOtherDiscounts": { + "type": "boolean", + "description": "Indicates if discount can be combined with other discounts." + }, + "weeklyRecurrenceInfo": { + "$ref": "#/components/schemas/WeeklyRecurrenceInfo" + }, + "products": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "productCategories": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "brands": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "vendors": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "strains": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "tiers": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "tags": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "inventoryTags": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "customerTypes": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "discountGroups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiscountGroup" + }, + "description": "Associated discount groups for bundling and organization (loaded conditionally).", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Published discount model containing complete discount configuration and constraint information for customer-facing applications." + }, + "PurchaseOrderData": { + "type": "object", + "properties": { + "purchaseOrderId": { + "type": "integer", + "format": "int32" + }, + "expectedArrivalDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "dateReceived": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "dateSubmitted": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "shippingInformation": { + "type": "string", + "nullable": true + }, + "vendorId": { + "type": "integer", + "format": "int32" + }, + "vendorName": { + "type": "string", + "nullable": true + }, + "vendorContact": { + "type": "string", + "nullable": true + }, + "status": { + "type": "string", + "nullable": true + }, + "purchaseOrderNumber": { + "type": "integer", + "format": "int32" + }, + "createdByUser": { + "type": "string", + "nullable": true + }, + "dateCreated": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "purchaseOrderItems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PurchaseOrderItemDetail" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PurchaseOrderItemDetail": { + "type": "object", + "properties": { + "purchaseOrderId": { + "type": "integer", + "format": "int32" + }, + "purchaseOrderItemId": { + "type": "integer", + "format": "int32" + }, + "productId": { + "type": "integer", + "format": "int32" + }, + "productName": { + "type": "string", + "nullable": true + }, + "quantity": { + "type": "integer", + "format": "int32" + }, + "unitId": { + "type": "integer", + "format": "int32" + }, + "unitName": { + "type": "string", + "nullable": true + }, + "unitNameAbbreviation": { + "type": "string", + "nullable": true + }, + "subtotal": { + "type": "number", + "format": "double" + }, + "tax": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "ReceiveInventoryItemSave": { + "required": ["productId", "quantity"], + "type": "object", + "properties": { + "productId": { + "type": "integer", + "description": "Product identifier for the cannabis product being received into inventory (required).", + "format": "int32" + }, + "quantity": { + "type": "number", + "description": "Quantity of the product being received into inventory (required).", + "format": "double" + }, + "unitType": { + "type": "string", + "description": "Unit type for the received quantity (qty; ml; g; Gal; L; lb; mg; oz; fl oz; kg).", + "nullable": true + }, + "flowerEquivalent": { + "type": "number", + "description": "Flower equivalent weight for regulatory compliance and limit calculations.", + "format": "double", + "nullable": true + }, + "recFlowerEquivalent": { + "type": "number", + "description": "Recreational flower equivalent weight for regulatory compliance tracking.", + "format": "double", + "nullable": true + }, + "vendorId": { + "type": "integer", + "description": "Vendor identifier for supply chain tracking and vendor management.", + "format": "int32", + "nullable": true + }, + "roomId": { + "type": "integer", + "description": "Room identifier for facility location assignment and space management.", + "format": "int32", + "nullable": true + }, + "packageId": { + "type": "string", + "description": "Package identifier from state tracking system for compliance documentation.", + "nullable": true + }, + "lot": { + "type": "string", + "description": "Lot number for batch tracking and quality control management.", + "nullable": true + }, + "cost": { + "type": "number", + "description": "Unit cost for inventory valuation and cost accounting.", + "format": "double", + "nullable": true + }, + "price": { + "type": "number", + "description": "General retail price for the received inventory item.", + "format": "double", + "nullable": true + }, + "recPrice": { + "type": "number", + "description": "Recreational market price for dual-license operations.", + "format": "double", + "nullable": true + }, + "tax": { + "type": "number", + "description": "Tax amount for financial compliance and tax reporting.", + "format": "double", + "nullable": true + }, + "expirationDate": { + "type": "string", + "description": "Product expiration date for inventory rotation and compliance management.", + "format": "date-time", + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Collection of tag identifiers for product categorization and organization.", + "nullable": true + }, + "cultivationTax": { + "type": "number", + "description": "Cultivation tax amount for cannabis-specific tax compliance.", + "format": "double", + "nullable": true + }, + "tableId": { + "type": "integer", + "description": "Table identifier within the room for precise location tracking.", + "format": "int32", + "nullable": true + }, + "sourceAllocatedInventoryId": { + "type": "integer", + "description": "Source allocated inventory identifier for traceability and audit trails.", + "format": "int32", + "nullable": true + }, + "totalPackageCost": { + "type": "number", + "description": "Total package cost for comprehensive cost allocation and accounting.", + "format": "double", + "nullable": true + }, + "getMetrcLabResults": { + "type": "boolean", + "description": "Flag to retrieve lab results from Metrc for compliance integration.", + "nullable": true + }, + "productName": { + "type": "string", + "description": "Product name for inventory identification and display purposes.", + "nullable": true + }, + "packagingDate": { + "type": "string", + "description": "Date when the product was packaged for shelf life tracking.", + "format": "date-time", + "nullable": true + }, + "manufacturingDate": { + "type": "string", + "description": "Date when the product was manufactured for quality control tracking.", + "format": "date-time", + "nullable": true + }, + "producerId": { + "type": "integer", + "description": "Producer identifier for supply chain tracking and compliance documentation.", + "format": "int32", + "nullable": true + }, + "externalPackageId": { + "type": "string", + "description": "External package identifier for cross-system integration and tracking.", + "nullable": true + }, + "potencyIndicator": { + "type": "string", + "description": "Potency indicator for product strength classification and customer information.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for receiving and recording new cannabis inventory items into the facility management system." + }, + "ReceiveInventorySave": { + "required": ["deliveredOn"], + "type": "object", + "properties": { + "vendorId": { + "type": "integer", + "description": "Vendor identifier for the supplier (optional, can be resolved from VendorLicense).", + "format": "int32", + "nullable": true + }, + "deliveredBy": { + "type": "string", + "description": "Name of the person who delivered the inventory shipment.", + "nullable": true + }, + "deliveredOn": { + "type": "string", + "description": "Date and time when the inventory was delivered (required).", + "format": "date-time" + }, + "vendorLicense": { + "type": "string", + "description": "Vendor license code for compliance tracking and vendor identification.", + "nullable": true + }, + "transactionId": { + "type": "string", + "description": "External transaction reference ID for tracking and reconciliation.", + "nullable": true + }, + "orderTitle": { + "type": "string", + "description": "Descriptive title for the receive order for identification purposes.", + "nullable": true + }, + "externalId": { + "type": "string", + "description": "External system ID for preventing duplicate receives (must be unique).", + "nullable": true + }, + "note": { + "type": "string", + "description": "Additional notes or comments about the receive transaction.", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReceiveInventoryItemSave" + }, + "description": "Collection of inventory items being received in this transaction.", + "nullable": true + }, + "receiveIntoInventory": { + "type": "boolean", + "description": "Indicates whether to immediately process items into inventory (true) or save as draft (false).", + "nullable": true + }, + "userId": { + "type": "integer", + "description": "User ID for processing the receive (required when ReceiveIntoInventory=true).", + "format": "int32", + "nullable": true + }, + "userName": { + "type": "string", + "description": "Username for processing the receive (alternative to UserId, required when ReceiveIntoInventory=true).", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for creating inventory receive orders for incoming transfers, purchase orders, or direct inventory additions." + }, + "ReceivedInventory": { + "type": "object", + "properties": { + "receiveInventoryHistoryId": { + "type": "integer", + "description": "Unique identifier for the receive inventory transaction.", + "format": "int32" + }, + "title": { + "type": "string", + "description": "Descriptive title for the receive order for identification purposes.", + "nullable": true + }, + "status": { + "type": "string", + "description": "Current processing status of the receive order (e.g., \"Pending\", \"Completed\", \"Failed\").", + "nullable": true + }, + "failureMessage": { + "type": "string", + "description": "Error message if the receive order failed processing (optional).", + "nullable": true + }, + "deliveredOn": { + "type": "string", + "description": "Date and time when the inventory was delivered by the vendor (optional).", + "format": "date-time", + "nullable": true + }, + "addedOn": { + "type": "string", + "description": "Date and time when the receive order was created in the system (optional).", + "format": "date-time", + "nullable": true + }, + "vendor": { + "type": "string", + "description": "Name of the vendor who supplied the inventory.", + "nullable": true + }, + "vendorLicense": { + "type": "string", + "description": "Vendor license code for compliance tracking and verification.", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReceivedInventoryItem" + }, + "description": "Collection of inventory items included in this receive order.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Received inventory record model representing completed or pending inventory receive orders and their processing status." + }, + "ReceivedInventoryItem": { + "type": "object", + "properties": { + "product": { + "type": "string", + "description": "Product name for inventory item identification and display.", + "nullable": true + }, + "sku": { + "type": "string", + "description": "Stock Keeping Unit (SKU) for product identification and retail operations.", + "nullable": true + }, + "productId": { + "type": "integer", + "description": "Product identifier for database references and system integration.", + "format": "int32", + "nullable": true + }, + "type": { + "type": "string", + "description": "Product type classification for cannabis product categorization.", + "nullable": true + }, + "quantity": { + "type": "number", + "description": "Quantity of the received inventory item for stock tracking.", + "format": "double" + }, + "unitAbbreviation": { + "type": "string", + "description": "Unit abbreviation for quantity measurement display (e.g., \"g\", \"oz\", \"ml\").", + "nullable": true + }, + "unit": { + "type": "string", + "description": "Full unit name for quantity measurement (e.g., \"grams\", \"ounces\", \"milliliters\").", + "nullable": true + }, + "unitCost": { + "type": "number", + "description": "Cost per unit for inventory valuation and financial accounting.", + "format": "double" + }, + "unitTax": { + "type": "number", + "description": "Tax amount per unit for cannabis tax compliance and reporting.", + "format": "double" + }, + "totalCost": { + "type": "number", + "description": "Total cost for the received inventory item including all taxes and fees.", + "format": "double" + }, + "packageId": { + "type": "string", + "description": "Package identifier from state tracking system for compliance documentation.", + "nullable": true + }, + "externalPackageId": { + "type": "string", + "description": "External package identifier for cross-system tracking and integration.", + "nullable": true + }, + "batchName": { + "type": "string", + "description": "Batch name for lot tracking and quality control management.", + "nullable": true + }, + "batchId": { + "type": "integer", + "description": "Batch identifier for database references and batch tracking.", + "format": "int32", + "nullable": true + }, + "room": { + "type": "string", + "description": "Room name for facility location identification and display.", + "nullable": true + }, + "roomId": { + "type": "integer", + "description": "Room identifier for database references and location tracking.", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Response model representing received cannabis inventory items with complete tracking and financial information." + }, + "RegisterAdjustment": { + "type": "object", + "properties": { + "adjustmentId": { + "type": "integer", + "description": "Unique identifier for the register adjustment transaction.\nPrimary key for tracking and referencing specific adjustment records.", + "format": "int32" + }, + "adjustmentType": { + "type": "string", + "description": "Type of register adjustment being performed.\nCommon values include \"Adjustment\", \"Close Out\", \"Deposit\", \"Withdrawal\", \"Cash Drop\".", + "nullable": true + }, + "adjustmentAmount": { + "type": "number", + "description": "Dollar amount of the register adjustment (positive or negative).\nPositive values indicate cash added to register, negative values indicate cash removed.", + "format": "double" + }, + "adjustedBy": { + "type": "string", + "description": "Name of the employee who performed the register adjustment.\nUsed for accountability and audit trail purposes.", + "nullable": true + }, + "adjustedOn": { + "type": "string", + "description": "Date and time when the register adjustment was performed (optional).\nTimestamp for audit trail and reconciliation purposes.", + "format": "date-time", + "nullable": true + }, + "terminalName": { + "type": "string", + "description": "Name of the register/terminal where the adjustment occurred.\nIdentifies which physical register or point-of-sale terminal was adjusted.", + "nullable": true + }, + "terminalId": { + "type": "integer", + "description": "Unique identifier for the register/terminal where the adjustment occurred.\nNumeric identifier for the specific point-of-sale terminal.", + "format": "int32" + }, + "adjustedByEmployeeId": { + "type": "integer", + "description": "Employee ID of the staff member who performed the adjustment.\nNumeric identifier linking to the employee record for accountability.", + "format": "int32" + }, + "adjustmentReason": { + "type": "string", + "description": "Reason code or description for why the adjustment was made.\nProvides business justification for the cash adjustment.", + "nullable": true + }, + "comment": { + "type": "string", + "description": "Additional comments or notes about the register adjustment (optional).\nFree-text field for additional details or explanations.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Represents a register cash adjustment transaction record for financial reconciliation and audit trails.\n\nRegister adjustments include manual cash corrections, deposits, withdrawals, close-outs, and other\ncash management activities that affect register balances. Each adjustment maintains a complete\naudit trail with employee accountability and reason tracking." + }, + "RegisterCashSummary": { + "type": "object", + "properties": { + "terminalName": { + "type": "string", + "description": "Name of the register/terminal for which this cash summary applies.\nIdentifies the specific point-of-sale terminal or register location.", + "nullable": true + }, + "startingBalance": { + "type": "number", + "description": "Starting cash balance for the register at the beginning of the period.\nBase amount of cash in the register before any transactions occurred.", + "format": "double" + }, + "endingBalance": { + "type": "number", + "description": "Ending cash balance for the register at the end of the period.\nFinal amount of cash in the register after all transactions and adjustments.", + "format": "double" + }, + "sales": { + "type": "number", + "description": "Total cash sales processed through the register during the period.\nIncludes all cash payments received for customer transactions.", + "format": "double" + }, + "returns": { + "type": "number", + "description": "Total cash refunds and returns processed during the period.\nRepresents cash paid out to customers for returned merchandise.", + "format": "double" + }, + "deposits": { + "type": "number", + "description": "Total cash deposits added to the register during the period.\nIncludes cash added to the register for operational purposes.", + "format": "double" + }, + "adjustments": { + "type": "number", + "description": "Total register adjustments (positive or negative) made during the period.\nIncludes manual cash corrections, withdrawals, and balancing entries.", + "format": "double" + }, + "overShort": { + "type": "number", + "description": "Cash variance (over or short) compared to expected register balance.\nPositive values indicate cash overage, negative values indicate shortage.", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Represents a comprehensive cash flow summary for a specific register terminal.\n\nThis model provides real-time cash reconciliation data including starting balances,\ntransaction activity, and variance calculations for cash management and balancing\npurposes. Used for end-of-shift reconciliation and cash discrepancy identification." + }, + "RegisterTransaction": { + "type": "object", + "properties": { + "registerTransactionId": { + "type": "integer", + "description": "Unique identifier for the register transaction record.\nPrimary key for tracking and referencing specific transaction activities.", + "format": "int32" + }, + "transactionType": { + "type": "string", + "description": "Type of register transaction being recorded.\nExamples include \"Sale\", \"Adjustment\", \"Close Out\", \"Deposit\", \"Withdrawal\", \"Return\", \"Payment\".", + "nullable": true + }, + "transactionAmount": { + "type": "number", + "description": "Dollar amount of the register transaction (positive or negative).\nRepresents the financial impact of the transaction on register balances.", + "format": "double" + }, + "transactionBy": { + "type": "string", + "description": "Name of the employee who processed the register transaction.\nUsed for accountability and performance tracking.", + "nullable": true + }, + "transactionDateUTC": { + "type": "string", + "description": "Date and time when the register transaction occurred in UTC (optional).\nTimestamp for audit trail and financial reconciliation purposes.", + "format": "date-time", + "nullable": true + }, + "transactionId": { + "type": "integer", + "description": "Reference to the associated business transaction ID (optional).\nLinks register activity to customer sales transactions when applicable.", + "format": "int32", + "nullable": true + }, + "terminalName": { + "type": "string", + "description": "Name of the register/terminal where the transaction was processed.\nIdentifies which physical register or point-of-sale terminal handled the transaction.", + "nullable": true + }, + "terminalId": { + "type": "integer", + "description": "Unique identifier for the register/terminal where the transaction occurred.\nNumeric identifier for the specific point-of-sale terminal.", + "format": "int32" + }, + "transactionByEmployeeId": { + "type": "integer", + "description": "Employee ID of the staff member who processed the transaction.\nNumeric identifier linking to the employee record for accountability tracking.", + "format": "int32" + }, + "adjustmentReason": { + "type": "string", + "description": "Reason code or description for adjustment transactions (optional).\nProvides business justification when the transaction is an adjustment or correction.", + "nullable": true + }, + "comment": { + "type": "string", + "description": "Additional comments or notes about the register transaction (optional).\nFree-text field for additional context or explanations.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Represents a comprehensive register transaction record including sales, adjustments, and cash management activities.\n\nThis model encompasses all types of register activity including customer sales transactions, cash adjustments,\npayment processing, register maintenance, and operational activities. Each transaction maintains complete\naudit trails with employee accountability and detailed financial information." + }, + "RegulatoryCategory": { + "type": "object", + "properties": { + "regulatoryCategoryId": { + "type": "integer", + "description": "Unique identifier for the regulatory category.", + "format": "int32" + }, + "regulatoryCategoryName": { + "type": "string", + "description": "Display name of the regulatory category as defined by state cannabis regulations.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Regulatory category model containing state-mandated product classification information for cannabis compliance and reporting." + }, + "ReportingDiscountDetail": { + "type": "object", + "properties": { + "isAvailableOnline": { + "type": "boolean", + "description": "Indicates if discount is available for online/e-commerce ordering." + }, + "applicationMethod": { + "type": "string", + "description": "Method used to apply the discount in the system.", + "nullable": true + }, + "externalId": { + "type": "string", + "description": "External system identifier for integration mapping.", + "nullable": true + }, + "requireManagerApproval": { + "type": "boolean", + "description": "Indicates if discount application requires manager approval." + }, + "isDeleted": { + "type": "boolean", + "description": "Indicates if discount has been marked as deleted." + }, + "appliesToLocations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LocationMapping" + }, + "description": "Collection of location mappings where this discount applies.", + "nullable": true + }, + "discountId": { + "type": "integer", + "description": "Unique identifier for the discount.", + "format": "int32" + }, + "discountName": { + "type": "string", + "description": "Display name of the discount for customer-facing applications.", + "nullable": true + }, + "discountAmount": { + "type": "number", + "description": "Monetary discount amount or percentage value.", + "format": "double" + }, + "discountCode": { + "type": "string", + "description": "Promotional code required to apply the discount (optional).", + "nullable": true + }, + "discountType": { + "type": "string", + "description": "Type classification of the discount (e.g., percentage, fixed amount).", + "nullable": true + }, + "discountMethod": { + "type": "string", + "description": "Method used to apply the discount (e.g., automatic, code required).", + "nullable": true + }, + "isActive": { + "type": "boolean", + "description": "Indicates if the discount is currently active and available." + }, + "validFrom": { + "type": "string", + "description": "Start date and time when discount becomes valid (UTC converted from Eastern Time).", + "format": "date-time", + "nullable": true + }, + "validUntil": { + "type": "string", + "description": "End date and time when discount expires (UTC converted from Eastern Time).", + "format": "date-time", + "nullable": true + }, + "thresholdType": { + "type": "string", + "description": "Type of threshold requirement for discount eligibility (optional).", + "nullable": true + }, + "minimumItemsRequired": { + "type": "number", + "description": "Minimum number of qualifying items required for discount application (optional).", + "format": "double", + "nullable": true + }, + "maximumItemsAllowed": { + "type": "number", + "description": "Maximum number of items that can receive the discount (optional).", + "format": "double", + "nullable": true + }, + "maximumUsageCount": { + "type": "number", + "description": "Maximum number of times this discount can be used (optional).", + "format": "double", + "nullable": true + }, + "includeNonCannabis": { + "type": "boolean", + "description": "Indicates if discount applies to non-cannabis products." + }, + "firstTimeCustomerOnly": { + "type": "boolean", + "description": "Indicates if discount is restricted to first-time customers only." + }, + "stackOnOtherDiscounts": { + "type": "boolean", + "description": "Indicates if discount can be combined with other discounts." + }, + "weeklyRecurrenceInfo": { + "$ref": "#/components/schemas/WeeklyRecurrenceInfo" + }, + "products": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "productCategories": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "brands": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "vendors": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "strains": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "tiers": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "tags": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "inventoryTags": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "customerTypes": { + "$ref": "#/components/schemas/DiscountRestriction" + }, + "discountGroups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiscountGroup" + }, + "description": "Associated discount groups for bundling and organization (loaded conditionally).", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Extended discount model with additional reporting and administrative properties for internal operations." + }, + "ReportingInventoryItem": { + "type": "object", + "properties": { + "unitWeightUnit": { + "type": "string", + "description": "Unit of measurement for unit weight, always \"g\" (grams).", + "nullable": true + }, + "unitCost": { + "type": "number", + "description": "Unit cost of the inventory item for cost of goods sold calculations (in USD).", + "format": "double", + "nullable": true + }, + "allocatedQuantity": { + "type": "number", + "description": "Quantity of inventory allocated to orders or transfers but not yet fulfilled.", + "format": "double", + "nullable": true + }, + "inventoryId": { + "type": "integer", + "description": "Unique inventory record identifier for this specific inventory item.", + "format": "int32" + }, + "productId": { + "type": "integer", + "description": "Product identifier linking this inventory to the product catalog.", + "format": "int32" + }, + "sku": { + "type": "string", + "description": "Stock Keeping Unit (SKU) code for inventory tracking and identification.", + "nullable": true + }, + "productName": { + "type": "string", + "description": "Display name of the product for customer-facing applications.", + "nullable": true + }, + "description": { + "type": "string", + "description": "Detailed product description including effects, characteristics, and usage information.", + "nullable": true + }, + "categoryId": { + "type": "integer", + "description": "Category identifier for product classification (optional).", + "format": "int32", + "nullable": true + }, + "category": { + "type": "string", + "description": "Category name for product classification and filtering.", + "nullable": true + }, + "imageUrl": { + "type": "string", + "description": "URL path to product image for display purposes.", + "nullable": true + }, + "quantityAvailable": { + "type": "number", + "description": "Current available quantity for sale or transfer.", + "format": "double" + }, + "quantityUnits": { + "type": "string", + "description": "Unit of measurement for the available quantity (e.g., \"g\", \"mg\", \"ea\").", + "nullable": true + }, + "unitWeight": { + "type": "number", + "description": "Weight per unit in grams for dosing and compliance calculations.", + "format": "double" + }, + "flowerEquivalent": { + "type": "number", + "description": "Flower equivalent amount in grams for compliance tracking.", + "format": "double" + }, + "recFlowerEquivalent": { + "type": "number", + "description": "Recreational flower equivalent amount in grams (optional).", + "format": "double", + "nullable": true + }, + "flowerEquivalentUnits": { + "type": "string", + "description": "Unit of measurement for flower equivalent, always \"g\" (grams).", + "nullable": true, + "readOnly": true + }, + "batchId": { + "type": "integer", + "description": "Batch identifier for lot tracking and quality control.", + "format": "int32" + }, + "batchName": { + "type": "string", + "description": "Human-readable batch name or lot number for tracking.", + "nullable": true + }, + "packageId": { + "type": "string", + "description": "Package identifier for compliance tracking and traceability.", + "nullable": true + }, + "packageStatus": { + "type": "string", + "description": "Current status of the package (e.g., \"Active\", \"Testing\", \"Quarantine\").", + "nullable": true + }, + "unitPrice": { + "type": "number", + "description": "Base unit price for retail sales.", + "format": "double" + }, + "medUnitPrice": { + "type": "number", + "description": "Medical program pricing (optional, different from retail).", + "format": "double", + "nullable": true + }, + "recUnitPrice": { + "type": "number", + "description": "Recreational program pricing (optional, different from medical).", + "format": "double", + "nullable": true + }, + "strainId": { + "type": "integer", + "description": "Strain identifier for cannabis products (optional).", + "format": "int32", + "nullable": true + }, + "strain": { + "type": "string", + "description": "Strain name for cannabis products.", + "nullable": true + }, + "strainType": { + "type": "string", + "description": "Cannabis strain classification (Hybrid, Indica, Sativa, CBD).", + "nullable": true + }, + "size": { + "type": "string", + "description": "Product size designation for packaging and dosing information.", + "nullable": true + }, + "labResults": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LabResult" + }, + "description": "Collection of laboratory test results for this batch (included when includeLabResults=true).", + "nullable": true + }, + "testedDate": { + "type": "string", + "description": "Date when laboratory testing was completed (optional).", + "format": "date-time", + "nullable": true + }, + "sampleDate": { + "type": "string", + "description": "Date when sample was collected for laboratory testing (optional).", + "format": "date-time", + "nullable": true + }, + "packagedDate": { + "type": "string", + "description": "Date when product was packaged for distribution (optional).", + "format": "date-time", + "nullable": true + }, + "manufacturingDate": { + "type": "string", + "description": "Date when product was manufactured or produced (optional).", + "format": "date-time", + "nullable": true + }, + "lastModifiedDateUtc": { + "type": "string", + "description": "Last modification timestamp in UTC for data synchronization.", + "format": "date-time", + "nullable": true + }, + "labTestStatus": { + "type": "string", + "description": "Current status of laboratory testing (e.g., \"Passed\", \"Failed\", \"Pending\").", + "nullable": true + }, + "vendorId": { + "type": "integer", + "description": "Vendor identifier for the supplier of this inventory (optional).", + "format": "int32", + "nullable": true + }, + "vendor": { + "type": "string", + "description": "Vendor name for the supplier of this inventory.", + "nullable": true + }, + "expirationDate": { + "type": "string", + "description": "Product expiration date for compliance and quality control (optional).", + "format": "date-time", + "nullable": true + }, + "roomQuantities": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InventoryRoomQuantity" + }, + "description": "Quantity breakdown by storage room/location (included when includeRoomQuantities=true).", + "nullable": true + }, + "pricingTierName": { + "type": "string", + "description": "Pricing tier classification for bulk pricing strategies.", + "nullable": true + }, + "alternateName": { + "type": "string", + "description": "Alternative product name for display purposes.", + "nullable": true + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InventoryTag" + }, + "description": "Collection of compliance tags associated with this inventory package.", + "nullable": true + }, + "brandId": { + "type": "integer", + "description": "Brand identifier for branded products (optional).", + "format": "int32", + "nullable": true + }, + "brandName": { + "type": "string", + "description": "Brand name for branded products.", + "nullable": true + }, + "medicalOnly": { + "type": "boolean", + "description": "Indicates if product is restricted to medical program only." + }, + "externalPackageId": { + "type": "string", + "description": "External compliance system ID (METRC or BioTrack) for regulatory tracking.", + "nullable": true + }, + "producer": { + "type": "string", + "description": "Producer name for cultivation and manufacturing tracking.", + "nullable": true + }, + "producerId": { + "type": "integer", + "description": "Producer identifier for cultivation and manufacturing tracking (optional).", + "format": "int32", + "nullable": true + }, + "lineage": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PackageLineage" + }, + "description": "Package lineage information for traceability and compliance tracking.", + "nullable": true + }, + "potencyIndicator": { + "type": "string", + "description": "Potency classification indicator for dosing guidance.", + "nullable": true + }, + "masterCategory": { + "type": "string", + "description": "Master category classification for product grouping.", + "nullable": true + }, + "effectivePotencyMg": { + "type": "number", + "description": "Effective potency in milligrams for dosing calculations (optional).", + "format": "double", + "nullable": true + }, + "isCannabis": { + "type": "boolean", + "description": "Indicates if product contains cannabis or is cannabis-related." + }, + "packageNDC": { + "type": "string", + "description": "National Drug Code for pharmaceutical tracking (optional).", + "nullable": true + }, + "labResultUrl": { + "type": "string", + "description": "URL to certificate of analysis or lab testing document.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Extended inventory item model for financial reporting with cost and allocation data." + }, + "RetagPlantRequest": { + "type": "object", + "properties": { + "plantId": { + "type": "integer", + "description": "Plant identifier for the cannabis plant being retagged with a new serial number.", + "format": "int32" + }, + "serialNumber": { + "type": "string", + "description": "New serial number for the plant identification tag replacement.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for retagging cannabis plants with new serial numbers for compliance and tracking updates." + }, + "RetireImmaturePlantsDetails": { + "type": "object", + "properties": { + "batchId": { + "type": "integer", + "description": "Batch identifier for the plant batch containing plants to be retired.", + "format": "int32" + }, + "countToRetire": { + "type": "integer", + "description": "Number of plants to retire from the specified batch.", + "format": "int32" + }, + "reasonCode": { + "type": "string", + "description": "Standardized reason code for the plant retirement (e.g., \"DISEASE\", \"PEST\", \"POOR_HEALTH\", \"CONTAMINATION\").", + "nullable": true + }, + "retireDate": { + "type": "string", + "description": "Date when the plants were retired for cultivation timeline documentation.", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Detailed specification for retiring immature plants from cultivation batches with compliance documentation." + }, + "RetireImmaturePlantsRequest": { + "type": "object", + "properties": { + "plants": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RetireImmaturePlantsDetails" + }, + "description": "Collection of plant retirement specifications for batch processing of plant removals.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for retiring immature cannabis plants due to loss, contamination, or quality issues." + }, + "RetirePlantRequest": { + "type": "object", + "properties": { + "plantIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "reasonId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "reasonCode": { + "type": "string", + "nullable": true + }, + "wasteType": { + "type": "string", + "nullable": true + }, + "roomId": { + "type": "integer", + "format": "int32" + }, + "wasteWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "comment": { + "type": "string", + "nullable": true + }, + "wastePackageId": { + "type": "string", + "nullable": true + }, + "wasteDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "plantWeight": { + "type": "number", + "format": "double", + "nullable": true + }, + "plantWeightUnitId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "wasteMaterial": { + "type": "string", + "nullable": true + }, + "wasteReason": { + "type": "string", + "nullable": true + }, + "wasteMethod": { + "type": "string", + "nullable": true + }, + "reasonNote": { + "type": "string", + "nullable": true + }, + "emptyCloneGroup": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "Room": { + "type": "object", + "properties": { + "roomId": { + "type": "integer", + "description": "Unique identifier for the cultivation room or facility area.\n**Required for updates, null/0 for new room creation.**", + "format": "int32", + "nullable": true + }, + "roomName": { + "type": "string", + "description": "Human-readable name for room identification and cultivation tracking.\n**Required for both create and update operations.**", + "nullable": true + }, + "isQuarantineRoom": { + "type": "boolean", + "description": "Indicates if this room is designated for quarantine operations and compliance isolation." + }, + "isVaultRoom": { + "type": "boolean", + "description": "Indicates if this room is designated as a secure vault for valuable inventory storage." + }, + "isWaitingRoom": { + "type": "boolean", + "description": "Indicates if this room is designated as a customer waiting area." + }, + "isSalesFloor": { + "type": "boolean", + "description": "Indicates if this room is designated as the main sales floor for customer transactions." + }, + "isPOSRoom": { + "type": "boolean", + "description": "Indicates if this room is designated for point-of-sale operations and transactions." + }, + "isInventoryRoom": { + "type": "boolean", + "description": "Indicates if this room is designated for inventory storage and management." + }, + "isPreOrderRoom": { + "type": "boolean", + "description": "Indicates if this room is designated for pre-order fulfillment operations." + }, + "isEcommerceRoom": { + "type": "boolean", + "description": "Indicates if this room is designated for e-commerce order processing and fulfillment." + } + }, + "additionalProperties": false, + "description": "Cultivation room model containing facility area configuration information for cannabis operations and facility management." + }, + "RoomWaste": { + "type": "object", + "properties": { + "wasteId": { + "type": "integer", + "description": "Unique identifier for the waste record.", + "format": "int32", + "nullable": true + }, + "referenceNo": { + "type": "string", + "description": "Reference number for waste tracking and documentation.", + "nullable": true + }, + "comments": { + "type": "string", + "description": "Additional comments or notes about the waste disposal.", + "nullable": true + }, + "wasteDate": { + "type": "string", + "description": "Date when the waste disposal occurred.", + "format": "date-time", + "nullable": true + }, + "wasteType": { + "type": "string", + "description": "Type or category of waste material being disposed.", + "nullable": true + }, + "roomId": { + "type": "integer", + "description": "Identifier for the room or facility area where waste originated.", + "format": "int32" + }, + "wasteAmount": { + "type": "number", + "description": "Quantity of waste material being disposed.", + "format": "double" + }, + "unitId": { + "type": "integer", + "description": "Unit of measurement identifier for the waste amount.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Room-based waste record model for facility waste disposal tracking and compliance documentation." + }, + "SavedReceive": { + "type": "object", + "properties": { + "receiveInventoryHistoryId": { + "type": "integer", + "description": "Unique identifier for the created receive inventory transaction.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Response model for successful inventory receive order creation operations." + }, + "SetImageRequest": { + "required": ["base64Image", "fileName", "productId"], + "type": "object", + "properties": { + "productId": { + "type": "integer", + "description": "The unique identifier of the product to associate the image with.", + "format": "int32" + }, + "base64Image": { + "minLength": 1, + "type": "string", + "description": "Base64-encoded string representation of the image file data." + }, + "fileName": { + "minLength": 1, + "type": "string", + "description": "Original filename of the image including file extension for proper handling." + }, + "image": { + "type": "string", + "description": "Computed property that converts the Base64Image string to byte array for processing.", + "format": "byte", + "nullable": true, + "readOnly": true + }, + "fileType": { + "$ref": "#/components/schemas/UploadFileType" + } + }, + "additionalProperties": false, + "description": "Request model for setting a product image through the product image management API." + }, + "SetImageResponse": { + "type": "object", + "properties": { + "imageId": { + "type": "integer", + "description": "Unique identifier assigned to the uploaded image for tracking and reference.", + "format": "int32" + }, + "imageUrl": { + "type": "string", + "description": "Public URL where the uploaded image can be accessed and displayed.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Response model for successful product image upload operations." + }, + "Severity": { + "enum": [0, 1, 2], + "type": "integer", + "format": "int32" + }, + "Size": { + "type": "object", + "properties": { + "sizeId": { + "type": "integer", + "description": "Unique identifier for the product size configuration.", + "format": "int32" + }, + "sizeName": { + "type": "string", + "description": "Display name for the product size.", + "nullable": true + }, + "description": { + "type": "string", + "description": "Detailed description of the product size and its usage.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Represents a product size configuration for cannabis products within an organization." + }, + "SplitBatchDetails": { + "type": "object", + "properties": { + "newBatchName": { + "type": "string", + "nullable": true + }, + "batchId": { + "type": "integer", + "format": "int32" + }, + "location": { + "type": "string", + "nullable": true + }, + "strain": { + "type": "string", + "nullable": true + }, + "quantity": { + "type": "integer", + "format": "int32" + }, + "splitDate": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "SplitImmaturePlantResult": { + "type": "object", + "properties": { + "batch": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SplitImmaturePlantResultDetail" + }, + "nullable": true + }, + "plant": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SplitImmaturePlantResultDetail" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "SplitImmaturePlantResultApiResult": { + "type": "object", + "properties": { + "result": { + "type": "boolean" + }, + "message": { + "type": "string", + "nullable": true + }, + "data": { + "$ref": "#/components/schemas/SplitImmaturePlantResult" + } + }, + "additionalProperties": false + }, + "SplitImmaturePlantResultDetail": { + "type": "object", + "properties": { + "batchId": { + "type": "integer", + "format": "int32" + }, + "batchPlantCount": { + "type": "integer", + "format": "int32" + }, + "newBatchId": { + "type": "integer", + "format": "int32" + }, + "newBatchPlantCount": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "SplitImmaturePlantsRequest": { + "type": "object", + "properties": { + "batch": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SplitBatchDetails" + }, + "description": "Collection of batch split specifications for dividing immature plant batches into smaller groups.", + "nullable": true + }, + "plant": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SplitPlantDetails" + }, + "description": "Collection of individual plant split specifications for precise cultivation management.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for splitting immature cannabis plant batches and individual plants for cultivation optimization." + }, + "SplitPlantDetails": { + "type": "object", + "properties": { + "batchId": { + "type": "integer", + "format": "int32" + }, + "location": { + "type": "string", + "nullable": true + }, + "strain": { + "type": "string", + "nullable": true + }, + "quantity": { + "type": "integer", + "format": "int32" + }, + "splitDate": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "StandardAllergensDetails": { + "type": "object", + "properties": { + "milk": { + "type": "boolean" + }, + "eggs": { + "type": "boolean" + }, + "fish": { + "type": "boolean" + }, + "peanuts": { + "type": "boolean" + }, + "treeNuts": { + "type": "boolean" + }, + "sesame": { + "type": "boolean" + }, + "shellfish": { + "type": "boolean" + }, + "soybeans": { + "type": "boolean" + }, + "wheat": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "StrainDetail": { + "type": "object", + "properties": { + "strainId": { + "type": "integer", + "description": "Unique identifier for the strain", + "format": "int32" + }, + "strainName": { + "type": "string", + "description": "Name of the cannabis strain", + "nullable": true + }, + "strainDescription": { + "type": "string", + "description": "Detailed description of the strain's characteristics and effects", + "nullable": true + }, + "strainAbbreviation": { + "type": "string", + "description": "Short name or code for the strain", + "nullable": true + }, + "strainType": { + "type": "string", + "description": "Classification type of the strain. Valid values: `Indica`, `Sativa`, `Hybrid`, `CBD`", + "nullable": true + }, + "externalId": { + "type": "string", + "description": "External system identifier for third-party integration", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Cannabis strain information with genetic and classification details for product categorization and cultivation tracking." + }, + "StringIEnumerableOptional": { + "type": "array", + "additionalProperties": false + }, + "StringOptional": { + "type": "string", + "additionalProperties": false + }, + "SuccessResult": { + "type": "object", + "properties": { + "result": { + "type": "boolean" + }, + "message": { + "type": "string", + "nullable": true + }, + "data": { + "type": "object", + "nullable": true + } + }, + "additionalProperties": false + }, + "Table": { + "type": "object", + "properties": { + "tableId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "tableName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Tag": { + "type": "object", + "properties": { + "tagName": { + "type": "string", + "nullable": true + }, + "tagId": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "TaxSummaryInfo": { + "type": "object", + "properties": { + "rateName": { + "type": "string", + "description": "Name of the tax type being summarized (e.g., \"State Excise Tax\", \"Sales Tax\").", + "nullable": true + }, + "amount": { + "type": "number", + "description": "Total tax amount for this tax type across all transaction items (in USD).", + "format": "double" + } + }, + "additionalProperties": false, + "description": "Summary tax information aggregated across transaction items for reporting and receipt generation." + }, + "Terminal": { + "type": "object", + "properties": { + "terminalId": { + "type": "integer", + "description": "Unique identifier for the point-of-sale terminal.", + "format": "int32" + }, + "terminalName": { + "type": "string", + "description": "Human-readable name for terminal identification and assignment.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Point-of-sale terminal model containing terminal identification information for retail operations and transaction processing." + }, + "Transaction": { + "type": "object", + "properties": { + "transactionId": { + "type": "integer", + "format": "int32" + }, + "customerId": { + "type": "integer", + "format": "int32" + }, + "employeeId": { + "type": "integer", + "format": "int32" + }, + "transactionDate": { + "type": "string", + "format": "date-time" + }, + "voidDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "isVoid": { + "type": "boolean" + }, + "subtotal": { + "type": "number", + "format": "double" + }, + "totalDiscount": { + "type": "number", + "format": "double" + }, + "totalBeforeTax": { + "type": "number", + "format": "double", + "readOnly": true + }, + "tax": { + "type": "number", + "format": "double" + }, + "tipAmount": { + "type": "number", + "format": "double", + "nullable": true + }, + "total": { + "type": "number", + "format": "double" + }, + "paid": { + "type": "number", + "format": "double" + }, + "changeDue": { + "type": "number", + "format": "double" + }, + "totalItems": { + "type": "integer", + "format": "int32" + }, + "terminalName": { + "type": "string", + "nullable": true + }, + "checkInDate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "invoiceNumber": { + "type": "string", + "nullable": true + }, + "isTaxInclusive": { + "type": "boolean" + }, + "transactionType": { + "type": "string", + "description": "Will have one of the following values: Retail, Transfer, WholesaleOrder", + "nullable": true + }, + "loyaltyEarned": { + "type": "number", + "description": "Loyalty points earned on this transaction (can be negative if it's a return)", + "format": "double", + "nullable": true + }, + "loyaltySpent": { + "type": "number", + "description": "Loyalty points spent on this transaction (can be negative if it's a return)", + "format": "double", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TransactionItem" + }, + "nullable": true + }, + "discounts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AppliedDiscount" + }, + "nullable": true, + "readOnly": true + }, + "lastModifiedDateUTC": { + "type": "string", + "format": "date-time" + }, + "cashPaid": { + "type": "number", + "format": "double", + "nullable": true + }, + "debitPaid": { + "type": "number", + "format": "double", + "nullable": true + }, + "electronicPaid": { + "type": "number", + "format": "double", + "nullable": true + }, + "electronicPaymentMethod": { + "type": "string", + "nullable": true + }, + "checkPaid": { + "type": "number", + "format": "double", + "nullable": true + }, + "creditPaid": { + "type": "number", + "format": "double", + "nullable": true + }, + "giftPaid": { + "type": "number", + "format": "double", + "nullable": true + }, + "mmapPaid": { + "type": "number", + "format": "double", + "nullable": true + }, + "prePaymentAmount": { + "type": "number", + "format": "double", + "nullable": true + }, + "revenueFeesAndDonations": { + "type": "number", + "format": "double", + "nullable": true + }, + "nonRevenueFeesAndDonations": { + "type": "number", + "format": "double", + "nullable": true + }, + "feesAndDonations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FeeDonationInfo" + }, + "nullable": true + }, + "taxSummary": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaxSummaryInfo" + }, + "nullable": true, + "readOnly": true + }, + "returnOnTransactionId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "adjustmentForTransactionId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "orderType": { + "type": "string", + "nullable": true + }, + "wasPreOrdered": { + "type": "boolean" + }, + "orderSource": { + "type": "string", + "nullable": true + }, + "orderMethod": { + "type": "string", + "nullable": true + }, + "invoiceName": { + "type": "string", + "nullable": true + }, + "isReturn": { + "type": "boolean", + "readOnly": true + }, + "authCode": { + "type": "string", + "nullable": true + }, + "customerTypeId": { + "type": "integer", + "format": "int32" + }, + "isMedical": { + "type": "boolean" + }, + "orderIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "nullable": true + }, + "totalCredit": { + "type": "number", + "format": "double" + }, + "completedByUser": { + "type": "string", + "nullable": true + }, + "responsibleForSaleUserId": { + "type": "integer", + "format": "int32" + }, + "transactionDateLocalTime": { + "type": "string", + "format": "date-time" + }, + "estTimeArrivalLocal": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "estDeliveryDateLocal": { + "type": "string", + "format": "date-time", + "nullable": true, + "readOnly": true + }, + "referenceId": { + "type": "string", + "nullable": true + }, + "manualPayments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ManualPayment" + }, + "nullable": true + }, + "manualPaid": { + "type": "number", + "format": "double", + "nullable": true + }, + "integratedPayments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IntegratedPayment" + }, + "nullable": true + }, + "integratedPaid": { + "type": "number", + "format": "double", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Complete cannabis retail transaction model representing all aspects of cannabis sales operations." + }, + "TransactionItem": { + "type": "object", + "properties": { + "transactionId": { + "type": "integer", + "description": "Parent transaction identifier linking this item to the overall transaction.", + "format": "int32" + }, + "productId": { + "type": "integer", + "description": "Product identifier for the purchased cannabis product.", + "format": "int32" + }, + "totalPrice": { + "type": "number", + "description": "Total price for this line item including all taxes and discounts (in USD).", + "format": "double" + }, + "quantity": { + "type": "number", + "description": "Quantity of the product purchased (units based on product type - grams, pieces, etc.).", + "format": "double" + }, + "unitPrice": { + "type": "number", + "description": "Unit price per individual item before taxes and discounts (in USD).", + "format": "double" + }, + "unitCost": { + "type": "number", + "description": "Cost basis of the product for internal accounting and margin calculations (in USD).", + "format": "double", + "nullable": true + }, + "packageId": { + "type": "string", + "description": "State tracking system package identifier for regulatory compliance (seed-to-sale tracking).", + "nullable": true + }, + "sourcePackageId": { + "type": "string", + "description": "Original source package identifier for product lineage tracking in state systems.", + "nullable": true + }, + "totalDiscount": { + "type": "number", + "description": "Total discount amount applied to this line item (in USD).", + "format": "double" + }, + "inventoryId": { + "type": "integer", + "description": "Inventory record identifier for the specific product inventory being sold.", + "format": "int32" + }, + "unitId": { + "type": "integer", + "description": "Unit type identifier defining how the product is measured and sold.", + "format": "int32" + }, + "unitWeight": { + "type": "number", + "description": "Weight of the product unit in grams (calculated for flower products with UnitId = 1).", + "format": "double", + "nullable": true, + "readOnly": true + }, + "unitWeightUnit": { + "type": "string", + "description": "Unit of measurement for product weight (always \"g\" for grams).", + "nullable": true, + "readOnly": true + }, + "flowerEquivalent": { + "type": "number", + "description": "Flower equivalent weight for concentrate products in grams (for regulatory compliance).", + "format": "double", + "nullable": true + }, + "flowerEquivalentUnit": { + "type": "string", + "description": "Unit of measurement for flower equivalent (always \"g\" for grams).", + "nullable": true, + "readOnly": true + }, + "discounts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AppliedDiscount" + }, + "description": "Collection of discounts applied to this transaction item.", + "nullable": true + }, + "taxes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LineItemTaxInfo" + }, + "description": "Collection of taxes applied to this transaction item.", + "nullable": true + }, + "returnDate": { + "type": "string", + "description": "Date when this item was returned (null if not returned).", + "format": "date-time", + "nullable": true + }, + "isReturned": { + "type": "boolean", + "description": "Indicates whether this transaction item has been returned.", + "readOnly": true + }, + "returnedByTransactionId": { + "type": "integer", + "description": "Transaction identifier of the return transaction that processed this item's return.", + "format": "int32", + "nullable": true + }, + "returnReason": { + "type": "string", + "description": "Reason provided for returning this item (e.g., \"Defective\", \"Customer Dissatisfaction\").", + "nullable": true + }, + "batchName": { + "type": "string", + "description": "Cultivation batch name for product traceability and regulatory compliance.", + "nullable": true + }, + "transactionItemId": { + "type": "integer", + "description": "Reference identifier to tie child items to parent items within a transaction.\nNot guaranteed to be unique outside of a single transaction.", + "format": "int32", + "readOnly": true + }, + "vendor": { + "type": "string", + "description": "Vendor or supplier name for the product.", + "nullable": true + }, + "isCoupon": { + "type": "boolean", + "description": "Indicates whether this item represents a coupon or promotional discount rather than a physical product." + } + }, + "additionalProperties": false, + "description": "Individual line item within a cannabis retail transaction containing product, pricing, and compliance information." + }, + "Unit": { + "type": "object", + "properties": { + "unitId": { + "type": "integer", + "description": "Unique identifier for the measurement unit.", + "format": "int32" + }, + "unitName": { + "type": "string", + "description": "Full name of the measurement unit (e.g., \"Grams\", \"Ounces\", \"Pounds\").", + "nullable": true + }, + "abbreviation": { + "type": "string", + "description": "Short abbreviation for the unit (e.g., \"g\", \"oz\", \"lb\").", + "nullable": true + }, + "unitTypeId": { + "type": "integer", + "description": "Unit type classification identifier linking to measurement category.", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "Measurement unit model for cannabis product tracking and inventory management." + }, + "UnitType": { + "type": "object", + "properties": { + "unitTypeId": { + "type": "integer", + "description": "Unique identifier for the unit type category.", + "format": "int32" + }, + "unitTypeName": { + "type": "string", + "description": "Display name of the unit type category (e.g., \"Weight\", \"Volume\", \"Quantity\").", + "nullable": true + }, + "unitTypeAbbreivation": { + "type": "string", + "description": "Short abbreviation for the unit type (e.g., \"Wgt\", \"Vol\", \"Qty\").", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Unit type classification model for organizing measurement units by category." + }, + "UpdateBatchLabResultsRequest": { + "required": ["batchName"], + "type": "object", + "properties": { + "batchName": { + "minLength": 1, + "type": "string", + "description": "Name of the batch to update with laboratory test results (required)." + }, + "sampleWeight": { + "type": "number", + "description": "Weight of the laboratory sample used for testing (in grams).", + "format": "double", + "nullable": true + }, + "labResults": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CannabinoidTerpeneValue" + }, + "description": "Collection of laboratory test results including cannabinoids and terpenes.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for updating laboratory test results for a specific batch by batch name." + }, + "UpdateBatchRequest": { + "type": "object", + "properties": { + "batchName": { + "type": "string", + "nullable": true + }, + "roomId": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "strainId": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "UpdateDeliveryRouteDetailRequest": { + "type": "object", + "properties": { + "transactionId": { + "type": "integer", + "description": "Delivery transaction identifier to update (required).", + "format": "int32" + }, + "driverId": { + "type": "integer", + "description": "Primary driver identifier for delivery assignment (optional).", + "format": "int32", + "nullable": true + }, + "driverId2": { + "type": "integer", + "description": "Secondary driver identifier for delivery assignment (optional).", + "format": "int32", + "nullable": true + }, + "vehicleId": { + "type": "integer", + "description": "Vehicle identifier for delivery assignment (optional).", + "format": "int32", + "nullable": true + }, + "route": { + "type": "string", + "description": "Route information or delivery notes (optional).", + "nullable": true + }, + "status": { + "type": "string", + "description": "Delivery status update (optional).", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Request model for updating delivery route details including vehicle assignments, driver assignments, and delivery status." + }, + "UpdateJournalEntryRequest": { + "required": ["body", "date", "journalEntryId", "subject"], + "type": "object", + "properties": { + "journalEntryId": { + "type": "integer", + "description": "The ID of the existing journal entry to update.", + "format": "int32" + }, + "subject": { + "minLength": 1, + "type": "string", + "description": "Updated title or summary for the journal entry." + }, + "body": { + "minLength": 1, + "type": "string", + "description": "Updated detailed content and notes for the journal entry." + }, + "date": { + "type": "string", + "description": "Updated date and time when the journal entry should be dated.", + "format": "date-time" + } + }, + "additionalProperties": false, + "description": "Request model for updating existing customer journal entries with modified content and details." + }, + "UpdatePackageTagsRequest": { + "required": ["tags"], + "type": "object", + "properties": { + "packageIds": { + "$ref": "#/components/schemas/StringIEnumerableOptional" + }, + "inventoryIds": { + "$ref": "#/components/schemas/Int32IEnumerableOptional" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Required collection of tags to apply to the specified packages (required)." + } + }, + "additionalProperties": false + }, + "UpdatePlantDetails": { + "type": "object", + "properties": { + "plantId": { + "type": "integer", + "format": "int32" + }, + "serialNumber": { + "$ref": "#/components/schemas/StringOptional" + }, + "dateCreated": { + "$ref": "#/components/schemas/DateTimeNullableOptional" + }, + "bornDate": { + "$ref": "#/components/schemas/DateTimeNullableOptional" + }, + "isMother": { + "$ref": "#/components/schemas/BooleanNullableOptional" + }, + "strainId": { + "$ref": "#/components/schemas/Int32NullableOptional" + }, + "roomId": { + "$ref": "#/components/schemas/Int32NullableOptional" + }, + "tableId": { + "$ref": "#/components/schemas/Int32NullableOptional" + }, + "batchId": { + "$ref": "#/components/schemas/Int32NullableOptional" + } + }, + "additionalProperties": false + }, + "UpdatePlantsRequest": { + "type": "object", + "properties": { + "plants": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdatePlantDetails" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "UpdatePreOrderRequest": { + "type": "object", + "properties": { + "orderId": { + "type": "integer", + "format": "int32" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PreOrderItem" + }, + "nullable": true + }, + "isDelivery": { + "type": "boolean" + }, + "orderSource": { + "type": "string", + "nullable": true, + "deprecated": true + }, + "deliveryStreet": { + "type": "string", + "nullable": true + }, + "deliveryCity": { + "type": "string", + "nullable": true + }, + "deliveryState": { + "type": "string", + "nullable": true + }, + "deliveryPostalCode": { + "type": "string", + "nullable": true + }, + "deliveryScheduleId": { + "$ref": "#/components/schemas/DeliveryScheduleType" + }, + "notes": { + "type": "string", + "nullable": true + }, + "redemptions": { + "$ref": "#/components/schemas/PreOrderRedemptionIEnumerableOptional" + }, + "customerId": { + "type": "integer", + "format": "int32" + }, + "deliveryStreet2": { + "type": "string", + "nullable": true + }, + "timeWindowStartDateUtc": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "timeWindowEndDateUtc": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "UpdateStrain": { + "required": ["strainDescription", "strainName"], + "type": "object", + "properties": { + "strainId": { + "type": "integer", + "description": "Unique identifier for strain updates.\n- **For CREATE**: Omit this field, set to null, or set to 0\n- **For UPDATE**: Provide the existing strain's ID", + "format": "int32", + "nullable": true + }, + "strainName": { + "minLength": 1, + "type": "string", + "description": "Name of the cannabis strain (required for creation)" + }, + "strainDescription": { + "minLength": 1, + "type": "string", + "description": "Detailed description of the strain's characteristics and effects.\n**REQUIRED** - Cannot be null or empty for both create and update operations." + }, + "abbreviation": { + "type": "string", + "description": "Short name or code for the strain (optional)", + "nullable": true + }, + "strainType": { + "type": "string", + "description": "Classification type of the strain (optional).\n**Must be one of**: `Indica`, `Sativa`, `Hybrid`, `CBD`\nIf provided, value will be validated against allowed strain types.", + "nullable": true + }, + "externalId": { + "type": "string", + "description": "External system identifier for third-party integration (optional).\nUseful for synchronizing with cultivation management systems.", + "nullable": true + }, + "broadcast": { + "$ref": "#/components/schemas/BooleanOptional" + } + }, + "additionalProperties": false, + "description": "Request model for creating or updating cannabis strain information.\n\n**Create vs Update Behavior:**\n- **CREATE**: When `StrainId` is null, 0, or omitted, a new strain record will be created\n- **UPDATE**: When `StrainId` is provided with a valid strain ID, the existing strain will be updated\n\n**Sparse Update Behavior:**\n- **Provided fields**: Will overwrite existing values with provided data\n- **Omitted fields**: Will preserve existing values (no data loss for updates)\n- **Special handling**: `StrainDescription` is always required and cannot be null" + }, + "UploadFileType": { + "enum": [0, 1, 2, 3, 4, 5], + "type": "integer", + "format": "int32" + }, + "ValidationFailure": { + "type": "object", + "properties": { + "propertyName": { + "type": "string", + "nullable": true + }, + "errorMessage": { + "type": "string", + "nullable": true + }, + "attemptedValue": { + "type": "object", + "nullable": true + }, + "customState": { + "type": "object", + "nullable": true + }, + "severity": { + "$ref": "#/components/schemas/Severity" + }, + "errorCode": { + "type": "string", + "nullable": true + }, + "formattedMessagePlaceholderValues": { + "type": "object", + "additionalProperties": { + "type": "object", + "nullable": true + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ValidationResult": { + "type": "object", + "properties": { + "isValid": { + "type": "boolean", + "readOnly": true + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ValidationFailure" + }, + "nullable": true + }, + "ruleSetsExecuted": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "VehicleDetail": { + "type": "object", + "properties": { + "vehicleId": { + "type": "integer", + "format": "int32" + }, + "make": { + "type": "string", + "nullable": true + }, + "model": { + "type": "string", + "nullable": true + }, + "modelYear": { + "type": "string", + "nullable": true + }, + "color": { + "type": "string", + "nullable": true + }, + "licensePlate": { + "type": "string", + "nullable": true + }, + "vin": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Vendor": { + "type": "object", + "properties": { + "vendorId": { + "type": "integer", + "description": "Unique identifier for the vendor in the system (null for new vendor creation).", + "format": "int32", + "nullable": true + }, + "vendorName": { + "type": "string", + "description": "Official business name of the vendor as registered with regulatory authorities.", + "nullable": true + }, + "address": { + "type": "string", + "description": "Street address of the vendor's business location.", + "nullable": true + }, + "city": { + "type": "string", + "description": "City where the vendor's business is located.", + "nullable": true + }, + "state": { + "type": "string", + "description": "State or province where the vendor's business is located.", + "nullable": true + }, + "postalCode": { + "type": "string", + "description": "Postal or ZIP code for the vendor's business address.", + "nullable": true + }, + "licenseNumber": { + "type": "string", + "description": "Cannabis business license number issued by state regulatory authorities.", + "nullable": true + }, + "contactName": { + "type": "string", + "description": "Name of the primary business contact for this vendor.", + "nullable": true + }, + "contactEmail": { + "type": "string", + "description": "Email address for business communications with the vendor.", + "nullable": true + }, + "contactPhone": { + "type": "string", + "description": "Phone number for business communications with the vendor.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Vendor information model for cannabis supply chain and compliance management." + }, + "WasteSummary": { + "type": "object", + "properties": { + "roomWaste": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoomWaste" + }, + "description": "Collection of room-based waste disposal records.", + "nullable": true + }, + "harvestWaste": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ObjectWaste" + }, + "description": "Collection of harvest-based waste disposal records.", + "nullable": true + }, + "plantWaste": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ObjectWaste" + }, + "description": "Collection of plant-based waste disposal records.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Comprehensive waste summary model containing all waste types for facility waste management and regulatory reporting." + }, + "WeeklyRecurrenceInfo": { + "type": "object", + "properties": { + "startTime": { + "type": "string", + "description": "Daily start time when discount becomes available (optional).", + "format": "date-span", + "nullable": true + }, + "endTime": { + "type": "string", + "description": "Daily end time when discount expires (optional).", + "format": "date-span", + "nullable": true + }, + "appliesOnMonday": { + "type": "boolean", + "description": "Indicates if discount is available on Mondays." + }, + "appliesOnTuesday": { + "type": "boolean", + "description": "Indicates if discount is available on Tuesdays." + }, + "appliesOnWednesday": { + "type": "boolean", + "description": "Indicates if discount is available on Wednesdays." + }, + "appliesOnThursday": { + "type": "boolean", + "description": "Indicates if discount is available on Thursdays." + }, + "appliesOnFriday": { + "type": "boolean", + "description": "Indicates if discount is available on Fridays." + }, + "appliesOnSaturday": { + "type": "boolean", + "description": "Indicates if discount is available on Saturdays." + }, + "appliesOnSunday": { + "type": "boolean", + "description": "Indicates if discount is available on Sundays." + } + }, + "additionalProperties": false, + "description": "Weekly recurring schedule model defining time-based availability patterns for discount application." + } + }, + "securitySchemes": { + "basicAuth": { + "type": "http", + "description": "**API Key Authentication Required**\r\n\r\n**How to Authenticate:**\r\n1. Use HTTP Basic Authentication\r\n2. Username: Your API key\r\n3. Password: Leave empty\r\n4. Header format: `Authorization: Basic `\r\n\r\n**Example:**\r\n- API Key: `your-api-key-here`\r\n- Header: `Authorization: Basic eW91ci1hcGkta2V5LWhlcmU6`\r\n\r\n**All endpoints require authentication** - requests without valid API keys will receive `401 Unauthorized` responses.", + "scheme": "basic" + } + } + }, + "security": [ + { + "basicAuth": [] + } + ] +} diff --git a/packages/openapi-ts/src/config/parser.ts b/packages/openapi-ts/src/config/parser.ts index 2e9328ecc5..e44f6af867 100644 --- a/packages/openapi-ts/src/config/parser.ts +++ b/packages/openapi-ts/src/config/parser.ts @@ -11,98 +11,143 @@ export const defaultPaginationKeywords = [ ] as const; export const getParser = (userConfig: UserConfig): Config['parser'] => { - const parser: Config['parser'] = { - ...userConfig.parser, - hooks: {}, - pagination: { - keywords: defaultPaginationKeywords, - }, - transforms: { - enums: { - case: 'PascalCase', - enabled: false, - mode: 'root', - name: '{{name}}Enum', + const parser = valueToObject({ + defaultValue: { + hooks: {}, + pagination: { + keywords: defaultPaginationKeywords, }, - readWrite: { - enabled: true, - requests: { - case: 'preserve', - name: '{{name}}Writable', + transforms: { + enums: { + case: 'PascalCase', + enabled: false, + mode: 'root', + name: '{{name}}Enum', }, - responses: { - case: 'preserve', - name: '{{name}}', + propertiesRequiredByDefault: false, + readWrite: { + enabled: true, + requests: { + case: 'preserve', + name: '{{name}}Writable', + }, + responses: { + case: 'preserve', + name: '{{name}}', + }, }, }, + validate_EXPERIMENTAL: false, }, - validate_EXPERIMENTAL: false, - }; - - if (userConfig.parser) { - if (userConfig.parser.hooks) { - parser.hooks = userConfig.parser.hooks; - } - - if (userConfig.parser.pagination?.keywords) { - parser.pagination.keywords = userConfig.parser.pagination.keywords; - } - - if (userConfig.parser.transforms) { - if (userConfig.parser.transforms.enums !== undefined) { - parser.transforms.enums = valueToObject({ + mappers: { + object: (fields, defaultValue) => ({ + ...fields, + pagination: valueToObject({ defaultValue: { - ...parser.transforms.enums, - enabled: Boolean(userConfig.parser.transforms.enums), - }, - mappers: { - boolean: (enabled) => ({ enabled }), - string: (mode) => ({ mode }), + ...(defaultValue.pagination as Extract< + typeof defaultValue.pagination, + Record + >), }, - value: userConfig.parser.transforms.enums, - }) as typeof parser.transforms.enums; - } - - if (userConfig.parser.transforms.readWrite !== undefined) { - parser.transforms.readWrite = valueToObject({ + value: fields.pagination, + }), + transforms: valueToObject({ defaultValue: { - ...parser.transforms.readWrite, - enabled: Boolean(userConfig.parser.transforms.readWrite), + ...(defaultValue.transforms as Extract< + typeof defaultValue.transforms, + Record + >), }, mappers: { - boolean: (enabled) => ({ enabled }), - object: (fields) => ({ + object: (fields, defaultValue) => ({ ...fields, - requests: valueToObject({ - defaultValue: parser.transforms.readWrite.requests, + enums: valueToObject({ + defaultValue: { + ...(defaultValue.enums as Extract< + typeof defaultValue.enums, + Record + >), + enabled: + fields.enums !== undefined + ? Boolean(fields.enums) + : ( + defaultValue.enums as Extract< + typeof defaultValue.enums, + Record + > + ).enabled, + }, mappers: { - function: (name) => ({ name }), - string: (name) => ({ name }), + boolean: (enabled) => ({ enabled }), + string: (mode) => ({ mode }), }, - value: fields.requests, + value: fields.enums, }), - responses: valueToObject({ - defaultValue: parser.transforms.readWrite.responses, + propertiesRequiredByDefault: + fields.propertiesRequiredByDefault !== undefined + ? fields.propertiesRequiredByDefault + : defaultValue.propertiesRequiredByDefault, + readWrite: valueToObject({ + defaultValue: { + ...(defaultValue.readWrite as Extract< + typeof defaultValue.readWrite, + Record + >), + enabled: + fields.readWrite !== undefined + ? Boolean(fields.readWrite) + : ( + defaultValue.readWrite as Extract< + typeof defaultValue.readWrite, + Record + > + ).enabled, + }, mappers: { - function: (name) => ({ name }), - string: (name) => ({ name }), + boolean: (enabled) => ({ enabled }), + object: (fields, defaultValue) => ({ + ...fields, + requests: valueToObject({ + defaultValue: { + ...(defaultValue.requests as Extract< + typeof defaultValue.requests, + Record + >), + }, + mappers: { + function: (name) => ({ name }), + string: (name) => ({ name }), + }, + value: fields.requests, + }), + responses: valueToObject({ + defaultValue: { + ...(defaultValue.responses as Extract< + typeof defaultValue.responses, + Record + >), + }, + mappers: { + function: (name) => ({ name }), + string: (name) => ({ name }), + }, + value: fields.responses, + }), + }), }, - value: fields.responses, + value: fields.readWrite, }), }), }, - value: userConfig.parser.transforms.readWrite, - }) as typeof parser.transforms.readWrite; - } - } - - if (userConfig.parser.validate_EXPERIMENTAL) { - parser.validate_EXPERIMENTAL = - userConfig.parser.validate_EXPERIMENTAL === true - ? 'warn' - : userConfig.parser.validate_EXPERIMENTAL; - } - } - - return parser; + value: fields.transforms, + }), + validate_EXPERIMENTAL: + fields.validate_EXPERIMENTAL === true + ? 'warn' + : fields.validate_EXPERIMENTAL, + }), + }, + value: userConfig.parser, + }); + return parser as Config['parser']; }; diff --git a/packages/openapi-ts/src/generate/__tests__/class.test.ts b/packages/openapi-ts/src/generate/__tests__/class.test.ts index d68e87eb2d..33419b551e 100644 --- a/packages/openapi-ts/src/generate/__tests__/class.test.ts +++ b/packages/openapi-ts/src/generate/__tests__/class.test.ts @@ -57,6 +57,7 @@ describe('generateLegacyClientClass', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { diff --git a/packages/openapi-ts/src/generate/__tests__/core.test.ts b/packages/openapi-ts/src/generate/__tests__/core.test.ts index 8e0332a981..174280cafc 100644 --- a/packages/openapi-ts/src/generate/__tests__/core.test.ts +++ b/packages/openapi-ts/src/generate/__tests__/core.test.ts @@ -72,6 +72,7 @@ describe('generateLegacyCore', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { @@ -224,6 +225,7 @@ describe('generateLegacyCore', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { @@ -359,6 +361,7 @@ describe('generateLegacyCore', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { diff --git a/packages/openapi-ts/src/generate/legacy/__tests__/index.test.ts b/packages/openapi-ts/src/generate/legacy/__tests__/index.test.ts index da5b2332ab..c8b36f9b62 100644 --- a/packages/openapi-ts/src/generate/legacy/__tests__/index.test.ts +++ b/packages/openapi-ts/src/generate/legacy/__tests__/index.test.ts @@ -56,6 +56,7 @@ describe('generateIndexFile', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { diff --git a/packages/openapi-ts/src/generate/legacy/__tests__/output.test.ts b/packages/openapi-ts/src/generate/legacy/__tests__/output.test.ts index a0db4be34b..88aa382a56 100644 --- a/packages/openapi-ts/src/generate/legacy/__tests__/output.test.ts +++ b/packages/openapi-ts/src/generate/legacy/__tests__/output.test.ts @@ -69,6 +69,7 @@ describe('generateLegacyOutput', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { diff --git a/packages/openapi-ts/src/openApi/shared/transforms/index.ts b/packages/openapi-ts/src/openApi/shared/transforms/index.ts index c0203b8ca9..321863c0ac 100644 --- a/packages/openapi-ts/src/openApi/shared/transforms/index.ts +++ b/packages/openapi-ts/src/openApi/shared/transforms/index.ts @@ -1,5 +1,6 @@ import type { IR } from '../../../ir/types'; import { enumsTransform } from './enums'; +import { propertiesRequiredByDefaultTransform } from './propertiesRequiredByDefault'; import { readWriteTransform } from './readWrite'; export const transformOpenApiSpec = ({ context }: { context: IR.Context }) => { @@ -12,6 +13,10 @@ export const transformOpenApiSpec = ({ context }: { context: IR.Context }) => { }); } + if (context.config.parser.transforms.propertiesRequiredByDefault) { + propertiesRequiredByDefaultTransform({ spec: context.spec }); + } + if (context.config.parser.transforms.readWrite.enabled) { readWriteTransform({ config: context.config.parser.transforms.readWrite, diff --git a/packages/openapi-ts/src/openApi/shared/transforms/propertiesRequiredByDefault.ts b/packages/openapi-ts/src/openApi/shared/transforms/propertiesRequiredByDefault.ts new file mode 100644 index 0000000000..55efd205e6 --- /dev/null +++ b/packages/openapi-ts/src/openApi/shared/transforms/propertiesRequiredByDefault.ts @@ -0,0 +1,100 @@ +import { childSchemaRelationships } from '../utils/schemaChildRelationships'; + +type NodeInfo = { + key: string | number | null; + node: unknown; + parent: unknown; + path: ReadonlyArray; +}; + +/** + * Recursively walk all schemas in the OpenAPI spec, visiting every object. + * Calls the visitor with node info for each. + * + * @param key - The key of the current node + * @param node - The current node + * @param parent - The parent node + * @param path - The path to the current node + * @param visitor - Function to call for each visited node + */ +const walkSchemas = ({ + key, + node, + parent, + path, + visitor, +}: NodeInfo & { + visitor: (nodeInfo: NodeInfo) => void; +}) => { + if (!node || typeof node !== 'object' || node instanceof Array) return; + + const value = node as Record; + + if ( + 'type' in value || + childSchemaRelationships.some(([keyword]) => keyword in value) + ) { + visitor({ key, node, parent, path }); + } + + for (const [k, v] of Object.entries(value)) { + if (typeof v === 'object' && v !== null) { + if (v instanceof Array) { + v.forEach((item, index) => + walkSchemas({ + key: index, + node: item, + parent: v, + path: [...path, k, index], + visitor, + }), + ); + } else { + walkSchemas({ + key: k, + node: v, + parent: node, + path: [...path, k], + visitor, + }); + } + } + } +}; + +/** + * Applies the properties required by default transform + * + * @param spec - The OpenAPI spec object to transform + */ +export const propertiesRequiredByDefaultTransform = ({ + spec, +}: { + spec: unknown; +}) => { + walkSchemas({ + key: null, + node: spec, + parent: null, + path: [], + visitor: (nodeInfo) => { + if ( + nodeInfo.node && + typeof nodeInfo.node === 'object' && + 'type' in nodeInfo.node && + nodeInfo.node.type === 'object' && + 'properties' in nodeInfo.node && + nodeInfo.node.properties && + typeof nodeInfo.node.properties === 'object' && + !('required' in nodeInfo.node) + ) { + const propKeys = Object.keys( + nodeInfo.node.properties as Record, + ); + if (propKeys.length > 0) { + (nodeInfo.node as Record).required = propKeys; + } + } + }, + }); +}; diff --git a/packages/openapi-ts/src/plugins/@hey-api/schemas/__tests__/schemas.test.ts b/packages/openapi-ts/src/plugins/@hey-api/schemas/__tests__/schemas.test.ts index deff71a745..c350ec0cfa 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/schemas/__tests__/schemas.test.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/schemas/__tests__/schemas.test.ts @@ -60,6 +60,7 @@ describe('generateLegacySchemas', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { @@ -217,6 +218,7 @@ describe('generateLegacySchemas', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { diff --git a/packages/openapi-ts/src/plugins/@hey-api/sdk/__tests__/plugin.test.ts b/packages/openapi-ts/src/plugins/@hey-api/sdk/__tests__/plugin.test.ts index 971228a2e4..33403626e6 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/sdk/__tests__/plugin.test.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/sdk/__tests__/plugin.test.ts @@ -62,6 +62,7 @@ describe('handlerLegacy', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { @@ -292,6 +293,7 @@ describe('methodNameBuilder', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { @@ -444,6 +446,7 @@ describe('methodNameBuilder', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { @@ -599,6 +602,7 @@ describe('methodNameBuilder', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { diff --git a/packages/openapi-ts/src/plugins/@hey-api/typescript/__tests__/plugin.test.ts b/packages/openapi-ts/src/plugins/@hey-api/typescript/__tests__/plugin.test.ts index a01dcea790..e4b0f1098f 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/typescript/__tests__/plugin.test.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/typescript/__tests__/plugin.test.ts @@ -60,6 +60,7 @@ describe('generateLegacyTypes', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { diff --git a/packages/openapi-ts/src/types/config.d.ts b/packages/openapi-ts/src/types/config.d.ts index ad1b4e2b4f..2654762562 100644 --- a/packages/openapi-ts/src/types/config.d.ts +++ b/packages/openapi-ts/src/types/config.d.ts @@ -3,7 +3,7 @@ import type { Plugin, PluginNames } from '../plugins/types'; import type { Input, Watch } from './input'; import type { Logs } from './logs'; import type { Output, UserOutput } from './output'; -import type { Parser, ResolvedParser } from './parser'; +import type { Parser, UserParser } from './parser'; export interface UserConfig { /** @@ -58,7 +58,7 @@ export interface UserConfig { * Customize how the input is parsed and transformed before it's passed to * plugins. */ - parser?: Parser; + parser?: UserParser; /** * Plugins generate artifacts from `input`. By default, we generate SDK * functions and TypeScript interfaces. If you manually define `plugins`, @@ -150,7 +150,7 @@ export type Config = Omit< * Customize how the input is parsed and transformed before it's passed to * plugins. */ - parser: ResolvedParser; + parser: Parser; pluginOrder: ReadonlyArray; plugins: { [K in PluginNames]?: Plugin.ConfigWithName; diff --git a/packages/openapi-ts/src/types/parser.d.ts b/packages/openapi-ts/src/types/parser.d.ts index 3c48187e3e..ad4d2e05f1 100644 --- a/packages/openapi-ts/src/types/parser.d.ts +++ b/packages/openapi-ts/src/types/parser.d.ts @@ -11,7 +11,7 @@ import type { StringCase, StringName } from './case'; type EnumsMode = 'inline' | 'root'; -export type Parser = { +export type UserParser = { /** * Filters can be used to select a subset of your input before it's passed * to plugins. @@ -93,6 +93,19 @@ export type Parser = { */ name?: StringName; }; + /** + * By default, any object schema with a missing `required` keyword is + * interpreted as "no properties are required." This is the correct + * behavior according to the OpenAPI standard. However, some specifications + * interpret a missing `required` keyword as "all properties should be + * required." + * + * This option allows you to change the default behavior so that + * properties are required by default unless explicitly marked as optional. + * + * @default false + */ + propertiesRequiredByDefault?: boolean; /** * Your schemas might contain read-only or write-only fields. Using such * schemas directly could mean asking the user to provide a read-only @@ -180,7 +193,7 @@ export type Parser = { validate_EXPERIMENTAL?: boolean | 'strict' | 'warn'; }; -export type ResolvedParser = { +export type Parser = { /** * Filters can be used to select a subset of your input before it's passed * to plugins. @@ -257,6 +270,19 @@ export type ResolvedParser = { */ name: StringName; }; + /** + * By default, any object schema with a missing `required` keyword is + * interpreted as "no properties are required." This is the correct + * behavior according to the OpenAPI standard. However, some specifications + * interpret a missing `required` keyword as "all properties should be + * required." + * + * This option allows you to change the default behavior so that + * properties are required by default unless explicitly marked as optional. + * + * @default false + */ + propertiesRequiredByDefault: boolean; /** * Your schemas might contain read-only or write-only fields. Using such * schemas directly could mean asking the user to provide a read-only diff --git a/packages/openapi-ts/src/utils/__tests__/handlebars.test.ts b/packages/openapi-ts/src/utils/__tests__/handlebars.test.ts index 2c683ed439..03c3b0fbc5 100644 --- a/packages/openapi-ts/src/utils/__tests__/handlebars.test.ts +++ b/packages/openapi-ts/src/utils/__tests__/handlebars.test.ts @@ -54,6 +54,7 @@ describe('registerHandlebarHelpers', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { @@ -179,6 +180,7 @@ describe('registerHandlebarTemplates', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: { diff --git a/packages/openapi-ts/src/utils/__tests__/parse.test.ts b/packages/openapi-ts/src/utils/__tests__/parse.test.ts index e0cec7036b..153d28cf9e 100644 --- a/packages/openapi-ts/src/utils/__tests__/parse.test.ts +++ b/packages/openapi-ts/src/utils/__tests__/parse.test.ts @@ -48,6 +48,7 @@ describe('operationNameFn', () => { mode: 'root', name: '', }, + propertiesRequiredByDefault: false, readWrite: { enabled: false, requests: {