@putiikkipalvelu/storefront-sdk 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -419,6 +419,10 @@ interface CartResponse {
419
419
  /** Cart ID for guest users (undefined for logged-in users) */
420
420
  cartId?: string;
421
421
  }
422
+ /**
423
+ * Reason why a discount code was removed during validation
424
+ */
425
+ type DiscountRemovalReason = "CAMPAIGN_ACTIVE" | "MIN_ORDER_NOT_MET" | "CODE_INVALID";
422
426
  /**
423
427
  * Changes detected during cart validation
424
428
  */
@@ -429,9 +433,16 @@ interface CartValidationChanges {
429
433
  quantityAdjusted: number;
430
434
  /** Number of items with changed price */
431
435
  priceChanged: number;
436
+ /** Whether discount code was removed */
437
+ discountCouponRemoved: boolean;
438
+ /** Reason why discount was removed (only present if discountCouponRemoved is true) */
439
+ discountRemovalReason?: DiscountRemovalReason;
432
440
  }
433
441
  /**
434
442
  * Response from GET /cart/validate
443
+ *
444
+ * Returns validated cart items and change metadata.
445
+ * No totals or discount data - those are calculated client-side or fetched separately.
435
446
  */
436
447
  interface CartValidationResponse {
437
448
  /** Validated cart items (with auto-fixed quantities/prices) */
@@ -724,7 +735,7 @@ interface Order {
724
735
  storeId: string;
725
736
  /** Order creation timestamp */
726
737
  createdAt: string;
727
- /** Total order amount in cents */
738
+ /** Total order amount in cents (subtotal before discount) */
728
739
  totalAmount: number;
729
740
  /** Current order status */
730
741
  status: OrderStatus;
@@ -736,6 +747,12 @@ interface Order {
736
747
  orderCustomerData: ConfirmationOrderCustomerData | null;
737
748
  /** Shipment method with tracking info */
738
749
  orderShipmentMethod: ConfirmationOrderShipmentMethod | null;
750
+ /** Discount code string (e.g., "SUMMER20") - null if no discount applied */
751
+ discountCodeValue: string | null;
752
+ /** Discount amount in cents - null if no discount applied */
753
+ discountAmount: number | null;
754
+ /** VAT rate used for the discount calculation */
755
+ discountVatRate: number | null;
739
756
  }
740
757
 
741
758
  /**
@@ -1232,6 +1249,104 @@ interface CheckoutErrorDetails {
1232
1249
  [key: string]: unknown;
1233
1250
  }
1234
1251
 
1252
+ /**
1253
+ * Discount Code Types
1254
+ *
1255
+ * Types for discount code API endpoints.
1256
+ */
1257
+ /**
1258
+ * Type of discount
1259
+ */
1260
+ type DiscountType = "PERCENTAGE" | "FIXED_AMOUNT";
1261
+ /**
1262
+ * Applied discount code information (stored in cart)
1263
+ */
1264
+ interface AppliedDiscount {
1265
+ /** The discount code string */
1266
+ code: string;
1267
+ /** Type of discount */
1268
+ discountType: DiscountType;
1269
+ /** Discount value (percentage 1-100 or cents for fixed amount) */
1270
+ discountValue: number;
1271
+ }
1272
+ /**
1273
+ * Parameters for applying a discount code
1274
+ */
1275
+ interface ApplyDiscountParams {
1276
+ /** The discount code to apply */
1277
+ code: string;
1278
+ /** Cart ID for guest users */
1279
+ cartId?: string;
1280
+ /** Session ID for logged-in users */
1281
+ sessionId?: string;
1282
+ /** Cart items for campaign conflict check (SDK uses this for instant validation) */
1283
+ cartItems?: CartItem[];
1284
+ /** Active campaigns for campaign conflict check (SDK uses this for instant validation) */
1285
+ campaigns?: Campaign[];
1286
+ }
1287
+ /**
1288
+ * Parameters for removing a discount code
1289
+ */
1290
+ interface RemoveDiscountParams {
1291
+ /** Cart ID for guest users */
1292
+ cartId?: string;
1293
+ /** Session ID for logged-in users */
1294
+ sessionId?: string;
1295
+ }
1296
+ /**
1297
+ * Parameters for getting current discount
1298
+ */
1299
+ interface GetDiscountParams {
1300
+ /** Cart ID for guest users */
1301
+ cartId?: string;
1302
+ /** Session ID for logged-in users */
1303
+ sessionId?: string;
1304
+ }
1305
+ /**
1306
+ * Response from POST /discount-code/apply
1307
+ *
1308
+ * Note: No discountAmount returned - cart can change before checkout.
1309
+ * Calculate locally or get from cart validate if needed.
1310
+ */
1311
+ interface ApplyDiscountResponse {
1312
+ /** Whether the discount was applied successfully */
1313
+ success: boolean;
1314
+ /** Applied discount details */
1315
+ discount: {
1316
+ code: string;
1317
+ discountType: DiscountType;
1318
+ discountValue: number;
1319
+ /** Minimum order amount for this code (in cents) - for UI display */
1320
+ minOrderAmount: number | null;
1321
+ };
1322
+ }
1323
+ /**
1324
+ * Response from GET /discount-code/apply (get current discount)
1325
+ *
1326
+ * Returns stored discount data without re-validation.
1327
+ * Use /cart/validate for full validation.
1328
+ */
1329
+ interface GetDiscountResponse {
1330
+ /** Current discount (null if none applied) */
1331
+ discount: AppliedDiscount | null;
1332
+ }
1333
+ /**
1334
+ * Response from DELETE /discount-code/apply
1335
+ */
1336
+ interface RemoveDiscountResponse {
1337
+ /** Whether the discount was removed successfully */
1338
+ success: boolean;
1339
+ }
1340
+ /**
1341
+ * Error response from discount code endpoints
1342
+ */
1343
+ interface DiscountCodeError {
1344
+ /** Error message (Finnish, user-friendly) */
1345
+ error: string;
1346
+ /** Error code for programmatic use */
1347
+ code: "MISSING_CODE" | "MISSING_CART_TOTAL" | "CART_MISSING" | "NOT_FOUND" | "INACTIVE" | "NOT_STARTED" | "EXPIRED" | "MAX_USES_REACHED" | "MIN_ORDER_NOT_MET" | "CAMPAIGN_ACTIVE" | "INTERNAL_ERROR";
1348
+ }
1349
+
1235
1350
  /**
1236
1351
  * Putiikkipalvelu Storefront SDK Types
1237
1352
  *
@@ -1658,28 +1773,35 @@ declare function createCartResource(fetcher: Fetcher): {
1658
1773
  * Checks product availability, stock levels, and prices.
1659
1774
  * Auto-fixes issues (removes unavailable items, adjusts quantities).
1660
1775
  *
1776
+ * Campaign conflict detection:
1777
+ * - SDK calculates if BuyXPayY campaigns apply using calculateCartWithCampaigns()
1778
+ * - Sends x-campaigns-apply header to backend
1779
+ * - If campaigns apply AND discount code exists, backend removes it
1780
+ * - Returns changes.discountCouponRemoved = true
1781
+ *
1661
1782
  * @param options - Cart session options
1783
+ * @param cartItems - Current cart items for campaign calculation
1784
+ * @param campaigns - Active campaigns for conflict check
1662
1785
  * @param fetchOptions - Fetch options
1663
1786
  * @returns Validated cart with change metadata
1664
1787
  *
1665
1788
  * @example Validate before checkout
1666
1789
  * ```typescript
1667
- * const { items, hasChanges, changes } = await client.cart.validate({ cartId });
1790
+ * const result = await client.cart.validate(
1791
+ * { cartId },
1792
+ * cartItems,
1793
+ * storeConfig.campaigns
1794
+ * );
1668
1795
  *
1669
- * if (hasChanges) {
1670
- * if (changes.removedItems > 0) {
1671
- * notify('Some items were removed (out of stock)');
1672
- * }
1673
- * if (changes.quantityAdjusted > 0) {
1674
- * notify('Some quantities were adjusted');
1675
- * }
1676
- * if (changes.priceChanged > 0) {
1677
- * notify('Some prices have changed');
1796
+ * if (result.hasChanges) {
1797
+ * if (result.changes.discountCouponRemoved) {
1798
+ * notify("Alennuskoodi poistettu - kampanja-alennus aktivoitui");
1678
1799
  * }
1800
+ * // Handle other changes...
1679
1801
  * }
1680
1802
  * ```
1681
1803
  */
1682
- validate(options?: CartSessionOptions, fetchOptions?: FetchOptions): Promise<CartValidationResponse>;
1804
+ validate(options?: CartSessionOptions, cartItems?: CartItem[], campaigns?: Campaign[], fetchOptions?: FetchOptions): Promise<CartValidationResponse>;
1683
1805
  };
1684
1806
  /**
1685
1807
  * Type for the cart resource
@@ -1700,6 +1822,8 @@ interface GetShippingOptionsParams extends FetchOptions {
1700
1822
  cartItems?: CartItem[];
1701
1823
  /** Active campaigns - used to calculate cart total with discounts for free shipping */
1702
1824
  campaigns?: Campaign[];
1825
+ /** Discount amount in cents (from discount code) - subtracted from cart total for free shipping threshold */
1826
+ discountAmount?: number;
1703
1827
  /** Country code (default: "FI") */
1704
1828
  country?: string;
1705
1829
  }
@@ -2303,6 +2427,70 @@ declare function createCheckoutResource(fetcher: Fetcher): {
2303
2427
  */
2304
2428
  type CheckoutResource = ReturnType<typeof createCheckoutResource>;
2305
2429
 
2430
+ /**
2431
+ * Discount Code Resource
2432
+ *
2433
+ * Provides methods for managing discount codes in the cart.
2434
+ */
2435
+
2436
+ /**
2437
+ * Creates the discount code resource with methods for managing discount codes.
2438
+ */
2439
+ declare function createDiscountCodeResource(fetcher: Fetcher): {
2440
+ /**
2441
+ * Apply a discount code to the cart
2442
+ *
2443
+ * Checks for BuyXPayY campaign conflict before calling API.
2444
+ * Discount codes cannot be used when a campaign discount is active.
2445
+ *
2446
+ * @param params - Parameters including code, session info, and cart/campaign data for conflict check
2447
+ * @returns Applied discount details
2448
+ * @throws {StorefrontError} With code "CAMPAIGN_ACTIVE" if a BuyXPayY campaign is active
2449
+ *
2450
+ * @example
2451
+ * ```typescript
2452
+ * const result = await client.discountCode.apply({
2453
+ * code: "SUMMER20",
2454
+ * cartId: cartId,
2455
+ * cartItems: cart.items,
2456
+ * campaigns: storeConfig.campaigns,
2457
+ * });
2458
+ * ```
2459
+ */
2460
+ apply(params: ApplyDiscountParams): Promise<ApplyDiscountResponse>;
2461
+ /**
2462
+ * Get the currently applied discount code
2463
+ *
2464
+ * @param params - Session info (cartId or sessionId)
2465
+ * @returns Current discount or null if none applied
2466
+ *
2467
+ * @example
2468
+ * ```typescript
2469
+ * const { discount } = await client.discountCode.get({ cartId });
2470
+ * if (discount) {
2471
+ * console.log(`Code ${discount.code}: ${discount.discountValue}${discount.discountType === 'PERCENTAGE' ? '%' : '¢'} off`);
2472
+ * }
2473
+ * ```
2474
+ */
2475
+ get(params?: GetDiscountParams): Promise<GetDiscountResponse>;
2476
+ /**
2477
+ * Remove the currently applied discount code
2478
+ *
2479
+ * @param params - Session info (cartId or sessionId)
2480
+ * @returns Success status
2481
+ *
2482
+ * @example
2483
+ * ```typescript
2484
+ * await client.discountCode.remove({ cartId });
2485
+ * ```
2486
+ */
2487
+ remove(params?: RemoveDiscountParams): Promise<RemoveDiscountResponse>;
2488
+ };
2489
+ /**
2490
+ * Type for the discount code resource
2491
+ */
2492
+ type DiscountCodeResource = ReturnType<typeof createDiscountCodeResource>;
2493
+
2306
2494
  /**
2307
2495
  * The Storefront API client
2308
2496
  */
@@ -2343,6 +2531,10 @@ interface StorefrontClient {
2343
2531
  * Checkout resource for payment processing
2344
2532
  */
2345
2533
  readonly checkout: CheckoutResource;
2534
+ /**
2535
+ * Discount code resource for applying/removing discount codes
2536
+ */
2537
+ readonly discountCode: DiscountCodeResource;
2346
2538
  }
2347
2539
  /**
2348
2540
  * Create a new Storefront API client
@@ -2427,6 +2619,126 @@ declare function getPriceInfo(product: ProductDetail, variation?: ProductVariati
2427
2619
  */
2428
2620
  declare function calculateCartWithCampaigns(items: CartItem[], campaigns: Campaign[]): CartCalculationResult;
2429
2621
 
2622
+ /**
2623
+ * Discount Code Utilities
2624
+ *
2625
+ * Helper functions for working with discount codes.
2626
+ */
2627
+
2628
+ /**
2629
+ * Options for formatting discount values
2630
+ */
2631
+ interface FormatDiscountOptions {
2632
+ /**
2633
+ * Currency symbol to use for fixed amount discounts
2634
+ * @default "€"
2635
+ */
2636
+ currencySymbol?: string;
2637
+ /**
2638
+ * Whether to show the currency symbol before or after the value
2639
+ * @default "after"
2640
+ */
2641
+ currencyPosition?: "before" | "after";
2642
+ /**
2643
+ * Number of decimal places for fixed amount
2644
+ * @default 2
2645
+ */
2646
+ decimals?: number;
2647
+ /**
2648
+ * Whether to include the minus sign prefix
2649
+ * @default true
2650
+ */
2651
+ showMinus?: boolean;
2652
+ }
2653
+ /**
2654
+ * Format a discount value for display.
2655
+ *
2656
+ * @param discount - The applied discount (or just type and value)
2657
+ * @param options - Formatting options
2658
+ * @returns Formatted discount string (e.g., "-20%" or "-5,00 €")
2659
+ *
2660
+ * @example
2661
+ * ```typescript
2662
+ * // Percentage discount
2663
+ * formatDiscountValue({ discountType: "PERCENTAGE", discountValue: 20 });
2664
+ * // Returns: "-20%"
2665
+ *
2666
+ * // Fixed amount discount (value in cents)
2667
+ * formatDiscountValue({ discountType: "FIXED_AMOUNT", discountValue: 500 });
2668
+ * // Returns: "-5,00 €"
2669
+ *
2670
+ * // Custom currency
2671
+ * formatDiscountValue(
2672
+ * { discountType: "FIXED_AMOUNT", discountValue: 1000 },
2673
+ * { currencySymbol: "$", currencyPosition: "before" }
2674
+ * );
2675
+ * // Returns: "-$10.00"
2676
+ * ```
2677
+ */
2678
+ declare function formatDiscountValue(discount: Pick<AppliedDiscount, "discountType" | "discountValue">, options?: FormatDiscountOptions): string;
2679
+ /**
2680
+ * Calculate the discount amount in cents.
2681
+ *
2682
+ * @param subtotal - Cart subtotal in cents (before discount)
2683
+ * @param discount - The applied discount
2684
+ * @returns Discount amount in cents (always positive)
2685
+ *
2686
+ * @example
2687
+ * ```typescript
2688
+ * // 20% off 100€ subtotal
2689
+ * calculateDiscountAmount(10000, { discountType: "PERCENTAGE", discountValue: 20 });
2690
+ * // Returns: 2000 (20€ in cents)
2691
+ *
2692
+ * // Fixed 5€ discount
2693
+ * calculateDiscountAmount(10000, { discountType: "FIXED_AMOUNT", discountValue: 500 });
2694
+ * // Returns: 500 (5€ in cents)
2695
+ *
2696
+ * // Fixed discount larger than subtotal (capped)
2697
+ * calculateDiscountAmount(300, { discountType: "FIXED_AMOUNT", discountValue: 500 });
2698
+ * // Returns: 300 (capped to subtotal)
2699
+ * ```
2700
+ */
2701
+ declare function calculateDiscountAmount(subtotal: number, discount: Pick<AppliedDiscount, "discountType" | "discountValue">): number;
2702
+ /**
2703
+ * Supported locales for error messages
2704
+ */
2705
+ type DiscountMessageLocale = "fi" | "en";
2706
+ /**
2707
+ * Get a user-friendly message for discount removal reason.
2708
+ *
2709
+ * @param reason - The removal reason from cart validation
2710
+ * @param locale - Locale for the message (fi or en)
2711
+ * @returns Localized user-friendly message
2712
+ *
2713
+ * @example
2714
+ * ```typescript
2715
+ * getDiscountRemovalMessage("CAMPAIGN_ACTIVE", "fi");
2716
+ * // Returns: "Alennuskoodi poistettu - kampanja-alennus aktivoitui"
2717
+ *
2718
+ * getDiscountRemovalMessage("MIN_ORDER_NOT_MET", "en");
2719
+ * // Returns: "Discount code removed - cart total below minimum order"
2720
+ * ```
2721
+ */
2722
+ declare function getDiscountRemovalMessage(reason: DiscountRemovalReason | undefined, locale?: DiscountMessageLocale): string;
2723
+ /**
2724
+ * Error codes from discount code apply endpoint
2725
+ */
2726
+ type DiscountApplyErrorCode = "NOT_FOUND" | "INACTIVE" | "NOT_STARTED" | "EXPIRED" | "MAX_USES_REACHED" | "MIN_ORDER_NOT_MET" | "CAMPAIGN_ACTIVE";
2727
+ /**
2728
+ * Get a user-friendly message for discount apply error.
2729
+ *
2730
+ * @param errorCode - The error code from apply endpoint
2731
+ * @param locale - Locale for the message (fi or en)
2732
+ * @returns Localized user-friendly message
2733
+ *
2734
+ * @example
2735
+ * ```typescript
2736
+ * getDiscountApplyErrorMessage("EXPIRED", "fi");
2737
+ * // Returns: "Alennuskoodi on vanhentunut"
2738
+ * ```
2739
+ */
2740
+ declare function getDiscountApplyErrorMessage(errorCode: DiscountApplyErrorCode | string | undefined, locale?: DiscountMessageLocale): string;
2741
+
2430
2742
  /**
2431
2743
  * Base error class for all Storefront API errors
2432
2744
  */
@@ -2470,4 +2782,4 @@ declare class VerificationRequiredError extends StorefrontError {
2470
2782
  constructor(message: string, customerId: string);
2471
2783
  }
2472
2784
 
2473
- export { type AddToCartParams, type AddToWishlistResponse, AuthError, type BuyXPayYCampaign, type CalculatedCartItem, type Campaign, type CampaignType, type CartCalculationResult, type CartItem, type CartResponse, type CartSessionOptions, type CartValidationChanges, type CartValidationResponse, type Category, type CategoryReference, type CategoryResponse, type CheckoutCustomerData, type CheckoutErrorCode, type CheckoutErrorDetails, type CheckoutOptions, type CheckoutParams, type CheckoutShipmentMethod, type ConfirmationItemType, type ConfirmationOrderCustomerData, type ConfirmationOrderLineItem, type ConfirmationOrderShipmentMethod, type Customer, type CustomerOrder, type DeleteAccountResponse, type FeatureFlags, type FetchOptions, type ForgotPasswordResponse, type GetOrdersResponse, type GetUserResponse, type HomeDeliveryOption, type LoginOptions, type LoginResponse, type LoginVerificationRequiredResponse, type LogoutResponse, NotFoundError, type OpeningHours, type Order, type OrderLineItem, type OrderProductInfo, type OrderShipmentMethod, type OrderStatus, type PaymentConfig, type PaytrailCheckoutResponse, type PaytrailGroup, type PaytrailProvider, type PickupPointOption, type PriceInfo, type Product, type ProductCountResponse, type ProductDetail, type ProductListParams, type ProductListResponse, type ProductSortOption, type ProductVariation, type ProductVariationListing, RateLimitError, type RegisterData, type RegisterResponse, type RemoveFromCartParams, type RemoveFromWishlistResponse, type ResendVerificationResponse, type ResetPasswordResponse, type ShipitShippingMethod, type ShipmentMethod, type ShipmentMethodsResponse, type StoreConfig, type StoreInfo, type StoreSeo, type StorefrontClient, type StorefrontClientConfig, StorefrontError, type StripeCheckoutResponse, type UpdateCartQuantityParams, type UpdateProfileData, type UpdateProfileResponse, ValidationError, type VariationOption, VerificationRequiredError, type VerifyEmailResponse, type WishlistItem, type WishlistProduct, type WishlistResponse, type WishlistVariation, type WishlistVariationOption, calculateCartWithCampaigns, createStorefrontClient, getPriceInfo, isSaleActive };
2785
+ export { type AddToCartParams, type AddToWishlistResponse, type AppliedDiscount, type ApplyDiscountParams, type ApplyDiscountResponse, AuthError, type BuyXPayYCampaign, type CalculatedCartItem, type Campaign, type CampaignType, type CartCalculationResult, type CartItem, type CartResponse, type CartSessionOptions, type CartValidationChanges, type CartValidationResponse, type Category, type CategoryReference, type CategoryResponse, type CheckoutCustomerData, type CheckoutErrorCode, type CheckoutErrorDetails, type CheckoutOptions, type CheckoutParams, type CheckoutShipmentMethod, type ConfirmationItemType, type ConfirmationOrderCustomerData, type ConfirmationOrderLineItem, type ConfirmationOrderShipmentMethod, type Customer, type CustomerOrder, type DeleteAccountResponse, type DiscountApplyErrorCode, type DiscountCodeError, type DiscountMessageLocale, type DiscountRemovalReason, type DiscountType, type FeatureFlags, type FetchOptions, type ForgotPasswordResponse, type FormatDiscountOptions, type GetDiscountParams, type GetDiscountResponse, type GetOrdersResponse, type GetUserResponse, type HomeDeliveryOption, type LoginOptions, type LoginResponse, type LoginVerificationRequiredResponse, type LogoutResponse, NotFoundError, type OpeningHours, type Order, type OrderLineItem, type OrderProductInfo, type OrderShipmentMethod, type OrderStatus, type PaymentConfig, type PaytrailCheckoutResponse, type PaytrailGroup, type PaytrailProvider, type PickupPointOption, type PriceInfo, type Product, type ProductCountResponse, type ProductDetail, type ProductListParams, type ProductListResponse, type ProductSortOption, type ProductVariation, type ProductVariationListing, RateLimitError, type RegisterData, type RegisterResponse, type RemoveDiscountParams, type RemoveDiscountResponse, type RemoveFromCartParams, type RemoveFromWishlistResponse, type ResendVerificationResponse, type ResetPasswordResponse, type ShipitShippingMethod, type ShipmentMethod, type ShipmentMethodsResponse, type StoreConfig, type StoreInfo, type StoreSeo, type StorefrontClient, type StorefrontClientConfig, StorefrontError, type StripeCheckoutResponse, type UpdateCartQuantityParams, type UpdateProfileData, type UpdateProfileResponse, ValidationError, type VariationOption, VerificationRequiredError, type VerifyEmailResponse, type WishlistItem, type WishlistProduct, type WishlistResponse, type WishlistVariation, type WishlistVariationOption, calculateCartWithCampaigns, calculateDiscountAmount, createStorefrontClient, formatDiscountValue, getDiscountApplyErrorMessage, getDiscountRemovalMessage, getPriceInfo, isSaleActive };