import {z} from 'zod' export type GetApiV2SellerEventArgs = {createdAfter?: string | undefined, eventTypeFilter?: string | undefined, channel?: string | undefined}; export type GetApiV2SellerEventOptions = {baseUrl?: string | undefined, SellerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const channelEventTypeList = z.enum(["System:Test", "System:Notification", "Channel:ChannelDataChanged", "Channel:Notification", "Channel:Offer.ListingInProgress", "Channel:Offer.ListingSuccessful", "Channel:Offer.ListingFailed", "Channel:Order", "Channel:Order.StatusUpdate", "Channel:Order.AddressUpdate", "Channel:Order.Cancellation.Request", "Channel:Order.Cancellation.Accepted", "Channel:Order.Cancellation.Denied", "Channel:Order.Invoice", "Channel:Order.Return", "Channel:Order.ReturnProcessingResult", "Channel:Order.RefundProcessingResult", "Channel:Report.ProcessingFinished", "Channel:Report.DataComplete", "Channel:Report.Data", "Channel:MetaDataChanged", "Channel:Ticket"]); export const channel = z.string(); export const sellerId = z.string(); export const channelNotificationSeverity = z.enum(["INFO", "WARNING", "ERROR"]); export const channelNotificationReferenceType = z.enum(["OFFER", "CHANNELOFFER", "ORDERITEMID"]); export const offerId = z.number().int().gte(1); export const channelOfferId = z.string().min(1).max(100); export const offerListingFailedError = z.object({code: z.string().min(1).max(255), message: z.string().min(1).max(250), longMessage: z.string().min(1).max(10000).nullable().optional(), relatedAttributeId: z.string().min(1).max(512).nullable().optional(), recommendedValue: z.string().min(1).max(1000).nullable().optional()}); export const channelOrderStatus = z.enum(["UNACKED", "CREATED", "ACCEPTED", "SHIPPED", "PARTIALLY_SHIPPED", "CANCELED_BY_SELLER", "CANCELED_BY_BUYER"]); export const channelOrderId = z.string().min(1).max(150); export const orderItemId = z.string().min(1).max(50); export const orderItemStatus = z.enum(["UNSHIPPED", "SHIPPED", "CANCELED_BY_SELLER", "CANCELED_BY_BUYER", "RETURNED", "REFUNDED"]); export const orderItemPaymentStatus = z.enum(["PENDING", "PAID"]); export const sKU = z.string().min(1).max(150); export const additionalOrderDataGroupValues = z.object({key: z.string().min(1).max(255).optional(), value: z.string().min(1).max(5000).optional()}); export const additionalOrderDataGroup = z.object({group: z.string().min(1).max(150).optional(), values: z.array(additionalOrderDataGroupValues).optional()}); export const shippingGroup = z.string(); export const orderItem = z.union([z.object({orderItemId: orderItemId, type: z.string(), itemStatus: orderItemStatus.optional(), itemPaymentStatus: orderItemPaymentStatus.optional(), grossPrice: z.string(), total: z.string(), taxPercent: z.string().nullable().optional(), grossFee: z.string().nullable().optional(), offerId: offerId.optional(), channelOfferId: channelOfferId.optional(), sku: sKU.optional(), quantity: z.string().optional(), title: z.string().optional(), estimatedShippingDate: z.string().optional(), estimatedDeliveryDate: z.string().optional(), remainingQuantity: z.string().nullable().optional(), additionalOrderItemData: z.array(additionalOrderDataGroup).optional(), shipFromCountry: z.string().nullable().optional()}), z.object({orderItemId: orderItemId, type: z.string(), grossPrice: z.string(), taxPercent: z.string().nullable().optional(), shippingGroup: shippingGroup}), z.object({orderItemId: orderItemId, type: z.string(), grossPrice: z.string(), taxPercent: z.string().nullable().optional(), note: z.string()})]); export const address = z.object({firstName: z.string().optional(), lastName: z.string(), gender: z.enum(["male", "female", "diverse"]).optional(), companyName: z.string().optional(), street: z.string(), houseNumber: z.string().optional(), addition: z.string().optional(), postcode: z.string().optional(), city: z.string(), phone: z.string().optional(), country: z.string(), state: z.string().nullable().optional()}); export const orderBuyer = z.object({email: z.string().optional(), vatId: z.string().optional()}); export const reportId = z.string(); export const reportType = z.literal("SELLER_INVENTORY"); export const quantityPrice = z.object({amount: z.string(), currency: z.string(), quantity: z.string().nullable().optional()}); export const priceContainer = z.object({id: z.string(), quantityPriceList: z.array(quantityPrice)}); export const channelAttribute = z.object({attributeId: z.string(), value: z.string(), group: z.string().nullable().optional()}); export const sellerInventoryItem = z.object({offerId: offerId.optional(), channelOfferId: channelOfferId.optional(), sku: sKU.optional(), ean: z.string().optional(), quantity: z.string().optional(), priceList: z.array(priceContainer).optional(), title: z.string().optional(), channelCategoryId: z.string().optional(), channelAttributeList: z.array(channelAttribute).optional()}); export const reportSellerInventory = z.array(sellerInventoryItem); export const orderCancellationRequestId = z.string(); export const cancelReason = z.enum(["BUYER_CANCELLED", "UNDELIVERABLE_TO_SHIPPING_ADDRESS", "UNDELIVERABLE_BY_CARRIER", "OUT_OF_STOCK", "DELAYED_INVENTORY", "PRICING_ERROR", "OTHER"]); export const invoiceDocumentType = z.enum(["INVOICE", "CREDITNOTE"]); export const orderInvoiceTransactionItemDiscounts = z.object({name: z.string().nullable().optional(), discountId: z.string().nullable().optional(), totalGrossPrice: z.number().gte(0), totalNetPrice: z.number().gte(0), totalVatAmount: z.number().gte(0), vatRate: z.number().gte(0).optional()}); export const orderInvoiceTransactionItem = z.object({orderItemId: z.string(), orderItemType: z.enum(["ITEM", "SHIPPING", "PAYMENT"]), sku: z.string().optional(), title: z.string().optional(), quantity: z.number().gte(0).optional(), totalGrossPriceWithDiscounts: z.number().gte(0), totalNetPriceWithDiscounts: z.number().gte(0), totalVatAmountWithDiscounts: z.number().gte(0), vatRate: z.number().gte(0), discounts: z.array(orderInvoiceTransactionItemDiscounts).nullable().optional()}); export const orderInvoice = z.object({orderId: channelOrderId, purchasedAt: z.string(), shippingAddress: address.optional(), transactionItemList: z.array(orderInvoiceTransactionItem).optional()}); export const returnReason = z.enum(["NO_REASON", "DEFECT", "WRONG_ITEM", "WRONG_SIZE", "TOO_LATE", "BAD_QUALITY"]); export const returnAnnouncementOrderItem = z.object({orderItemId: orderItemId, quantity: z.string(), returnReason: returnReason, note: z.string().max(1024).optional()}); export const channelReturnId = z.string(); export const sellerReturnId = z.string(); export const returnProcessingError = z.object({code: z.string().optional(), message: z.string().min(1).max(1024)}); export const refundId = z.string().min(1).max(128); export const refundProcessingError = z.object({code: z.string().optional(), message: z.string().min(1).max(1024)}); export const ticketId = z.string().min(1).max(256); export const topic = z.enum(["QUESTION", "FEEDBACK", "DELIVERY", "RETURN", "REFUND", "INCIDENT"]); export const ticketReference = z.object({type: z.enum(["OFFER", "CHANNELOFFER", "ORDERID", "ORDERITEMID"]), id: z.string()}).nullable(); export const ticketFrom = z.object({role: z.enum(["BUYER", "SELLER", "CHANNEL"]), name: z.string().max(100).optional()}); export const ticketAttachment = z.object({filename: z.string().min(1).max(256), contentType: z.string().min(1).max(128)}); export const channelEventList = z.object({eventList: z.array(z.object({id: z.string(), createdAt: z.string(), type: channelEventTypeList, event: z.union([z.object({channel: channel, sellerId: sellerId, message: z.string(), severity: z.enum(["INFO", "WARNING", "ERROR"])}), z.object({channel: channel, sellerId: sellerId, severity: channelNotificationSeverity, message: z.string(), reference: z.object({type: channelNotificationReferenceType, id: z.string()}).nullable().optional()}), z.object({channel: channel, sellerId: sellerId, offerId: offerId, startedAt: z.string()}), z.object({channel: channel, sellerId: sellerId, offerId: offerId, channelOfferId: channelOfferId.nullable().optional(), listedAt: z.string(), listingUrl: z.string().nullable().optional()}), z.object({channel: channel, sellerId: sellerId, offerId: offerId, errorList: z.array(offerListingFailedError), failedAt: z.string()}), z.object({channel: channel, sellerId: sellerId, orderStatus: channelOrderStatus, orderAcceptUntil: z.string().optional(), paymentMethod: z.string().min(1).max(150).optional(), paymentReference: z.string().optional(), orderId: channelOrderId, purchasedAt: z.string(), lastChangedAt: z.string(), currency: z.string(), orderItem: z.array(orderItem), billingAddress: address.optional(), shippingAddress: address.optional(), note: z.string().optional(), buyer: orderBuyer.optional(), weeePickup: z.boolean().nullable().optional(), language: z.string().nullable().optional(), invoiceDocumentTransfer: z.enum(["not-set", "from-seller", "from-channel"]).nullable().optional(), additionalOrderData: z.array(additionalOrderDataGroup).optional(), fbc: z.boolean().nullable().optional(), b2b: z.boolean().nullable().optional(), salesChannelName: z.string().max(100).nullable().optional()}), z.object({channel: channel, sellerId: sellerId, orderId: channelOrderId, orderStatus: channelOrderStatus, orderItems: z.array(z.object({orderItemId: orderItemId, itemStatus: orderItemStatus, paymentStatus: orderItemPaymentStatus, shipFromCountry: z.string().nullable().optional()})).optional()}), z.object({channel: channel, sellerId: sellerId, orderId: channelOrderId, billingAddress: address.nullable().optional(), shippingAddress: address.nullable().optional(), buyer: orderBuyer.nullable().optional()}), z.object({channel: channel, sellerId: sellerId}), z.object({channel: channel, sellerId: sellerId.optional(), reportId: reportId.optional(), reportType: reportType.optional(), data: z.array(reportSellerInventory).optional(), checkSum: z.string().optional()}), z.object({channel: channel, sellerId: sellerId.optional(), reportId: reportId.optional(), reportType: reportType.optional(), receivedChecksumList: z.array(z.string()).optional()}), z.object({channel: channel, type: z.enum(["CATEGORY", "GLOBAL_ATTRIBUTES", "SELLER_ATTRIBUTES", "PRICE_TYPES", "SHIPPING_RULES", "PAYMENT_RULES"]).optional(), resource: z.string().optional()}), z.object({channel: channel, sellerId: sellerId, orderCancellationRequestId: orderCancellationRequestId}), z.object({channel: channel, sellerId: sellerId, orderCancellationRequestId: orderCancellationRequestId, reason: z.string().max(250)}), z.object({channel: channel, orderCancellationRequestId: orderCancellationRequestId, sellerId: sellerId, orderId: channelOrderId, orderItem: z.array(z.object({orderItemId: orderItemId, quantity: z.string().optional()})).nullable(), cancelReason: cancelReason.optional(), message: z.string().max(1024).optional()}), z.object({type: invoiceDocumentType, sellerId: sellerId, orderId: channelOrderId, invoiceNumber: z.string().min(1).max(256), originalInvoiceNumber: z.string().nullable().optional(), transactionDate: z.string(), taxCalculationDate: z.string(), transactionDetails: z.string().nullable().optional(), shipmentDate: z.string().optional(), taxAddressRole: z.enum(["shipFrom", "shipTo"]).optional(), exportOutsideEu: z.boolean().optional(), currency: z.string(), billingAddress: address, sellerVatNumber: z.string().nullable().optional(), buyerVatNumber: z.string().nullable().optional(), orderList: z.array(orderInvoice).optional(), channel: channel, documentId: z.string(), documentExpiresAt: z.string()}), z.object({channel: channel, sellerId: sellerId, orderId: channelOrderId, orderItem: z.array(returnAnnouncementOrderItem).optional(), channelReturnId: channelReturnId, returnTracking: z.object({carrier: z.string(), trackingNumber: z.string()}).optional()}), z.object({channel: channel, sellerId: sellerId, sellerReturnId: sellerReturnId, isAccepted: z.boolean(), processingErrorList: z.array(returnProcessingError).optional()}), z.object({channel: channel, refundId: refundId, sellerId: sellerId, isAccepted: z.boolean(), processingErrorList: z.array(refundProcessingError).optional()}), z.object({channel: channel, sellerId: sellerId, ticketId: ticketId, topic: topic, reference: ticketReference.optional(), replyRequested: z.boolean().optional(), createdAt: z.string(), from: ticketFrom, subject: z.string().min(1).max(1024), message: z.string().min(1).max(1024), attachment: z.array(ticketAttachment).optional()}), z.object({channel: channel})])})).optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Channel Events * * * GET /v2/seller/event */ export const getApiV2SellerEvent = async (args: GetApiV2SellerEventArgs, options?: GetApiV2SellerEventOptions) => { const {baseUrl = "https://scx-sbx.api.jtl-software.com", fetch: fetchFn = fetch, SellerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.createdAfter != null) query.append("createdAfter", String(args.createdAfter)) if (args.eventTypeFilter != null) query.append("eventTypeFilter", String(args.eventTypeFilter)) if (args.channel != null) query.append("channel", String(args.channel)) if (SellerAuth !== undefined) headers.set('authorization', `Bearer ${SellerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/v2/seller/event${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(channelEventList, await res.json()) };