@sayren/store-sdk 0.10.0 → 0.11.0
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.mts +437 -4
- package/dist/index.mjs +562 -27
- package/package.json +1 -1
- package/src/client.ts +7 -0
- package/src/index.ts +1 -0
- package/src/schemas/claim.ts +24 -0
- package/src/schemas/order.ts +72 -4
- package/src/schemas/payment.ts +64 -0
- package/src/schemas/product.ts +42 -3
- package/src/schemas/shipping-policy.ts +375 -0
- package/src/schemas/store.ts +10 -0
package/dist/index.mjs
CHANGED
|
@@ -722,6 +722,21 @@ const claimReasonSchema = z.enum([
|
|
|
722
722
|
"DIFFERENT_FROM_PAGE",
|
|
723
723
|
"DELAY"
|
|
724
724
|
]);
|
|
725
|
+
/**
|
|
726
|
+
* 반품지 (이슈 #30) — 반품·교환 수거가 안내하는 주소다. 스토어 주소록의 기본 반품지이거나,
|
|
727
|
+
* 상품이 반품지를 따로 지정했으면 그 주소다.
|
|
728
|
+
*
|
|
729
|
+
* 취소 클레임은 보낼 물건이 없어 null이고, 반품지를 등록하지 않은 스토어도 null이다.
|
|
730
|
+
* 구매자가 직접 보내는 수거(`BUYER_SEND`)에 이 주소가 필요하다.
|
|
731
|
+
*/
|
|
732
|
+
const claimReturnAddressSchema = z.object({
|
|
733
|
+
name: z.string().describe("주소 이름(셀러가 붙인 별칭). 예: 본사 물류센터"),
|
|
734
|
+
contactName: z.string().describe("수취인 이름"),
|
|
735
|
+
phone: z.string().describe("연락처"),
|
|
736
|
+
zipCode: z.string(),
|
|
737
|
+
address1: z.string(),
|
|
738
|
+
address2: z.string().nullable()
|
|
739
|
+
});
|
|
725
740
|
const claimSchema = z.object({
|
|
726
741
|
claimId: z.string(),
|
|
727
742
|
type: claimTypeSchema,
|
|
@@ -750,7 +765,8 @@ const claimSchema = z.object({
|
|
|
750
765
|
/** 보류 중이면 자동 해제 시각(ISO 8601), 아니면 null */
|
|
751
766
|
holdExpiresAt: z.string().nullable(),
|
|
752
767
|
/** 보류를 이미 썼는지 — 보류는 클레임당 1회라 해제·만료 뒤에도 true */
|
|
753
|
-
holdUsed: z.boolean()
|
|
768
|
+
holdUsed: z.boolean(),
|
|
769
|
+
returnAddress: claimReturnAddressSchema.nullable().describe("수거 안내에 쓸 반품지(이슈 #30). 상품이 지정한 반품지, 없으면 스토어 기본 반품지다. 취소 클레임과 반품지를 등록하지 않은 스토어는 null")
|
|
754
770
|
});
|
|
755
771
|
/** `GET /v1/claims` 쿼리 — OpenAPI 문서용 형태(값은 쿼리 문자열) */
|
|
756
772
|
const claimListQuerySchema = z.object({
|
|
@@ -1488,6 +1504,42 @@ const paymentRecordStatusSchema = z.enum([
|
|
|
1488
1504
|
"FAILED"
|
|
1489
1505
|
]);
|
|
1490
1506
|
const paymentAttemptStatusSchema = z.string().describe("시도 상태 — ready·approving·approved·unknown·declined·prepare_failed·canceled·failed·abandoned·voided. 새 값이 추가될 수 있으니 모르는 값은 '진행 중이 아닌 시도'로 다룬다");
|
|
1507
|
+
/**
|
|
1508
|
+
* 현금영수증 상태 — 값이 추가될 수 있어 응답은 문자열로 받는다. 화면 분기는 이 목록으로 하고 모르는 값은 처리 중으로 다룬다.
|
|
1509
|
+
* - `REQUESTED`: 구매자가 신청했고 결제 승인 전이다
|
|
1510
|
+
* - `PENDING`: 발급·취소를 기다린다(승인 직후, 또는 일시 오류로 자동 재시도 대기)
|
|
1511
|
+
* - `ISSUED`: 발급됐다. 부분 환불이 있었으면 그만큼 취소(또는 재발급)된 금액이다
|
|
1512
|
+
* - `CANCELED`: 전액 환불로 취소됐다
|
|
1513
|
+
* - `FAILED`: 발급·취소가 실패했고 자동 재시도가 끝났다. `failCode`·`failMessage`를 보고 재발급한다
|
|
1514
|
+
* - `SKIPPED`: 발급 대상이 아니다(승인된 결제수단이 계좌이체·가상계좌가 아님)
|
|
1515
|
+
*/
|
|
1516
|
+
const CASH_RECEIPT_STATUS_VALUES = [
|
|
1517
|
+
"REQUESTED",
|
|
1518
|
+
"PENDING",
|
|
1519
|
+
"ISSUED",
|
|
1520
|
+
"CANCELED",
|
|
1521
|
+
"FAILED",
|
|
1522
|
+
"SKIPPED"
|
|
1523
|
+
];
|
|
1524
|
+
const cashReceiptSchema = z.object({
|
|
1525
|
+
cashReceiptId: z.string(),
|
|
1526
|
+
status: z.string().describe("상태. `REQUESTED` 결제 전 · `PENDING` 발급 대기 · `ISSUED` 발급 · `CANCELED` 취소 · `FAILED` 실패 · `SKIPPED` 발급 대상 아님. 값이 추가될 수 있다"),
|
|
1527
|
+
type: z.string().describe("용도. `INCOME_DEDUCTION` 소득공제 · `EXPENSE_PROOF` 지출증빙"),
|
|
1528
|
+
identityType: z.string().describe("식별 번호 종류. `PHONE` 휴대폰 · `CARD` 현금영수증카드 · `BUSINESS` 사업자등록번호"),
|
|
1529
|
+
identityNumberMasked: z.string().describe("가린 식별 번호 (예: 010****5678). 원문은 조회할 수 없다"),
|
|
1530
|
+
amount: z.number().int().describe("발급해야 할 금액 = 결제 금액 − 환불 완료 금액. 승인 전에는 결제 금액"),
|
|
1531
|
+
issuedAmount: z.number().int().describe("PG에 현재 발급돼 있는 금액. 취소됐거나 발급 전이면 0"),
|
|
1532
|
+
provider: pgProviderSchema.nullable().describe("발급 PG — 결제를 승인한 PG. 승인 전에는 null"),
|
|
1533
|
+
issueNumber: z.string().nullable().describe("현금영수증 승인 번호"),
|
|
1534
|
+
receiptUrl: z.string().nullable().describe("현금영수증 확인 주소"),
|
|
1535
|
+
issuedAt: z.string().nullable().describe("최근 발급 시각 (ISO 8601)"),
|
|
1536
|
+
canceledAt: z.string().nullable().describe("최근 취소 시각 (ISO 8601)"),
|
|
1537
|
+
failCode: z.string().nullable().describe("마지막 실패 코드. 성공하면 비운다"),
|
|
1538
|
+
failMessage: z.string().nullable().describe("마지막 실패 사유"),
|
|
1539
|
+
reissuable: z.boolean().describe("콘솔 재발급으로 다시 시도할 수 있는가 (`FAILED`·`PENDING`)"),
|
|
1540
|
+
requestedAt: z.string().describe("신청 시각 (ISO 8601)"),
|
|
1541
|
+
updatedAt: z.string().describe("마지막 변경 시각 (ISO 8601)")
|
|
1542
|
+
});
|
|
1491
1543
|
const paymentRecordSchema = z.object({
|
|
1492
1544
|
paymentId: z.string().describe("결제 건 id. 상세 조회 키"),
|
|
1493
1545
|
orderId: z.string().nullable().describe("승인돼 만들어진 주문. 승인 전에 끝난 결제는 null"),
|
|
@@ -1507,7 +1559,8 @@ const paymentRecordSchema = z.object({
|
|
|
1507
1559
|
failCode: z.string().nullable().describe("실패 코드. 실패로 끝난 결제만"),
|
|
1508
1560
|
failMessage: z.string().nullable().describe("실패 사유"),
|
|
1509
1561
|
paidAt: z.string().nullable().describe("승인 시각 (ISO 8601)"),
|
|
1510
|
-
createdAt: z.string().describe("결제 시작 시각 (ISO 8601)")
|
|
1562
|
+
createdAt: z.string().describe("결제 시작 시각 (ISO 8601)"),
|
|
1563
|
+
cashReceiptStatus: z.string().nullable().optional().default(null).describe("현금영수증 상태(`cashReceiptSchema.status`와 같은 값). 신청이 없으면 null. 서버는 항상 싣는다")
|
|
1511
1564
|
});
|
|
1512
1565
|
const paymentRecordPageSchema = pageSchema(paymentRecordSchema);
|
|
1513
1566
|
const paymentAttemptRecordSchema = z.object({
|
|
@@ -1541,7 +1594,8 @@ const paymentRecordDetailSchema = paymentRecordSchema.extend({
|
|
|
1541
1594
|
refundableAmount: z.number().int().describe("환불 가능 잔액 = 승인 금액 - 환불 완료 금액"),
|
|
1542
1595
|
merchantId: z.string().nullable().describe("가맹점 식별자 지문 (토스 clientKey, 포트원 Store ID). 비밀 값은 없다"),
|
|
1543
1596
|
attempts: z.array(paymentAttemptRecordSchema).describe("시도 이력. 순번 오름차순"),
|
|
1544
|
-
refunds: z.array(paymentRefundRecordSchema).describe("환불 이력. 실패한 요청도 남는다")
|
|
1597
|
+
refunds: z.array(paymentRefundRecordSchema).describe("환불 이력. 실패한 요청도 남는다"),
|
|
1598
|
+
cashReceipt: cashReceiptSchema.nullable().optional().default(null).describe("현금영수증. 구매자가 신청하지 않았으면 null. 서버는 항상 싣는다")
|
|
1545
1599
|
});
|
|
1546
1600
|
/** `GET /v1/payments` 쿼리 — OpenAPI 문서용 형태(값은 쿼리 문자열) */
|
|
1547
1601
|
const paymentListQuerySchema = z.object({
|
|
@@ -1630,7 +1684,8 @@ const orderSchema = z.object({
|
|
|
1630
1684
|
deliveryFee: z.number().int(),
|
|
1631
1685
|
discountAmount: z.number().int(),
|
|
1632
1686
|
totalAmount: z.number().int(),
|
|
1633
|
-
paidAt: z.string().nullable()
|
|
1687
|
+
paidAt: z.string().nullable(),
|
|
1688
|
+
cashReceipt: cashReceiptSchema.nullable().optional().default(null).describe("현금영수증. 구매자가 계좌이체·가상계좌 결제에서 신청했을 때만 있고 그 밖에는 null. 서버는 항상 싣는다")
|
|
1634
1689
|
}),
|
|
1635
1690
|
testPayment: z.boolean().describe("테스트 결제(샌드박스 결제) 주문인가. true면 실제로 돈이 오가지 않았어요. 상품을 발송하지 않도록 주의하세요"),
|
|
1636
1691
|
items: z.array(orderItemSchema)
|
|
@@ -1677,7 +1732,14 @@ const dispatchRequestSchema = z.object({
|
|
|
1677
1732
|
deliveryMethod: deliveryMethodSchema,
|
|
1678
1733
|
carrierCode: z.string().optional(),
|
|
1679
1734
|
trackingNumber: z.string().optional(),
|
|
1680
|
-
|
|
1735
|
+
/**
|
|
1736
|
+
* 발송 시각. ISO 8601이고 시간대(`Z` 또는 `+09:00`)를 포함해야 한다. 생략하면 현재 시각이다.
|
|
1737
|
+
*
|
|
1738
|
+
* 전에는 `z.string()`이라 아무 문자열이나 그대로 저장됐다. 이 값은 배송 정보 jsonb에 들어가
|
|
1739
|
+
* 자동 배송완료·추적 동기화 잡의 대상 선별 조건이 된다 — 잘못된 한 행이 스토어 구분 없이 도는
|
|
1740
|
+
* 잡 전체를 멈출 수 있어 입력에서 좁혔다. 검증을 통과한 값도 저장 전에 UTC ISO로 정규화한다.
|
|
1741
|
+
*/
|
|
1742
|
+
dispatchedAt: z.iso.datetime({ offset: true }).optional()
|
|
1681
1743
|
}).refine((value) => value.deliveryMethod === "DIRECT" || value.deliveryMethod === "NOTHING" ? true : !!value.carrierCode && !!value.trackingNumber, { message: "COURIER/QUICK 발송은 carrierCode와 trackingNumber가 필수입니다" });
|
|
1682
1744
|
const deliveryInfoSchema = z.object({
|
|
1683
1745
|
orderItemId: z.string(),
|
|
@@ -1694,12 +1756,26 @@ const deliveryInfoSchema = z.object({
|
|
|
1694
1756
|
dispatchedAt: z.string(),
|
|
1695
1757
|
deliveredAt: z.string().nullable()
|
|
1696
1758
|
});
|
|
1759
|
+
/**
|
|
1760
|
+
* 택배 추적 단계. 응답에서는 문자열로 받는다(값이 추가될 수 있다) — 현재 값은 `ACCEPTED`(접수)·`IN_TRANSIT`(이동 중)·
|
|
1761
|
+
* `OUT_FOR_DELIVERY`(배송 출발)·`DELIVERED`(배송완료)다.
|
|
1762
|
+
*/
|
|
1763
|
+
const trackingStageResponseSchema = z.string();
|
|
1697
1764
|
/** `GET /v1/order-items/{orderItemId}/delivery` 응답 — 배송 정보 + 배송 추적 이벤트 */
|
|
1698
|
-
const deliveryStatusSchema = deliveryInfoSchema.extend({
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1765
|
+
const deliveryStatusSchema = deliveryInfoSchema.extend({
|
|
1766
|
+
trackingEvents: z.array(z.object({
|
|
1767
|
+
status: z.string().describe("택배사가 알려 준 처리 내용(예: 집화처리, 배송출발)"),
|
|
1768
|
+
location: z.string().describe("처리 장소. 모르면 빈 문자열"),
|
|
1769
|
+
occurredAt: z.string(),
|
|
1770
|
+
stage: trackingStageResponseSchema.nullable().optional().default(null).describe("이 이벤트의 추적 단계. 배달 실패처럼 단계로 나눌 수 없는 이벤트는 null. 서버는 항상 싣는다. 현재 값은 `ACCEPTED`·`IN_TRANSIT`·`OUT_FOR_DELIVERY`·`DELIVERED`이고 값이 추가될 수 있어 문자열로 받는다")
|
|
1771
|
+
})).optional().describe("배송 추적 이력. 시각 오름차순(오래된 것부터)"),
|
|
1772
|
+
tracking: z.object({
|
|
1773
|
+
result: z.string().nullable().describe("마지막 추적 조회 결과. 조회에 성공한 적이 없으면 null. 현재 값은 `FOUND`(조회됨)·`NOT_FOUND`(택배사 전산에 송장 없음)·`UNSUPPORTED_CARRIER`(추적을 지원하지 않는 택배사)이고 값이 추가될 수 있어 문자열로 받는다"),
|
|
1774
|
+
stage: trackingStageResponseSchema.nullable().describe("현재 추적 단계. 조회되지 않았으면 null. 현재 값은 `ACCEPTED`·`IN_TRANSIT`·`OUT_FOR_DELIVERY`·`DELIVERED`이고 값이 추가될 수 있어 문자열로 받는다"),
|
|
1775
|
+
checkedAt: z.string().nullable().describe("택배사에서 추적 정보를 마지막으로 받아 온 시각(ISO 8601)"),
|
|
1776
|
+
carrierDeliveredAt: z.string().nullable().describe("택배사가 알려 준 배송완료 시각(ISO 8601). 추적으로 배송완료가 반영되면 주문상품의 `deliveredAt`은 반영 시각이라 이 값과 다를 수 있다")
|
|
1777
|
+
}).nullable().optional().default(null).describe("택배 추적 요약. 택배 발송이 아니거나 추적을 쓰지 않으면 null. 추적이 배송완료면 주문상품이 자동으로 배송완료된다. 서버는 항상 싣는다")
|
|
1778
|
+
});
|
|
1703
1779
|
/** `PUT /v1/order-items/{orderItemId}/dispatch/tracking` 응답 — 바뀐 송장 */
|
|
1704
1780
|
const trackingUpdateResultSchema = z.object({
|
|
1705
1781
|
orderItemId: z.string(),
|
|
@@ -1774,7 +1850,7 @@ const addressChangeRequestListSchema = z.array(z.record(z.string(), z.unknown())
|
|
|
1774
1850
|
* 한 주문에 정책이 섞이면 **상품별로 계산한다**. 배송비 묶음도 상품 단위다(주문서·장바구니의
|
|
1775
1851
|
* 배송비 합산과 같은 규칙: 같은 상품의 주문상품이 한 묶음이고 묶음마다 배송비가 붙는다).
|
|
1776
1852
|
*/
|
|
1777
|
-
const descriptions = {
|
|
1853
|
+
const descriptions$1 = {
|
|
1778
1854
|
preShipmentDeliveryFeeRefund: "발송 전 취소로 배송 묶음(같은 상품의 주문상품)이 모두 취소되면 그 묶음의 배송비를 환불한다. false면 배송비를 환불하지 않는다. 기본 true",
|
|
1779
1855
|
returnDeliveryFee: "단순 변심(구매자 귀책) 반품의 반품 배송비. 원 단위. 환불액에서 뺀다. 기본 0(무료). 상품별 정책에서 이 값을 주면 상품의 `returnFee`도 같은 값으로 맞춘다",
|
|
1780
1856
|
exchangeDeliveryFee: "단순 변심(구매자 귀책) 교환의 교환 배송비. 원 단위. 구매자에게 청구할 금액을 안내값으로 싣는다. 기본 0(무료). 상품별 정책에서 이 값을 주면 상품의 `exchangeFee`도 같은 값으로 맞춘다",
|
|
@@ -1783,11 +1859,11 @@ const descriptions = {
|
|
|
1783
1859
|
};
|
|
1784
1860
|
/** 유효 환불 정책 — 스토어 기본 + 상품별 덮어쓰기를 합친 결과 */
|
|
1785
1861
|
const refundPolicySchema = z.object({
|
|
1786
|
-
preShipmentDeliveryFeeRefund: z.boolean().describe(descriptions.preShipmentDeliveryFeeRefund),
|
|
1787
|
-
returnDeliveryFee: z.number().int().min(0).describe(descriptions.returnDeliveryFee),
|
|
1788
|
-
exchangeDeliveryFee: z.number().int().min(0).describe(descriptions.exchangeDeliveryFee),
|
|
1789
|
-
sellerFaultFreeShipping: z.boolean().describe(descriptions.sellerFaultFreeShipping),
|
|
1790
|
-
conditionalFreeShortfallCharge: z.boolean().describe(descriptions.conditionalFreeShortfallCharge)
|
|
1862
|
+
preShipmentDeliveryFeeRefund: z.boolean().describe(descriptions$1.preShipmentDeliveryFeeRefund),
|
|
1863
|
+
returnDeliveryFee: z.number().int().min(0).describe(descriptions$1.returnDeliveryFee),
|
|
1864
|
+
exchangeDeliveryFee: z.number().int().min(0).describe(descriptions$1.exchangeDeliveryFee),
|
|
1865
|
+
sellerFaultFreeShipping: z.boolean().describe(descriptions$1.sellerFaultFreeShipping),
|
|
1866
|
+
conditionalFreeShortfallCharge: z.boolean().describe(descriptions$1.conditionalFreeShortfallCharge)
|
|
1791
1867
|
});
|
|
1792
1868
|
/**
|
|
1793
1869
|
* 스토어가 정하지 않았을 때 서버가 쓰는 값.
|
|
@@ -1809,11 +1885,11 @@ const REFUND_POLICY_DEFAULTS = {
|
|
|
1809
1885
|
* 믿는데 정책은 기본값으로 남는다.
|
|
1810
1886
|
*/
|
|
1811
1887
|
const refundPolicyPatchSchema = z.strictObject({
|
|
1812
|
-
preShipmentDeliveryFeeRefund: z.boolean().optional().describe(descriptions.preShipmentDeliveryFeeRefund),
|
|
1813
|
-
returnDeliveryFee: z.number().int().min(0).optional().describe(descriptions.returnDeliveryFee),
|
|
1814
|
-
exchangeDeliveryFee: z.number().int().min(0).optional().describe(descriptions.exchangeDeliveryFee),
|
|
1815
|
-
sellerFaultFreeShipping: z.boolean().optional().describe(descriptions.sellerFaultFreeShipping),
|
|
1816
|
-
conditionalFreeShortfallCharge: z.boolean().optional().describe(descriptions.conditionalFreeShortfallCharge)
|
|
1888
|
+
preShipmentDeliveryFeeRefund: z.boolean().optional().describe(descriptions$1.preShipmentDeliveryFeeRefund),
|
|
1889
|
+
returnDeliveryFee: z.number().int().min(0).optional().describe(descriptions$1.returnDeliveryFee),
|
|
1890
|
+
exchangeDeliveryFee: z.number().int().min(0).optional().describe(descriptions$1.exchangeDeliveryFee),
|
|
1891
|
+
sellerFaultFreeShipping: z.boolean().optional().describe(descriptions$1.sellerFaultFreeShipping),
|
|
1892
|
+
conditionalFreeShortfallCharge: z.boolean().optional().describe(descriptions$1.conditionalFreeShortfallCharge)
|
|
1817
1893
|
});
|
|
1818
1894
|
/**
|
|
1819
1895
|
* 유효 정책 해석 — 상품별 덮어쓰기 → 스토어 기본 → `REFUND_POLICY_DEFAULTS` 순이다.
|
|
@@ -2161,6 +2237,21 @@ const variantStockSchema = z.object({
|
|
|
2161
2237
|
variantId: z.string(),
|
|
2162
2238
|
stockQuantity: z.number().int()
|
|
2163
2239
|
});
|
|
2240
|
+
/**
|
|
2241
|
+
* 출고지·반품지 지정 문구 — POST·PUT·PATCH가 같은 규칙을 쓰므로 설명도 한 곳이다 (이슈 #30).
|
|
2242
|
+
*
|
|
2243
|
+
* 세 값이 뜻이 다르다. **생략**은 「정하지 않음」이라 서버가 그 시점 스토어 기본 주소를 박아 저장하고,
|
|
2244
|
+
* **null**은 「스토어 기본을 따른다」는 명시적 비우기다. 주소록 항목은 상품이 참조 중이면 지울 수 없어
|
|
2245
|
+
* (`409 ADDRESS_IN_USE`) 참조를 푸는 수단이 필요한데, 생략을 기본값으로 되채우면 기본 주소는 영원히
|
|
2246
|
+
* 풀리지 않는다 — null이 그 경로다. 배송 묶음 판정은 null을 그 시점 스토어 기본 출고지로 정규화하므로
|
|
2247
|
+
* 두 표현이 배송비를 갈라놓지 않는다.
|
|
2248
|
+
*/
|
|
2249
|
+
const ADDRESS_DESCRIPTIONS = {
|
|
2250
|
+
shipping: "출고지 주소 id(`GET /v1/seller-addresses?type=SHIPPING`). 생략하면 스토어 기본 출고지를 저장하고, `null`이면 비워 둔다(스토어 기본 출고지를 따른다). 이 스토어의 `SHIPPING` 주소가 아니면 거부한다",
|
|
2251
|
+
return: "반품지 주소 id(`GET /v1/seller-addresses?type=RETURN`). 생략하면 스토어 기본 반품지를 저장하고, `null`이면 비워 둔다(스토어 기본 반품지를 따른다). 이 스토어의 `RETURN` 주소가 아니면 거부한다",
|
|
2252
|
+
patchShipping: "출고지 주소 id. **생략은 바꾸지 않음**이고 `null`은 비우기다(스토어 기본 출고지를 따른다). 이 스토어의 `SHIPPING` 주소가 아니면 거부한다",
|
|
2253
|
+
patchReturn: "반품지 주소 id. **생략은 바꾸지 않음**이고 `null`은 비우기다(스토어 기본 반품지를 따른다). 이 스토어의 `RETURN` 주소가 아니면 거부한다"
|
|
2254
|
+
};
|
|
2164
2255
|
const productCreateRequestSchema = z.object({
|
|
2165
2256
|
name: z.string().min(1).max(100),
|
|
2166
2257
|
categoryId: z.string().min(1, "카테고리를 선택해주세요"),
|
|
@@ -2178,19 +2269,21 @@ const productCreateRequestSchema = z.object({
|
|
|
2178
2269
|
value: z.string()
|
|
2179
2270
|
})).optional(),
|
|
2180
2271
|
deliveryType: deliveryTypeSchema.default("PAID").describe("배송비 유형. FREE 무료, PAID 유료, CONDITIONAL_FREE 조건부 무료"),
|
|
2181
|
-
deliveryFee: z.number().int().
|
|
2272
|
+
deliveryFee: z.number().int().min(0).optional().describe("배송비. 원 단위. **생략하면 스토어 기본 배송비**(`GET /v1/store`의 `shippingPolicy.baseDeliveryFee`)를 쓴다. `deliveryType`이 FREE면 0으로 저장한다"),
|
|
2182
2273
|
conditionalFreeAmount: z.number().int().optional().describe("CONDITIONAL_FREE일 때 무료 배송이 되는 주문 금액. 원 단위"),
|
|
2183
2274
|
returnFee: z.number().int().default(0).describe("반품 배송비. 원 단위. `refundPolicy.returnDeliveryFee`와 같은 값이다"),
|
|
2184
2275
|
exchangeFee: z.number().int().default(0).describe("교환 배송비. 원 단위. `refundPolicy.exchangeDeliveryFee`와 같은 값이다"),
|
|
2185
2276
|
refundPolicy: refundPolicyPatchSchema.nullish().describe("상품별 환불 정책 — 준 항목만 스토어 기본을 덮어쓴다. `null`이나 생략은 스토어 기본을 그대로 쓴다는 뜻이다. `returnDeliveryFee`·`exchangeDeliveryFee`를 주면 `returnFee`·`exchangeFee`도 같은 값으로 맞춘다"),
|
|
2186
|
-
shippingAddressId: z.string().optional(),
|
|
2187
|
-
returnAddressId: z.string().optional()
|
|
2277
|
+
shippingAddressId: z.string().nullable().optional().describe(ADDRESS_DESCRIPTIONS.shipping),
|
|
2278
|
+
returnAddressId: z.string().nullable().optional().describe(ADDRESS_DESCRIPTIONS.return)
|
|
2188
2279
|
}).extend(optionModelRequestSchema.shape);
|
|
2189
2280
|
const productPatchRequestSchema = z.object({
|
|
2190
2281
|
name: z.string().max(100).optional(),
|
|
2191
2282
|
salePrice: z.number().int().multipleOf(10).optional(),
|
|
2192
2283
|
status: productStatusSchema.optional(),
|
|
2193
|
-
deliveryFee: z.number().int().optional()
|
|
2284
|
+
deliveryFee: z.number().int().optional(),
|
|
2285
|
+
shippingAddressId: z.string().nullable().optional().describe(ADDRESS_DESCRIPTIONS.patchShipping),
|
|
2286
|
+
returnAddressId: z.string().nullable().optional().describe(ADDRESS_DESCRIPTIONS.patchReturn)
|
|
2194
2287
|
}).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
|
|
2195
2288
|
const productSortSchema = z.enum([
|
|
2196
2289
|
"createdAt.desc",
|
|
@@ -2223,6 +2316,441 @@ const discountRequestSchema = z.object({
|
|
|
2223
2316
|
endAt: z.string().optional()
|
|
2224
2317
|
});
|
|
2225
2318
|
//#endregion
|
|
2319
|
+
//#region src/schemas/shipping-policy.ts
|
|
2320
|
+
/**
|
|
2321
|
+
* 배송비 규칙 (이슈 #29) — 배송비를 **몇 번, 얼마나** 부과하는지를 정한다.
|
|
2322
|
+
*
|
|
2323
|
+
* 세 축이다.
|
|
2324
|
+
* 1. **배송 묶음**: 같은 출고지 + 같은 배송 정책인 주문상품은 한 묶음이고 배송비가 한 번만 붙는다
|
|
2325
|
+
* (`deliveryBundleKeyOf`). 이슈 #25의 「묶음 = 같은 상품」 규칙을 일반화한 것이다 — 키를 상품 id에서
|
|
2326
|
+
* 정책 지문으로 바꿨고, 주문상품이 주문 시점 키를 스냅샷해(`order_items.delivery_bundle_key`)
|
|
2327
|
+
* 환불 정산(`refund-settlement.ts`)과 주문 스냅샷(`orders.delivery_fee_settlements`)이 같은 키를 쓴다.
|
|
2328
|
+
* 2. **무료 기준**: 상품별 조건부 무료(`CONDITIONAL_FREE`, 묶음 소계 기준)와 스토어 전체 무료 기준
|
|
2329
|
+
* (`freeThreshold`, 주문 상품 금액 합 기준)이 있다. 둘 중 하나라도 충족하면 그 배송비는 0이다.
|
|
2330
|
+
* 3. **지역 추가 배송비**: 우편번호가 제주·도서산간이면 **묶음마다** 추가된다. 묶음이 곧 한 번의 발송이라
|
|
2331
|
+
* 두 출고지에서 각각 보내면 추가 운임도 두 번 든다.
|
|
2332
|
+
*
|
|
2333
|
+
* 지역 추가 배송비는 **무료배송과 무관하게 부과한다.** 무료 기준은 셀러가 기본 운임을 부담하겠다는
|
|
2334
|
+
* 뜻이지, 도서 지역 추가 운임까지 부담하겠다는 뜻은 아니다(국내 택배사 공통 관행).
|
|
2335
|
+
*
|
|
2336
|
+
* 계산은 `quoteDelivery` 하나다. 장바구니·주문서·결제 시작·환불 정산이 모두 이 함수를 쓴다 —
|
|
2337
|
+
* 네 곳이 각자 계산하면 화면 금액과 결제 금액이 갈라진다.
|
|
2338
|
+
*/
|
|
2339
|
+
const descriptions = {
|
|
2340
|
+
baseDeliveryFee: "스토어 기본 배송비. 원 단위. 상품 등록·수정에서 `deliveryFee`를 생략하면 이 값을 쓴다. 기본 3000",
|
|
2341
|
+
freeThreshold: "스토어 전체 무료배송 기준액. 주문 상품 금액 합이 이 값 이상이면 모든 묶음의 배송비가 0이다. null이면 전체 무료배송을 쓰지 않는다(상품별 조건부 무료는 그대로 동작한다). 기본 null",
|
|
2342
|
+
jejuSurcharge: "제주 지역 추가 배송비. 원 단위. **배송 묶음마다** 더한다. 기본 0",
|
|
2343
|
+
isolatedSurcharge: "도서산간 지역 추가 배송비. 원 단위. **배송 묶음마다** 더한다. 기본 0"
|
|
2344
|
+
};
|
|
2345
|
+
/** 유효 배송비 정책 — 스토어가 정하지 않은 항목은 `SHIPPING_POLICY_DEFAULTS`로 채운 값이다 */
|
|
2346
|
+
const shippingPolicySchema = z.object({
|
|
2347
|
+
baseDeliveryFee: z.number().int().min(0).describe(descriptions.baseDeliveryFee),
|
|
2348
|
+
freeThreshold: z.number().int().min(1).nullable().describe(descriptions.freeThreshold),
|
|
2349
|
+
jejuSurcharge: z.number().int().min(0).describe(descriptions.jejuSurcharge),
|
|
2350
|
+
isolatedSurcharge: z.number().int().min(0).describe(descriptions.isolatedSurcharge)
|
|
2351
|
+
});
|
|
2352
|
+
/**
|
|
2353
|
+
* 스토어가 정하지 않았을 때 서버가 쓰는 값.
|
|
2354
|
+
*
|
|
2355
|
+
* `as const`가 아니라 `ShippingPolicy`로 좁힌다 — 리터럴 타입이면 `Partial<typeof …>`로 일부만 바꿀 때
|
|
2356
|
+
* `null` 자리에 숫자를 넣을 수 없다(`REFUND_POLICY_DEFAULTS`와 같은 이유).
|
|
2357
|
+
*/
|
|
2358
|
+
const SHIPPING_POLICY_DEFAULTS = {
|
|
2359
|
+
baseDeliveryFee: 3e3,
|
|
2360
|
+
freeThreshold: null,
|
|
2361
|
+
jejuSurcharge: 0,
|
|
2362
|
+
isolatedSurcharge: 0
|
|
2363
|
+
};
|
|
2364
|
+
/**
|
|
2365
|
+
* 부분 정책 — `PATCH /v1/store`의 `shippingPolicy`가 쓴다. 준 항목만 바뀐다.
|
|
2366
|
+
*
|
|
2367
|
+
* `strictObject`라 모르는 키는 400이다. 오타를 조용히 무시하면 셀러는 저장됐다고 믿는데
|
|
2368
|
+
* 정책은 기본값으로 남는다(`refundPolicyPatchSchema`와 같은 이유).
|
|
2369
|
+
*/
|
|
2370
|
+
const shippingPolicyPatchSchema = z.strictObject({
|
|
2371
|
+
baseDeliveryFee: z.number().int().min(0).optional().describe(descriptions.baseDeliveryFee),
|
|
2372
|
+
freeThreshold: z.number().int().min(1).nullable().optional().describe(descriptions.freeThreshold),
|
|
2373
|
+
jejuSurcharge: z.number().int().min(0).optional().describe(descriptions.jejuSurcharge),
|
|
2374
|
+
isolatedSurcharge: z.number().int().min(0).optional().describe(descriptions.isolatedSurcharge)
|
|
2375
|
+
});
|
|
2376
|
+
/** 유효 정책 해석 — 스토어가 정한 항목 + `SHIPPING_POLICY_DEFAULTS` */
|
|
2377
|
+
function resolveShippingPolicy(patch) {
|
|
2378
|
+
if (!patch) return { ...SHIPPING_POLICY_DEFAULTS };
|
|
2379
|
+
const given = Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== void 0));
|
|
2380
|
+
return {
|
|
2381
|
+
...SHIPPING_POLICY_DEFAULTS,
|
|
2382
|
+
...given
|
|
2383
|
+
};
|
|
2384
|
+
}
|
|
2385
|
+
/** 지역 구분 — 우편번호로 판정한다 */
|
|
2386
|
+
const remoteAreaSchema = z.enum([
|
|
2387
|
+
"NONE",
|
|
2388
|
+
"JEJU",
|
|
2389
|
+
"ISOLATED"
|
|
2390
|
+
]);
|
|
2391
|
+
/**
|
|
2392
|
+
* 제주·도서산간 우편번호 범위 — **코드 상수다.** 금액은 스토어가 정하고 범위는 플랫폼이 고정한다.
|
|
2393
|
+
*
|
|
2394
|
+
* 국내 택배사가 공표하는 제주·도서산간 할증 구간을 5자리 우편번호 범위로 옮긴 표다. 셀러마다
|
|
2395
|
+
* 범위가 다르면 같은 주소에 다른 금액이 나가고 CS가 셀러 수만큼 갈라진다. 스토어별 범위 편집은
|
|
2396
|
+
* 후속 과제이고, 지금은 이 표가 유일한 원천이다.
|
|
2397
|
+
*
|
|
2398
|
+
* ## 근거
|
|
2399
|
+
*
|
|
2400
|
+
* 원천은 **CJ대한통운이 공표한 「제주 및 도서산간 지역 추가 운송비」 표**(구간 시작·끝 우편번호와
|
|
2401
|
+
* 지역명이 붙은 그 표)다. 같은 표가 한진택배 공지와 쇼핑몰 솔루션 안내에도 같은 값으로 실린다.
|
|
2402
|
+
* 서로 다른 게시자의 전재본 네 곳이 인천·전남·경남 구간까지 글자 그대로 일치하는 것을 확인했다.
|
|
2403
|
+
*
|
|
2404
|
+
* - CJ대한통운 표 전재 (구간별 금액 포함): https://ichibanhouse.com/article/공지뉴스/1/16/
|
|
2405
|
+
* - 같은 표의 다른 전재본: https://peppytail.com/article/공지사항/1/4046/
|
|
2406
|
+
* - 시행 시점(2020-02-01)과 구간별 행정구역명을 함께 적은 전재본:
|
|
2407
|
+
* https://tosstoss.co.kr/bbs/content.php?co_id=pilotage
|
|
2408
|
+
* - 솔루션 안내 「제주도 및 도서산간 지역 기준표」:
|
|
2409
|
+
* https://help.campaignus.me/ko/articles/제주도-및-도서산간-지역-기준표-342d2e5e
|
|
2410
|
+
*
|
|
2411
|
+
* 라벨의 행정구역명은 우편번호 배정을 따로 확인해 고쳤다. 택배사 표의 지역명은 축약·오기가 있다.
|
|
2412
|
+
* 확인한 것만 남기고, 확인하지 못한 구간은 이 표에서 뺀다 — 판정하지 못하면 받지 않는 쪽이
|
|
2413
|
+
* `remoteAreaOf`의 규칙과 같다.
|
|
2414
|
+
*
|
|
2415
|
+
* ## 표에서 뺀 구간
|
|
2416
|
+
*
|
|
2417
|
+
* - **54000**: 택배사 표는 「경남 통영 섬지역3」으로 적었지만 이 번호는 **전북 군산시 옥도면**이다.
|
|
2418
|
+
* 게다가 공정거래위원회가 2025-10-07 발표에서 연륙교로 이어진 신시도·야미도·선유도와 비연륙
|
|
2419
|
+
* 도서(방축도·관리도)가 같은 우편번호를 쓰는 대표 사례로 이 지역을 들었다. 라벨도 부과 근거도
|
|
2420
|
+
* 확정하지 못해 뺀다.
|
|
2421
|
+
* - **강화군 본섬(23000~23003, 23011~23099)**: 택배사 표의 강화 할증 구간은 23004~23010
|
|
2422
|
+
* (교동면·삼산면·서도면)뿐이다. 강화대교·초지대교로 이어진 본섬은 도선료가 없어 어느 택배사도
|
|
2423
|
+
* 할증하지 않는다. 「누락」이 아니라 대상이 아니다.
|
|
2424
|
+
*
|
|
2425
|
+
* ## 한계
|
|
2426
|
+
*
|
|
2427
|
+
* 우편번호 단위 판정은 한 번호 안에 연륙도서와 비연륙도서가 섞인 구간에서 과대 부과가 된다.
|
|
2428
|
+
* 공정위가 2025-10-07에 온라인몰 13곳의 이 방식을 시정하게 한 지적이 그것이다
|
|
2429
|
+
* (https://eiec.kdi.re.kr/policy/materialView.do?num=272070). 아래 구간 중 33411(보령 오천면,
|
|
2430
|
+
* 원산도가 해저터널로 연결), 46768~46771(강서구 가덕도, 거가대교로 연결)이 그런 혼재 구간이다.
|
|
2431
|
+
* 도로명주소·건물관리번호 단위 판정은 후속 과제다.
|
|
2432
|
+
*
|
|
2433
|
+
* 범위는 **닫힌 구간**(`from` ≤ zip ≤ `to`)이고 겹치지 않는다. 앞에서부터 처음 맞는 항목을 쓴다.
|
|
2434
|
+
* 순서는 콘솔 「추가 배송비 지역」 표의 행 순서이기도 하다(`remoteAreaGroups`). 제주를 먼저 두고
|
|
2435
|
+
* 도서산간은 우편번호 오름차순으로 둔다.
|
|
2436
|
+
*/
|
|
2437
|
+
const REMOTE_AREA_ZIP_RANGES = [
|
|
2438
|
+
{
|
|
2439
|
+
area: "JEJU",
|
|
2440
|
+
from: 63e3,
|
|
2441
|
+
to: 63644,
|
|
2442
|
+
label: "제주특별자치도"
|
|
2443
|
+
},
|
|
2444
|
+
{
|
|
2445
|
+
area: "ISOLATED",
|
|
2446
|
+
from: 22386,
|
|
2447
|
+
to: 22388,
|
|
2448
|
+
label: "인천 영종구 무의동"
|
|
2449
|
+
},
|
|
2450
|
+
{
|
|
2451
|
+
area: "ISOLATED",
|
|
2452
|
+
from: 23004,
|
|
2453
|
+
to: 23010,
|
|
2454
|
+
label: "인천 강화군 도서"
|
|
2455
|
+
},
|
|
2456
|
+
{
|
|
2457
|
+
area: "ISOLATED",
|
|
2458
|
+
from: 23100,
|
|
2459
|
+
to: 23116,
|
|
2460
|
+
label: "인천 옹진군 도서"
|
|
2461
|
+
},
|
|
2462
|
+
{
|
|
2463
|
+
area: "ISOLATED",
|
|
2464
|
+
from: 23124,
|
|
2465
|
+
to: 23136,
|
|
2466
|
+
label: "인천 옹진군 도서"
|
|
2467
|
+
},
|
|
2468
|
+
{
|
|
2469
|
+
area: "ISOLATED",
|
|
2470
|
+
from: 31708,
|
|
2471
|
+
to: 31708,
|
|
2472
|
+
label: "충남 당진시 도서"
|
|
2473
|
+
},
|
|
2474
|
+
{
|
|
2475
|
+
area: "ISOLATED",
|
|
2476
|
+
from: 32133,
|
|
2477
|
+
to: 32133,
|
|
2478
|
+
label: "충남 태안군 도서"
|
|
2479
|
+
},
|
|
2480
|
+
{
|
|
2481
|
+
area: "ISOLATED",
|
|
2482
|
+
from: 33411,
|
|
2483
|
+
to: 33411,
|
|
2484
|
+
label: "충남 보령시 도서"
|
|
2485
|
+
},
|
|
2486
|
+
{
|
|
2487
|
+
area: "ISOLATED",
|
|
2488
|
+
from: 40200,
|
|
2489
|
+
to: 40240,
|
|
2490
|
+
label: "경북 울릉군"
|
|
2491
|
+
},
|
|
2492
|
+
{
|
|
2493
|
+
area: "ISOLATED",
|
|
2494
|
+
from: 46768,
|
|
2495
|
+
to: 46771,
|
|
2496
|
+
label: "부산 강서구 도서"
|
|
2497
|
+
},
|
|
2498
|
+
{
|
|
2499
|
+
area: "ISOLATED",
|
|
2500
|
+
from: 52570,
|
|
2501
|
+
to: 52571,
|
|
2502
|
+
label: "경남 사천시 도서"
|
|
2503
|
+
},
|
|
2504
|
+
{
|
|
2505
|
+
area: "ISOLATED",
|
|
2506
|
+
from: 53031,
|
|
2507
|
+
to: 53033,
|
|
2508
|
+
label: "경남 통영시 도서"
|
|
2509
|
+
},
|
|
2510
|
+
{
|
|
2511
|
+
area: "ISOLATED",
|
|
2512
|
+
from: 53089,
|
|
2513
|
+
to: 53104,
|
|
2514
|
+
label: "경남 통영시 도서"
|
|
2515
|
+
},
|
|
2516
|
+
{
|
|
2517
|
+
area: "ISOLATED",
|
|
2518
|
+
from: 56347,
|
|
2519
|
+
to: 56349,
|
|
2520
|
+
label: "전북 부안군 위도면"
|
|
2521
|
+
},
|
|
2522
|
+
{
|
|
2523
|
+
area: "ISOLATED",
|
|
2524
|
+
from: 57068,
|
|
2525
|
+
to: 57069,
|
|
2526
|
+
label: "전남 영광군 낙월면"
|
|
2527
|
+
},
|
|
2528
|
+
{
|
|
2529
|
+
area: "ISOLATED",
|
|
2530
|
+
from: 58760,
|
|
2531
|
+
to: 58762,
|
|
2532
|
+
label: "전남 목포시 도서"
|
|
2533
|
+
},
|
|
2534
|
+
{
|
|
2535
|
+
area: "ISOLATED",
|
|
2536
|
+
from: 58800,
|
|
2537
|
+
to: 58810,
|
|
2538
|
+
label: "전남 신안군"
|
|
2539
|
+
},
|
|
2540
|
+
{
|
|
2541
|
+
area: "ISOLATED",
|
|
2542
|
+
from: 58816,
|
|
2543
|
+
to: 58818,
|
|
2544
|
+
label: "전남 신안군"
|
|
2545
|
+
},
|
|
2546
|
+
{
|
|
2547
|
+
area: "ISOLATED",
|
|
2548
|
+
from: 58826,
|
|
2549
|
+
to: 58826,
|
|
2550
|
+
label: "전남 신안군"
|
|
2551
|
+
},
|
|
2552
|
+
{
|
|
2553
|
+
area: "ISOLATED",
|
|
2554
|
+
from: 58828,
|
|
2555
|
+
to: 58866,
|
|
2556
|
+
label: "전남 신안군"
|
|
2557
|
+
},
|
|
2558
|
+
{
|
|
2559
|
+
area: "ISOLATED",
|
|
2560
|
+
from: 58953,
|
|
2561
|
+
to: 58958,
|
|
2562
|
+
label: "전남 진도군 조도면"
|
|
2563
|
+
},
|
|
2564
|
+
{
|
|
2565
|
+
area: "ISOLATED",
|
|
2566
|
+
from: 59102,
|
|
2567
|
+
to: 59103,
|
|
2568
|
+
label: "전남 완도군 도서"
|
|
2569
|
+
},
|
|
2570
|
+
{
|
|
2571
|
+
area: "ISOLATED",
|
|
2572
|
+
from: 59106,
|
|
2573
|
+
to: 59106,
|
|
2574
|
+
label: "전남 완도군 도서"
|
|
2575
|
+
},
|
|
2576
|
+
{
|
|
2577
|
+
area: "ISOLATED",
|
|
2578
|
+
from: 59127,
|
|
2579
|
+
to: 59127,
|
|
2580
|
+
label: "전남 완도군 도서"
|
|
2581
|
+
},
|
|
2582
|
+
{
|
|
2583
|
+
area: "ISOLATED",
|
|
2584
|
+
from: 59129,
|
|
2585
|
+
to: 59129,
|
|
2586
|
+
label: "전남 완도군 도서"
|
|
2587
|
+
},
|
|
2588
|
+
{
|
|
2589
|
+
area: "ISOLATED",
|
|
2590
|
+
from: 59137,
|
|
2591
|
+
to: 59166,
|
|
2592
|
+
label: "전남 완도군 도서"
|
|
2593
|
+
},
|
|
2594
|
+
{
|
|
2595
|
+
area: "ISOLATED",
|
|
2596
|
+
from: 59421,
|
|
2597
|
+
to: 59421,
|
|
2598
|
+
label: "전남 보성군 장도"
|
|
2599
|
+
},
|
|
2600
|
+
{
|
|
2601
|
+
area: "ISOLATED",
|
|
2602
|
+
from: 59531,
|
|
2603
|
+
to: 59531,
|
|
2604
|
+
label: "전남 고흥군 도서"
|
|
2605
|
+
},
|
|
2606
|
+
{
|
|
2607
|
+
area: "ISOLATED",
|
|
2608
|
+
from: 59551,
|
|
2609
|
+
to: 59551,
|
|
2610
|
+
label: "전남 고흥군 도서"
|
|
2611
|
+
},
|
|
2612
|
+
{
|
|
2613
|
+
area: "ISOLATED",
|
|
2614
|
+
from: 59563,
|
|
2615
|
+
to: 59563,
|
|
2616
|
+
label: "전남 고흥군 도서"
|
|
2617
|
+
},
|
|
2618
|
+
{
|
|
2619
|
+
area: "ISOLATED",
|
|
2620
|
+
from: 59568,
|
|
2621
|
+
to: 59568,
|
|
2622
|
+
label: "전남 고흥군 도서"
|
|
2623
|
+
},
|
|
2624
|
+
{
|
|
2625
|
+
area: "ISOLATED",
|
|
2626
|
+
from: 59650,
|
|
2627
|
+
to: 59650,
|
|
2628
|
+
label: "전남 여수시 도서"
|
|
2629
|
+
},
|
|
2630
|
+
{
|
|
2631
|
+
area: "ISOLATED",
|
|
2632
|
+
from: 59766,
|
|
2633
|
+
to: 59766,
|
|
2634
|
+
label: "전남 여수시 도서"
|
|
2635
|
+
},
|
|
2636
|
+
{
|
|
2637
|
+
area: "ISOLATED",
|
|
2638
|
+
from: 59781,
|
|
2639
|
+
to: 59790,
|
|
2640
|
+
label: "전남 여수시 도서"
|
|
2641
|
+
}
|
|
2642
|
+
];
|
|
2643
|
+
/**
|
|
2644
|
+
* 우편번호 → 지역 구분. 5자리 숫자가 아니면 `NONE`이다.
|
|
2645
|
+
*
|
|
2646
|
+
* 형식 검증은 배송지 스키마(`/^[0-9]{5}$/`)가 하고, 여기서는 **판정하지 못하면 추가 배송비를 받지 않는다**.
|
|
2647
|
+
* 반대로 두면 우편번호를 잘못 넣은 주문에 근거 없는 금액이 붙는다.
|
|
2648
|
+
*/
|
|
2649
|
+
function remoteAreaOf(zipCode) {
|
|
2650
|
+
if (!zipCode || !/^[0-9]{5}$/.test(zipCode)) return "NONE";
|
|
2651
|
+
const zip = Number.parseInt(zipCode, 10);
|
|
2652
|
+
for (const range of REMOTE_AREA_ZIP_RANGES) if (zip >= range.from && zip <= range.to) return range.area;
|
|
2653
|
+
return "NONE";
|
|
2654
|
+
}
|
|
2655
|
+
/** 지역 구분의 안내 이름 — 판정된 범위의 `label`이다. 판정되지 않으면 null */
|
|
2656
|
+
function remoteAreaLabelOf(zipCode) {
|
|
2657
|
+
if (!zipCode || !/^[0-9]{5}$/.test(zipCode)) return null;
|
|
2658
|
+
const zip = Number.parseInt(zipCode, 10);
|
|
2659
|
+
return REMOTE_AREA_ZIP_RANGES.find((r) => zip >= r.from && zip <= r.to)?.label ?? null;
|
|
2660
|
+
}
|
|
2661
|
+
/** 묶음 하나에 붙는 지역 추가 배송비 */
|
|
2662
|
+
function remoteSurchargeOf(policy, area) {
|
|
2663
|
+
if (area === "JEJU") return policy.jejuSurcharge;
|
|
2664
|
+
if (area === "ISOLATED") return policy.isolatedSurcharge;
|
|
2665
|
+
return 0;
|
|
2666
|
+
}
|
|
2667
|
+
/**
|
|
2668
|
+
* 배송 묶음 키 — **같은 출고지 + 같은 배송 정책이면 같은 키다.**
|
|
2669
|
+
*
|
|
2670
|
+
* 키는 주문 시점에 주문상품 행에 스냅샷된다(`order_items.delivery_bundle_key`). 셀러가 주문 뒤
|
|
2671
|
+
* 출고지나 배송비를 바꿔도 그 주문의 묶음은 움직이지 않는다 — 움직이면 이미 환불한 묶음의 키가
|
|
2672
|
+
* 달라져 `orders.delivery_fee_settlements`의 이중 환불 방지 표시가 무력해진다.
|
|
2673
|
+
*
|
|
2674
|
+
* `-`는 「값 없음」이다. 사람이 읽을 수 있게 남기고, 값 자체에 `:`가 들어갈 수 없는 형식만 쓴다
|
|
2675
|
+
* (주소 id는 `adr_…`, 나머지는 열거형·정수).
|
|
2676
|
+
*/
|
|
2677
|
+
function deliveryBundleKeyOf(product) {
|
|
2678
|
+
const origin = product.shippingAddressId ?? "-";
|
|
2679
|
+
const threshold = product.deliveryType === "CONDITIONAL_FREE" ? product.conditionalFreeAmount ?? 0 : "-";
|
|
2680
|
+
const fee = product.deliveryType === "FREE" ? 0 : product.deliveryFee;
|
|
2681
|
+
return `b:${origin}:${product.deliveryType}:${fee}:${threshold}`;
|
|
2682
|
+
}
|
|
2683
|
+
/**
|
|
2684
|
+
* 기본 배송비를 면제한 근거 — 면제하지 않았으면 null이다.
|
|
2685
|
+
*
|
|
2686
|
+
* 환불 정산이 근거를 구분해야 한다. 조건부 무료 기준 미달 차감은 **상품별 조건부 무료(`CONDITIONAL`)로
|
|
2687
|
+
* 면제된 묶음만** 대상이다. 스토어 전체 무료 기준(`STORE_THRESHOLD`)이나 무료배송 상품(`FREE`)은 셀러가
|
|
2688
|
+
* 배송비를 받지 않기로 한 것이므로, 일부 취소로 기준이 깨져도 구매자에게 배송비를 물리지 않는다.
|
|
2689
|
+
*
|
|
2690
|
+
* 세 값이 겹치면 `FREE` → `STORE_THRESHOLD` → `CONDITIONAL` 순으로 센 근거를 남긴다.
|
|
2691
|
+
*/
|
|
2692
|
+
const deliveryFeeWaiverSchema = z.enum([
|
|
2693
|
+
"FREE",
|
|
2694
|
+
"STORE_THRESHOLD",
|
|
2695
|
+
"CONDITIONAL"
|
|
2696
|
+
]);
|
|
2697
|
+
/**
|
|
2698
|
+
* 배송비 계산 — **순수 함수다.** 장바구니 요약, 주문서 금액, 결제 시작의 최종 확정,
|
|
2699
|
+
* 주문 배송비 스냅샷이 모두 이 한 곳을 쓴다.
|
|
2700
|
+
*
|
|
2701
|
+
* 순서가 규칙이다. 묶음별 조건부 무료를 먼저 보고, 그다음 스토어 전체 무료 기준으로 기본 배송비를
|
|
2702
|
+
* 한꺼번에 0으로 만들고, 마지막에 지역 추가 배송비를 묶음마다 더한다. 추가 배송비는 무료 기준에
|
|
2703
|
+
* 걸리지 않는다.
|
|
2704
|
+
*/
|
|
2705
|
+
function quoteDelivery(input) {
|
|
2706
|
+
const { policy } = input;
|
|
2707
|
+
const area = remoteAreaOf(input.zipCode);
|
|
2708
|
+
const surcharge = remoteSurchargeOf(policy, area);
|
|
2709
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2710
|
+
let productAmount = 0;
|
|
2711
|
+
for (const line of input.lines) {
|
|
2712
|
+
const product = input.productOf(line.productId);
|
|
2713
|
+
if (!product) continue;
|
|
2714
|
+
productAmount += line.amount;
|
|
2715
|
+
const key = deliveryBundleKeyOf(product);
|
|
2716
|
+
const group = groups.get(key) ?? {
|
|
2717
|
+
product,
|
|
2718
|
+
ids: /* @__PURE__ */ new Set(),
|
|
2719
|
+
sum: 0
|
|
2720
|
+
};
|
|
2721
|
+
group.ids.add(line.productId);
|
|
2722
|
+
group.sum += line.amount;
|
|
2723
|
+
groups.set(key, group);
|
|
2724
|
+
}
|
|
2725
|
+
const freeByThreshold = policy.freeThreshold !== null && productAmount >= policy.freeThreshold && groups.size > 0;
|
|
2726
|
+
const bundles = [];
|
|
2727
|
+
for (const [bundleKey, group] of groups) {
|
|
2728
|
+
const { product } = group;
|
|
2729
|
+
const freeThreshold = product.deliveryType === "CONDITIONAL_FREE" && product.conditionalFreeAmount !== null ? product.conditionalFreeAmount ?? 0 : null;
|
|
2730
|
+
const listFee = product.deliveryType === "FREE" ? 0 : product.deliveryFee;
|
|
2731
|
+
const waivedBy = product.deliveryType === "FREE" ? "FREE" : freeByThreshold ? "STORE_THRESHOLD" : freeThreshold !== null && group.sum >= freeThreshold ? "CONDITIONAL" : null;
|
|
2732
|
+
bundles.push({
|
|
2733
|
+
bundleKey,
|
|
2734
|
+
productIds: [...group.ids],
|
|
2735
|
+
fee: waivedBy === null ? listFee : 0,
|
|
2736
|
+
waivedBy,
|
|
2737
|
+
listFee,
|
|
2738
|
+
freeThreshold,
|
|
2739
|
+
remoteSurcharge: surcharge
|
|
2740
|
+
});
|
|
2741
|
+
}
|
|
2742
|
+
const baseFee = bundles.reduce((sum, b) => sum + b.fee, 0);
|
|
2743
|
+
const remoteSurcharge = bundles.reduce((sum, b) => sum + b.remoteSurcharge, 0);
|
|
2744
|
+
return {
|
|
2745
|
+
bundles,
|
|
2746
|
+
baseFee,
|
|
2747
|
+
remoteSurcharge,
|
|
2748
|
+
deliveryFee: baseFee + remoteSurcharge,
|
|
2749
|
+
remoteArea: area,
|
|
2750
|
+
freeByThreshold
|
|
2751
|
+
};
|
|
2752
|
+
}
|
|
2753
|
+
//#endregion
|
|
2226
2754
|
//#region src/schemas/store.ts
|
|
2227
2755
|
/**
|
|
2228
2756
|
* 스토어 코드 규칙 — 스토어프론트 API가 테넌트를 가르는 값이다(`X-Store-Code` 헤더).
|
|
@@ -2322,6 +2850,7 @@ const updateStoreRequestSchema = z.object({
|
|
|
2322
2850
|
autoDeliverDays: z.number().int().min(0).max(30).optional().describe(autoDeliverDaysDescription),
|
|
2323
2851
|
autoConfirmDays: z.number().int().min(0).max(30).optional().describe(autoConfirmDaysDescription),
|
|
2324
2852
|
refundPolicy: refundPolicyPatchSchema.optional().describe("스토어 기본 환불 정책 — 준 항목만 바꾼다. 상품별 정책(`products.refundPolicy`)이 없는 상품에 적용된다"),
|
|
2853
|
+
shippingPolicy: shippingPolicyPatchSchema.optional().describe("스토어 배송비 규칙 — 준 항목만 바꾼다. 기본 배송비, 전체 무료배송 기준액, 제주·도서산간 추가 배송비다. 바꾼 값은 **새 주문서부터** 적용된다(이미 만든 주문서·주문의 배송비는 스냅샷이 원천이다)"),
|
|
2325
2854
|
termsVersion: policyVersionSchema.optional().describe("이용약관 버전. 올리면 이 약관에 동의한 구매자에게 재동의를 요구한다(`GET /storefront/v1/me`의 `reconsentRequired`)"),
|
|
2326
2855
|
privacyVersion: policyVersionSchema.optional().describe("개인정보 수집이용 동의 버전. 올리면 구매자에게 재동의를 요구한다"),
|
|
2327
2856
|
termsUrl: policyDocumentUrlSchema.optional().describe("이용약관 문서 주소(https). 동의 시점의 값이 동의 이력에 복사된다. `null`을 주면 지운다"),
|
|
@@ -2346,6 +2875,7 @@ const storeSchema = z.object({
|
|
|
2346
2875
|
autoDeliverDays: z.number().int().describe(autoDeliverDaysDescription),
|
|
2347
2876
|
autoConfirmDays: z.number().int().describe(autoConfirmDaysDescription),
|
|
2348
2877
|
refundPolicy: refundPolicySchema.describe("스토어 기본 환불 정책. 스토어가 정하지 않은 항목은 플랫폼 기본값으로 채워 항상 전부 싣는다"),
|
|
2878
|
+
shippingPolicy: shippingPolicySchema.describe("스토어 배송비 규칙. 스토어가 정하지 않은 항목은 플랫폼 기본값으로 채워 항상 전부 싣는다"),
|
|
2349
2879
|
termsVersion: z.string().describe("현재 이용약관 버전. 가입·재동의가 이 값으로 이력에 남는다"),
|
|
2350
2880
|
privacyVersion: z.string().describe("현재 개인정보 수집이용 동의 버전"),
|
|
2351
2881
|
termsVersionUpdatedAt: z.string().nullable().describe("이용약관 버전을 마지막으로 바꾼 시각. 바꾼 적이 없으면 null"),
|
|
@@ -2614,7 +3144,12 @@ function createStoreClient(options) {
|
|
|
2614
3144
|
* 그 밖의 값은 400 `INVALID_PARAMETER`. 행마다 `testPayment`가 붙는다.
|
|
2615
3145
|
*/
|
|
2616
3146
|
list: (params) => storeHttp.request("GET", "/orders", pageSchema(orderSummarySchema), { query: params }),
|
|
2617
|
-
get: (orderId) => storeHttp.request("GET", path`/orders/${orderId}`, orderSchema)
|
|
3147
|
+
get: (orderId) => storeHttp.request("GET", path`/orders/${orderId}`, orderSchema),
|
|
3148
|
+
/**
|
|
3149
|
+
* `POST /v1/orders/{orderId}/cash-receipt/reissue` — 실패했거나 재시도 대기 중인 현금영수증을 지금 다시 발급·취소한다.
|
|
3150
|
+
* 콘솔 OWNER·ADMIN 전용(PAT·M2M 403 `INSUFFICIENT_ROLE`). 404 `CASH_RECEIPT_NOT_FOUND`, 409 `CASH_RECEIPT_NOT_REISSUABLE`
|
|
3151
|
+
*/
|
|
3152
|
+
reissueCashReceipt: (orderId) => storeHttp.request("POST", path`/orders/${orderId}/cash-receipt/reissue`, cashReceiptSchema)
|
|
2618
3153
|
},
|
|
2619
3154
|
orderItems: {
|
|
2620
3155
|
/** `GET /v1/order-items`. `testPayment` 필터는 `orders.list`와 같다 */
|
|
@@ -3296,4 +3831,4 @@ function createStoreSession(options) {
|
|
|
3296
3831
|
};
|
|
3297
3832
|
}
|
|
3298
3833
|
//#endregion
|
|
3299
|
-
export { ApiError, MAX_ANALYTICS_ALLOWED_ORIGINS, MAX_AUTO_TRANSITION_DAYS, MAX_OPTION_GROUPS, MAX_PRODUCT_IMAGES, MAX_VALUES_PER_GROUP, MAX_VARIANTS, PAYMENT_ROUTING_EXCLUSION_CODES, PORTONE_CHANNEL_NAME_MAX_LENGTH, PORTONE_MAX_CHANNELS, PORTONE_MIN_CHANNELS, REFUND_POLICY_DEFAULTS, RESERVED_STORE_CODES, STORE_CODE_PATTERN, STORE_ROLE_SCOPES, STORE_SCOPE_RESOURCES, STORE_SESSION_KEYS, TOSS_WIDGET_CLIENT_KEY_PATTERN, TOSS_WIDGET_KEY_MESSAGE, TOSS_WIDGET_SECRET_KEY_PATTERN, UPLOAD_PURPOSE_LIMITS, VARIANT_STOCK_EXCLUSIVE_MESSAGE, WEBHOOK_DEFAULT_TOLERANCE_SEC, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_EVENT_TYPE_HEADER, WEBHOOK_HEADERS, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_USER_AGENT, addressChangeRequestListSchema, addressTypeSchema, analyticsChannelSchema, analyticsCheckoutOutcomeSchema, analyticsCheckoutSchema, analyticsDeviceRowSchema, analyticsDevicesSchema, analyticsFunnelStepSchema, analyticsOriginSchema, analyticsOverviewSchema, analyticsPagesQuerySchema, analyticsPagesSchema, analyticsProductRowSchema, analyticsProductSortSchema, analyticsProductsQuerySchema, analyticsProductsSchema, analyticsRangeQuerySchema, analyticsRealtimeSchema, analyticsSearchQuerySchema, analyticsSearchSchema, analyticsSourceGroupBySchema, analyticsSourceRowSchema, analyticsSourcesQuerySchema, analyticsSourcesSchema, analyticsTotalsSchema, apiClientListQuerySchema, apiClientSchema, apiClientSecretRotatedSchema, apiClientStatusSchema, apiClientTypeSchema, apiLogErrorSchema, apiLogListQuerySchema, apiLogPageSchema, apiLogPrincipalSchema, apiLogPrincipalTypeSchema, apiLogSchema, apiLogStatusFilterSchema, apiLogSummarySchema, apiTokenCreateRequestSchema, apiTokenCreatedSchema, apiTokenSchema, approveClaimResultSchema, buildAuthorizeUrl, buildQuery, bulkResultSchema, cancelBySellerRequestSchema, cancelBySellerResultSchema, carrierSchema, categoryAttributeSchema, categoryCreateRequestSchema, categoryDeleteQuerySchema, categoryDeleteStrategySchema, categoryListQuerySchema, categoryPatchRequestSchema, categoryProductSortSchema, categorySchema, categorySearchResultSchema, categoryTreeNodeSchema, categoryWithPathSchema, changeTypeSchema, claimDetailSchema, claimHoldResultSchema, claimListQuerySchema, claimReasonSchema, claimSchema, claimStatusSchema, claimTypeSchema, claimWebhookEventDataSchema, claimWebhookEventSchema, clientCredentialsTokenResponseSchema, consentActionSchema, consentKindSchema, consentSourceSchema, createPkcePair, createStoreClient, createStoreSession, customerAddressSchema, customerConsentListQuerySchema, customerConsentSchema, customerConsentStateSchema, customerConsentsSchema, customerDetailSchema, customerInquiryCategorySchema, customerInquiryListQuerySchema, customerListQuerySchema, customerOrderSchema, customerSortSchema, customerStatsSchema, customerSummarySchema, customerWithdrawalBlockedDetailsSchema, deliveryInfoSchema, deliveryMethodSchema, deliveryStatusSchema, deliveryTypeSchema, discountRequestSchema, discountSchema, dispatchRequestSchema, easyPayProviderResponseSchema, easyPayProviderSchema, eventTypeSchema, exchangeAuthorizationCode, exchangeStoreTokenViaOAuth, holdOrderItemRequestSchema, inquiryListQuerySchema, inquirySchema, inquiryWebhookEventDataSchema, inquiryWebhookEventSchema, invitationListQuerySchema, invitationSchema, isReservedStoreCode, isStoreScope, isWebOrigin, liveGateConditionCodeSchema, liveGateConditionSchema, liveGateErrorDetailsSchema, liveGateSchema, loginProviderSchema, loginProviderStatusSchema, loginProviderTestSchema, loginSettingsSchema, maskedSecretSchema, myAccountSchema, myStoreSchema, oauthClientRegistrationRequestSchema, oauthClientRegistrationResponseSchema, oauthTokenResponseSchema, optionGroupRequestSchema, optionGroupSchema, optionModelRequestSchema, optionModelSchema, optionValueRequestSchema, optionValueSchema, orderItemListQuerySchema, orderItemMemoResultSchema, orderItemPageSchema, orderItemSchema, orderItemStatusSchema, orderListQuerySchema, orderSchema, orderSummaryPageSchema, orderSummarySchema, orderWebhookEventDataSchema, orderWebhookEventSchema, pageInfoSchema, pageQueryShape, pageSchema, paymentAttemptRecordSchema, paymentAttemptStatusSchema, paymentCredentialSetSchema, paymentListQuerySchema, paymentProviderSchema, paymentProviderVerificationSchema, paymentRecordDetailSchema, paymentRecordPageSchema, paymentRecordSchema, paymentRecordStatusSchema, paymentRefundRecordSchema, paymentSettingsSchema, pgEnvironmentSchema, pgPaymentMethodSchema, pgProviderSchema, pgVerificationResultSchema, policyDocumentUrlSchema, policyVersionSchema, portOneChannelSchema, portOneCredentialsInputSchema, productCreateRequestSchema, productImageRejection, productImageUrlSchema, productListQuerySchema, productOutOfStockWebhookEventDataSchema, productOutOfStockWebhookEventSchema, productPatchRequestSchema, productRefundPolicyOverride, productSchema, productSortSchema, productStatusSchema, productSummarySchema, productVariantRequestSchema, productVariantSchema, proratedRefundBase, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, refreshUserToken, refundPolicyPatchSchema, refundPolicySchema, rejectClaimRequestSchema, resolveRefundPolicy, reviewListQuerySchema, reviewReportResultSchema, reviewSchema, reviewSortSchema, reviewWebhookEventDataSchema, reviewWebhookEventSchema, salesReportGroupBySchema, salesReportQuerySchema, salesReportRowSchema, salesReportSchema, salesTotalsSchema, saveLoginProviderRequestSchema, scopeAccessSchema, sellerAddressListQuerySchema, sellerAddressRequestSchema, sellerAddressSchema, sellerCustomerInquirySchema, settlementDetailQuerySchema, settlementDetailSchema, settlementListQuerySchema, settlementStatusSchema, settlementSummarySchema, settlementWithDetailsSchema, shippingAddressSchema, storeCodeSchema, storeMemberRoleUpdatedSchema, storeMemberSchema, storeRoleSchema, storeSchema, storeScopeResourceSchema, storeTokenResponseSchema, tossPaymentsCredentialsInputSchema, trackingUpdateResultSchema, updateLoginProviderRequestSchema, updateLoginSettingsRequestSchema, updatePaymentProviderRequestSchema, updatePaymentSettingsRequestSchema, updateStoreRequestSchema, uploadExtensionOf, uploadPurposeSchema, uploadRejection, uploadRequestSchema, uploadTicketSchema, upsertPortOneProviderRequestSchema, upsertTossPaymentsProviderRequestSchema, userTokenResponseSchema, variantStockRequestSchema, variantStockSchema, verifyPaymentProviderRequestSchema, webhookCreatedSchema, webhookDeliveryErrorCodeSchema, webhookDeliveryListQuerySchema, webhookDeliverySchema, webhookDeliveryStatusSchema, webhookEventSchema, webhookRedeliverFailedResultSchema, webhookRequestSchema, webhookSchema, webhookSecretRotatedSchema, webhookStatusSchema, webhookTestRequestSchema, webhookTestResultSchema, withdrawCustomerRequestSchema };
|
|
3834
|
+
export { ApiError, CASH_RECEIPT_STATUS_VALUES, MAX_ANALYTICS_ALLOWED_ORIGINS, MAX_AUTO_TRANSITION_DAYS, MAX_OPTION_GROUPS, MAX_PRODUCT_IMAGES, MAX_VALUES_PER_GROUP, MAX_VARIANTS, PAYMENT_ROUTING_EXCLUSION_CODES, PORTONE_CHANNEL_NAME_MAX_LENGTH, PORTONE_MAX_CHANNELS, PORTONE_MIN_CHANNELS, REFUND_POLICY_DEFAULTS, REMOTE_AREA_ZIP_RANGES, RESERVED_STORE_CODES, SHIPPING_POLICY_DEFAULTS, STORE_CODE_PATTERN, STORE_ROLE_SCOPES, STORE_SCOPE_RESOURCES, STORE_SESSION_KEYS, TOSS_WIDGET_CLIENT_KEY_PATTERN, TOSS_WIDGET_KEY_MESSAGE, TOSS_WIDGET_SECRET_KEY_PATTERN, UPLOAD_PURPOSE_LIMITS, VARIANT_STOCK_EXCLUSIVE_MESSAGE, WEBHOOK_DEFAULT_TOLERANCE_SEC, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_EVENT_TYPE_HEADER, WEBHOOK_HEADERS, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_USER_AGENT, addressChangeRequestListSchema, addressTypeSchema, analyticsChannelSchema, analyticsCheckoutOutcomeSchema, analyticsCheckoutSchema, analyticsDeviceRowSchema, analyticsDevicesSchema, analyticsFunnelStepSchema, analyticsOriginSchema, analyticsOverviewSchema, analyticsPagesQuerySchema, analyticsPagesSchema, analyticsProductRowSchema, analyticsProductSortSchema, analyticsProductsQuerySchema, analyticsProductsSchema, analyticsRangeQuerySchema, analyticsRealtimeSchema, analyticsSearchQuerySchema, analyticsSearchSchema, analyticsSourceGroupBySchema, analyticsSourceRowSchema, analyticsSourcesQuerySchema, analyticsSourcesSchema, analyticsTotalsSchema, apiClientListQuerySchema, apiClientSchema, apiClientSecretRotatedSchema, apiClientStatusSchema, apiClientTypeSchema, apiLogErrorSchema, apiLogListQuerySchema, apiLogPageSchema, apiLogPrincipalSchema, apiLogPrincipalTypeSchema, apiLogSchema, apiLogStatusFilterSchema, apiLogSummarySchema, apiTokenCreateRequestSchema, apiTokenCreatedSchema, apiTokenSchema, approveClaimResultSchema, buildAuthorizeUrl, buildQuery, bulkResultSchema, cancelBySellerRequestSchema, cancelBySellerResultSchema, carrierSchema, cashReceiptSchema, categoryAttributeSchema, categoryCreateRequestSchema, categoryDeleteQuerySchema, categoryDeleteStrategySchema, categoryListQuerySchema, categoryPatchRequestSchema, categoryProductSortSchema, categorySchema, categorySearchResultSchema, categoryTreeNodeSchema, categoryWithPathSchema, changeTypeSchema, claimDetailSchema, claimHoldResultSchema, claimListQuerySchema, claimReasonSchema, claimReturnAddressSchema, claimSchema, claimStatusSchema, claimTypeSchema, claimWebhookEventDataSchema, claimWebhookEventSchema, clientCredentialsTokenResponseSchema, consentActionSchema, consentKindSchema, consentSourceSchema, createPkcePair, createStoreClient, createStoreSession, customerAddressSchema, customerConsentListQuerySchema, customerConsentSchema, customerConsentStateSchema, customerConsentsSchema, customerDetailSchema, customerInquiryCategorySchema, customerInquiryListQuerySchema, customerListQuerySchema, customerOrderSchema, customerSortSchema, customerStatsSchema, customerSummarySchema, customerWithdrawalBlockedDetailsSchema, deliveryBundleKeyOf, deliveryFeeWaiverSchema, deliveryInfoSchema, deliveryMethodSchema, deliveryStatusSchema, deliveryTypeSchema, discountRequestSchema, discountSchema, dispatchRequestSchema, easyPayProviderResponseSchema, easyPayProviderSchema, eventTypeSchema, exchangeAuthorizationCode, exchangeStoreTokenViaOAuth, holdOrderItemRequestSchema, inquiryListQuerySchema, inquirySchema, inquiryWebhookEventDataSchema, inquiryWebhookEventSchema, invitationListQuerySchema, invitationSchema, isReservedStoreCode, isStoreScope, isWebOrigin, liveGateConditionCodeSchema, liveGateConditionSchema, liveGateErrorDetailsSchema, liveGateSchema, loginProviderSchema, loginProviderStatusSchema, loginProviderTestSchema, loginSettingsSchema, maskedSecretSchema, myAccountSchema, myStoreSchema, oauthClientRegistrationRequestSchema, oauthClientRegistrationResponseSchema, oauthTokenResponseSchema, optionGroupRequestSchema, optionGroupSchema, optionModelRequestSchema, optionModelSchema, optionValueRequestSchema, optionValueSchema, orderItemListQuerySchema, orderItemMemoResultSchema, orderItemPageSchema, orderItemSchema, orderItemStatusSchema, orderListQuerySchema, orderSchema, orderSummaryPageSchema, orderSummarySchema, orderWebhookEventDataSchema, orderWebhookEventSchema, pageInfoSchema, pageQueryShape, pageSchema, paymentAttemptRecordSchema, paymentAttemptStatusSchema, paymentCredentialSetSchema, paymentListQuerySchema, paymentProviderSchema, paymentProviderVerificationSchema, paymentRecordDetailSchema, paymentRecordPageSchema, paymentRecordSchema, paymentRecordStatusSchema, paymentRefundRecordSchema, paymentSettingsSchema, pgEnvironmentSchema, pgPaymentMethodSchema, pgProviderSchema, pgVerificationResultSchema, policyDocumentUrlSchema, policyVersionSchema, portOneChannelSchema, portOneCredentialsInputSchema, productCreateRequestSchema, productImageRejection, productImageUrlSchema, productListQuerySchema, productOutOfStockWebhookEventDataSchema, productOutOfStockWebhookEventSchema, productPatchRequestSchema, productRefundPolicyOverride, productSchema, productSortSchema, productStatusSchema, productSummarySchema, productVariantRequestSchema, productVariantSchema, proratedRefundBase, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, quoteDelivery, refreshUserToken, refundPolicyPatchSchema, refundPolicySchema, rejectClaimRequestSchema, remoteAreaLabelOf, remoteAreaOf, remoteAreaSchema, remoteSurchargeOf, resolveRefundPolicy, resolveShippingPolicy, reviewListQuerySchema, reviewReportResultSchema, reviewSchema, reviewSortSchema, reviewWebhookEventDataSchema, reviewWebhookEventSchema, salesReportGroupBySchema, salesReportQuerySchema, salesReportRowSchema, salesReportSchema, salesTotalsSchema, saveLoginProviderRequestSchema, scopeAccessSchema, sellerAddressListQuerySchema, sellerAddressRequestSchema, sellerAddressSchema, sellerCustomerInquirySchema, settlementDetailQuerySchema, settlementDetailSchema, settlementListQuerySchema, settlementStatusSchema, settlementSummarySchema, settlementWithDetailsSchema, shippingAddressSchema, shippingPolicyPatchSchema, shippingPolicySchema, storeCodeSchema, storeMemberRoleUpdatedSchema, storeMemberSchema, storeRoleSchema, storeSchema, storeScopeResourceSchema, storeTokenResponseSchema, tossPaymentsCredentialsInputSchema, trackingStageResponseSchema, trackingUpdateResultSchema, updateLoginProviderRequestSchema, updateLoginSettingsRequestSchema, updatePaymentProviderRequestSchema, updatePaymentSettingsRequestSchema, updateStoreRequestSchema, uploadExtensionOf, uploadPurposeSchema, uploadRejection, uploadRequestSchema, uploadTicketSchema, upsertPortOneProviderRequestSchema, upsertTossPaymentsProviderRequestSchema, userTokenResponseSchema, variantStockRequestSchema, variantStockSchema, verifyPaymentProviderRequestSchema, webhookCreatedSchema, webhookDeliveryErrorCodeSchema, webhookDeliveryListQuerySchema, webhookDeliverySchema, webhookDeliveryStatusSchema, webhookEventSchema, webhookRedeliverFailedResultSchema, webhookRequestSchema, webhookSchema, webhookSecretRotatedSchema, webhookStatusSchema, webhookTestRequestSchema, webhookTestResultSchema, withdrawCustomerRequestSchema };
|