@sayren/store-sdk 0.9.0 → 0.10.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 +422 -0
- package/dist/index.mjs +223 -12
- package/package.json +1 -1
- package/src/client.ts +10 -0
- package/src/index.ts +1 -0
- package/src/schemas/claim.ts +38 -4
- package/src/schemas/customer.ts +72 -0
- package/src/schemas/order.ts +35 -3
- package/src/schemas/product.ts +21 -2
- package/src/schemas/refund-policy.ts +163 -0
- package/src/schemas/store.ts +58 -0
- package/src/schemas/webhook-event.ts +40 -0
package/dist/index.mjs
CHANGED
|
@@ -733,8 +733,9 @@ const claimSchema = z.object({
|
|
|
733
733
|
reason: claimReasonSchema,
|
|
734
734
|
reasonDetail: z.string().nullable(),
|
|
735
735
|
responsibility: z.enum(["BUYER", "SELLER"]),
|
|
736
|
-
claimDeliveryFee: z.number().int(),
|
|
737
|
-
expectedRefundAmount: z.number().int().nullable(),
|
|
736
|
+
claimDeliveryFee: z.number().int().describe("구매자가 부담하는 반품·교환 배송비. 원 단위"),
|
|
737
|
+
expectedRefundAmount: z.number().int().nullable().describe("접수 시점에 계산한 예상 환불액 — 수량 비율 상품 금액 − 반품 배송비 − 조건부 무료배송 미달 차감. **배송비 환불은 포함되지 않고 `expectedDeliveryFeeRefundAmount`로 따로 온다**(승인 시점의 배송 묶음 상태로 확정되기 때문이다). 교환은 환불이 없어 null이다"),
|
|
738
|
+
expectedDeliveryFeeRefundAmount: z.number().int().nullable().describe("접수 시점에 계산한 예상 배송비 환불액. 배송 묶음(같은 상품의 주문상품)이 모두 취소되거나 판매자 귀책일 때만 0보다 크다. 이 필드가 생기기 전에 접수된 클레임은 null이다"),
|
|
738
739
|
exchangeOption: z.object({
|
|
739
740
|
optionId: z.string(),
|
|
740
741
|
optionName: z.string()
|
|
@@ -788,8 +789,11 @@ const rejectClaimRequestSchema = z.object({
|
|
|
788
789
|
});
|
|
789
790
|
const approveClaimResultSchema = z.object({
|
|
790
791
|
claimId: z.string(),
|
|
791
|
-
refundAmount: z.number().int(),
|
|
792
|
-
deductAmount: z.number().int(),
|
|
792
|
+
refundAmount: z.number().int().describe("실제 환불한 금액 — 수량 비율 상품 금액 + 배송비 환불 − 반품 배송비 − 조건부 무료배송 미달 차감 − 추가 차감(`deductAmount`)"),
|
|
793
|
+
deductAmount: z.number().int().describe("승인 때 셀러가 추가로 차감한 금액"),
|
|
794
|
+
quantity: z.number().int().describe("환불한 수량"),
|
|
795
|
+
deliveryFeeRefundAmount: z.number().int().describe("환불에 포함된 배송비. 배송 묶음 전량 취소나 판매자 귀책일 때만 0보다 크다"),
|
|
796
|
+
deliveryFeeChargeAmount: z.number().int().describe("환불액에서 뺀 **배송비** — 반품·교환 배송비 + 조건부 무료배송 미달 차감. 추가 차감(`deductAmount`)은 포함하지 않는다"),
|
|
793
797
|
refundedAt: z.string()
|
|
794
798
|
});
|
|
795
799
|
//#endregion
|
|
@@ -838,6 +842,64 @@ const customerAddressSchema = z.object({
|
|
|
838
842
|
address1: z.string(),
|
|
839
843
|
address2: z.string().nullable()
|
|
840
844
|
});
|
|
845
|
+
/** 동의 종류 — 이용약관·개인정보 수집이용은 가입 필수, 마케팅 수신은 선택 */
|
|
846
|
+
const consentKindSchema = z.enum([
|
|
847
|
+
"TERMS",
|
|
848
|
+
"PRIVACY",
|
|
849
|
+
"MARKETING"
|
|
850
|
+
]);
|
|
851
|
+
const consentActionSchema = z.enum(["AGREED", "WITHDRAWN"]);
|
|
852
|
+
/**
|
|
853
|
+
* 동의가 일어난 경로. 값이 추가될 수 있어 모르는 값은 그대로 보여 준다.
|
|
854
|
+
* `SIGNUP` 비밀번호 가입 · `SOCIAL_SIGNUP` 소셜 가입 · `DELEGATED` 셀러 자체 회원 연동 ·
|
|
855
|
+
* `RECONSENT` 약관 개정 재동의 · `MEMBER_UPDATE` 구매자가 직접 변경 · `SELLER` 셀러가 처리
|
|
856
|
+
*/
|
|
857
|
+
const consentSourceSchema = z.enum([
|
|
858
|
+
"SIGNUP",
|
|
859
|
+
"SOCIAL_SIGNUP",
|
|
860
|
+
"DELEGATED",
|
|
861
|
+
"RECONSENT",
|
|
862
|
+
"MEMBER_UPDATE",
|
|
863
|
+
"SELLER"
|
|
864
|
+
]);
|
|
865
|
+
/** 동의 이력 한 줄 — 추가만 되고 지워지지 않는다(구매자 탈퇴 시에만 함께 지워진다) */
|
|
866
|
+
const customerConsentSchema = z.object({
|
|
867
|
+
consentId: z.string(),
|
|
868
|
+
kind: consentKindSchema,
|
|
869
|
+
/** 동의한 약관 버전. 마케팅은 버전이 없어 null */
|
|
870
|
+
version: z.string().nullable(),
|
|
871
|
+
/** 동의 시점의 약관 문서 주소. 스토어가 주소를 정하지 않았거나 마케팅이면 null */
|
|
872
|
+
documentUrl: z.string().nullable(),
|
|
873
|
+
action: consentActionSchema,
|
|
874
|
+
source: consentSourceSchema,
|
|
875
|
+
occurredAt: z.string()
|
|
876
|
+
});
|
|
877
|
+
/** 종류별 현재 동의 상태 */
|
|
878
|
+
const customerConsentStateSchema = z.object({
|
|
879
|
+
kind: consentKindSchema,
|
|
880
|
+
agreed: z.boolean(),
|
|
881
|
+
/** 동의한 약관 버전. 마케팅이거나 이력이 없으면 null */
|
|
882
|
+
agreedVersion: z.string().nullable(),
|
|
883
|
+
/** 스토어의 현재 약관 버전. 마케팅은 null */
|
|
884
|
+
currentVersion: z.string().nullable(),
|
|
885
|
+
/** 스토어가 정한 현재 약관 문서 주소. 정하지 않았거나 마케팅이면 null */
|
|
886
|
+
currentDocumentUrl: z.string().nullable(),
|
|
887
|
+
updatedAt: z.string().nullable(),
|
|
888
|
+
/** 약관이 개정돼 다시 받아야 하는가. 마케팅은 항상 false */
|
|
889
|
+
reconsentRequired: z.boolean()
|
|
890
|
+
});
|
|
891
|
+
const customerConsentsSchema = z.object({
|
|
892
|
+
terms: customerConsentStateSchema,
|
|
893
|
+
privacy: customerConsentStateSchema,
|
|
894
|
+
marketing: customerConsentStateSchema,
|
|
895
|
+
/** 필수 동의 중 하나라도 현재 버전이 아니면 true */
|
|
896
|
+
reconsentRequired: z.boolean()
|
|
897
|
+
});
|
|
898
|
+
/** `GET /v1/customers/{id}/consents` 쿼리 — 최근 순이다 */
|
|
899
|
+
const customerConsentListQuerySchema = z.object({
|
|
900
|
+
kind: consentKindSchema.optional().describe("동의 종류 필터. 생략하면 전체"),
|
|
901
|
+
...pageQueryShape()
|
|
902
|
+
});
|
|
841
903
|
/** 구매자 상세 — 휴대폰 전체를 보여 준다 */
|
|
842
904
|
const customerDetailSchema = z.object({
|
|
843
905
|
customerId: z.string(),
|
|
@@ -857,6 +919,7 @@ const customerDetailSchema = z.object({
|
|
|
857
919
|
/** 소셜 연결 시각. 비밀번호는 가입 시각 */
|
|
858
920
|
linkedAt: z.string()
|
|
859
921
|
})).describe("로그인 방법 — 이메일·비밀번호(`password`)와 연결된 소셜 계정"),
|
|
922
|
+
consents: customerConsentsSchema.describe("약관·개인정보·마케팅 동의의 현재 상태. 이력은 `GET /v1/customers/{customerId}/consents`"),
|
|
860
923
|
addresses: z.array(customerAddressSchema),
|
|
861
924
|
stats: customerStatsSchema.extend({
|
|
862
925
|
canceledOrReturnedCount: z.number().int().describe("취소된 주문 상품 + 완료된 반품 수"),
|
|
@@ -1526,10 +1589,12 @@ const orderItemSchema = z.object({
|
|
|
1526
1589
|
optionId: z.string().nullable(),
|
|
1527
1590
|
optionName: z.string().nullable(),
|
|
1528
1591
|
sellerCode: z.string().nullable(),
|
|
1529
|
-
quantity: z.number().int(),
|
|
1592
|
+
quantity: z.number().int().describe("주문 수량"),
|
|
1593
|
+
canceledQuantity: z.number().int().describe("취소·반품으로 환불된 누적 수량. 수량 단위 부분 취소가 없었으면 0이다"),
|
|
1594
|
+
activeQuantity: z.number().int().describe("살아 있는 수량 (`quantity` − `canceledQuantity`). 0이면 주문상품이 전량 취소됐다"),
|
|
1530
1595
|
unitPrice: z.number().int(),
|
|
1531
1596
|
discountAmount: z.number().int(),
|
|
1532
|
-
totalPrice: z.number().int(),
|
|
1597
|
+
totalPrice: z.number().int().describe("주문상품 금액 (할인 반영 단가 × 주문 수량)"),
|
|
1533
1598
|
hold: z.object({
|
|
1534
1599
|
reason: z.string(),
|
|
1535
1600
|
expectedDispatchDate: z.string()
|
|
@@ -1663,12 +1728,17 @@ const cancelBySellerRequestSchema = z.object({
|
|
|
1663
1728
|
"DELIVERY_IMPOSSIBLE",
|
|
1664
1729
|
"ETC"
|
|
1665
1730
|
]),
|
|
1666
|
-
detail: z.string().max(500).optional()
|
|
1731
|
+
detail: z.string().max(500).optional(),
|
|
1732
|
+
quantity: z.number().int().min(1).optional().describe("취소할 수량. 생략하면 남은 수량 전체다. 남은 수량보다 크면 400 `INVALID_QUANTITY`. 일부만 취소하면 주문상품은 상태를 유지한 채 `canceledQuantity`가 늘고, 전 수량이 소진되면 `CANCELED`가 된다")
|
|
1667
1733
|
});
|
|
1668
1734
|
/** `POST /v1/order-items/{orderItemId}/cancel` 응답 — 셀러 직권취소 환불 결과 */
|
|
1669
1735
|
const cancelBySellerResultSchema = z.object({
|
|
1670
1736
|
orderItemId: z.string(),
|
|
1671
|
-
refundAmount: z.number().int(),
|
|
1737
|
+
refundAmount: z.number().int().describe("실제 환불한 금액 — 수량 비율 상품 금액 + 배송비 환불 − 조건부 무료배송 미달 차감"),
|
|
1738
|
+
quantity: z.number().int().describe("취소한 수량"),
|
|
1739
|
+
canceledQuantity: z.number().int().describe("취소 후 누적 취소 수량"),
|
|
1740
|
+
deliveryFeeRefundAmount: z.number().int().describe("환불에 포함된 배송비. 배송 묶음(같은 상품)이 모두 취소됐고 환불 정책이 켜져 있을 때만 0보다 크다"),
|
|
1741
|
+
deliveryFeeChargeAmount: z.number().int().describe("조건부 무료배송 기준 미달로 환불액에서 뺀 배송비. 정책이 꺼져 있으면 항상 0이다"),
|
|
1672
1742
|
refundedAt: z.string()
|
|
1673
1743
|
});
|
|
1674
1744
|
/** `PUT /v1/order-items/{orderItemId}/memo` 응답 — 빈 문자열로 저장하면 메모가 지워져 `null`이다 */
|
|
@@ -1693,6 +1763,116 @@ const purchaseDecisionExtendResultSchema = z.object({
|
|
|
1693
1763
|
*/
|
|
1694
1764
|
const addressChangeRequestListSchema = z.array(z.record(z.string(), z.unknown())).describe("배송지 변경 요청 목록 (현재 항상 빈 배열)");
|
|
1695
1765
|
//#endregion
|
|
1766
|
+
//#region src/schemas/refund-policy.ts
|
|
1767
|
+
/**
|
|
1768
|
+
* 환불 정책 (이슈 #25) — 취소·반품·교환에서 **배송비를 누가 부담하는지**를 정한다.
|
|
1769
|
+
*
|
|
1770
|
+
* 두 층이다. 스토어 설정(`PATCH /v1/store`의 `refundPolicy`)이 기본값이고, 상품별 정책
|
|
1771
|
+
* (`POST/PUT /v1/products`의 `refundPolicy`)이 그 상품에만 덮어쓴다. 상품이 정하지 않은 항목은
|
|
1772
|
+
* 스토어 기본을 따르고, 스토어도 정하지 않았으면 `REFUND_POLICY_DEFAULTS`다.
|
|
1773
|
+
*
|
|
1774
|
+
* 한 주문에 정책이 섞이면 **상품별로 계산한다**. 배송비 묶음도 상품 단위다(주문서·장바구니의
|
|
1775
|
+
* 배송비 합산과 같은 규칙: 같은 상품의 주문상품이 한 묶음이고 묶음마다 배송비가 붙는다).
|
|
1776
|
+
*/
|
|
1777
|
+
const descriptions = {
|
|
1778
|
+
preShipmentDeliveryFeeRefund: "발송 전 취소로 배송 묶음(같은 상품의 주문상품)이 모두 취소되면 그 묶음의 배송비를 환불한다. false면 배송비를 환불하지 않는다. 기본 true",
|
|
1779
|
+
returnDeliveryFee: "단순 변심(구매자 귀책) 반품의 반품 배송비. 원 단위. 환불액에서 뺀다. 기본 0(무료). 상품별 정책에서 이 값을 주면 상품의 `returnFee`도 같은 값으로 맞춘다",
|
|
1780
|
+
exchangeDeliveryFee: "단순 변심(구매자 귀책) 교환의 교환 배송비. 원 단위. 구매자에게 청구할 금액을 안내값으로 싣는다. 기본 0(무료). 상품별 정책에서 이 값을 주면 상품의 `exchangeFee`도 같은 값으로 맞춘다",
|
|
1781
|
+
sellerFaultFreeShipping: "판매자 귀책(셀러 직권취소, 불량·오배송 반품)이면 배송비를 셀러가 부담한다 — 배송비를 환불하고 반품비를 받지 않는다. false면 구매자 귀책과 같은 규칙을 쓴다. 기본 true",
|
|
1782
|
+
conditionalFreeShortfallCharge: "조건부 무료배송(`CONDITIONAL_FREE`) 상품에서 일부 취소로 남은 금액이 무료 기준액에 미달하면 그 배송비를 환불액에서 뺀다. false면 추가 청구 없이 셀러가 부담한다. 기본 false"
|
|
1783
|
+
};
|
|
1784
|
+
/** 유효 환불 정책 — 스토어 기본 + 상품별 덮어쓰기를 합친 결과 */
|
|
1785
|
+
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)
|
|
1791
|
+
});
|
|
1792
|
+
/**
|
|
1793
|
+
* 스토어가 정하지 않았을 때 서버가 쓰는 값.
|
|
1794
|
+
*
|
|
1795
|
+
* `as const`가 아니라 `RefundPolicy`로 타입을 좁힌다 — 리터럴 타입이면 `Partial<typeof …>`로 일부만 바꿀 때
|
|
1796
|
+
* `true` 자리에 `false`를 넣을 수 없다.
|
|
1797
|
+
*/
|
|
1798
|
+
const REFUND_POLICY_DEFAULTS = {
|
|
1799
|
+
preShipmentDeliveryFeeRefund: true,
|
|
1800
|
+
returnDeliveryFee: 0,
|
|
1801
|
+
exchangeDeliveryFee: 0,
|
|
1802
|
+
sellerFaultFreeShipping: true,
|
|
1803
|
+
conditionalFreeShortfallCharge: false
|
|
1804
|
+
};
|
|
1805
|
+
/**
|
|
1806
|
+
* 부분 정책 — 스토어 설정 요청과 상품별 덮어쓰기가 쓴다. 준 항목만 바뀐다.
|
|
1807
|
+
*
|
|
1808
|
+
* `strictObject`라 모르는 키는 400이다. 오타(`returnFee` 등)를 조용히 무시하면 셀러는 저장됐다고
|
|
1809
|
+
* 믿는데 정책은 기본값으로 남는다.
|
|
1810
|
+
*/
|
|
1811
|
+
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)
|
|
1817
|
+
});
|
|
1818
|
+
/**
|
|
1819
|
+
* 유효 정책 해석 — 상품별 덮어쓰기 → 스토어 기본 → `REFUND_POLICY_DEFAULTS` 순이다.
|
|
1820
|
+
*
|
|
1821
|
+
* 반품비·교환비는 레거시 필드(`products.returnFee`·`exchangeFee`)와 **연결**한다. 상품이
|
|
1822
|
+
* `refundPolicy.returnDeliveryFee`를 정하면 그 값이 원천이고(서버가 `returnFee`도 같은 값으로 맞춘다),
|
|
1823
|
+
* 정하지 않았으면 레거시 값이 0보다 클 때 그 값을 쓴다. 0이면 스토어 기본을 따른다 —
|
|
1824
|
+
* 정책이 생기기 전에 만든 상품(반품비 0)이 스토어 기본을 물려받게 하는 규칙이다.
|
|
1825
|
+
*/
|
|
1826
|
+
function resolveRefundPolicy(storePolicy, product) {
|
|
1827
|
+
return {
|
|
1828
|
+
...REFUND_POLICY_DEFAULTS,
|
|
1829
|
+
...dropUndefined(storePolicy),
|
|
1830
|
+
...productRefundPolicyOverride(product) ?? {}
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* 상품의 **덮어쓰기 자체** — 레거시 반품비·교환비를 같은 형태로 승격한 값이다. 덮어쓰기가 없으면 null.
|
|
1835
|
+
*
|
|
1836
|
+
* `resolveRefundPolicy`가 합친 결과로는 "상품이 정한 값"과 "스토어 기본을 물려받은 값"을 가를 수 없다.
|
|
1837
|
+
* 관리 API 응답의 `refundPolicy`와 콘솔 폼의 덮어쓰기 스위치가 이 함수를 원천으로 쓴다 — 가르지 못하면
|
|
1838
|
+
* 스토어 기본을 쓰는 상품을 저장할 때 그 순간의 기본값이 상품에 박히거나, 레거시 값이 조용히 사라진다.
|
|
1839
|
+
*/
|
|
1840
|
+
function productRefundPolicyOverride(product) {
|
|
1841
|
+
const override = dropUndefined(product?.refundPolicy);
|
|
1842
|
+
const legacy = {};
|
|
1843
|
+
if (override.returnDeliveryFee === void 0 && (product?.returnFee ?? 0) > 0) legacy.returnDeliveryFee = product?.returnFee ?? 0;
|
|
1844
|
+
if (override.exchangeDeliveryFee === void 0 && (product?.exchangeFee ?? 0) > 0) legacy.exchangeDeliveryFee = product?.exchangeFee ?? 0;
|
|
1845
|
+
const merged = {
|
|
1846
|
+
...legacy,
|
|
1847
|
+
...override
|
|
1848
|
+
};
|
|
1849
|
+
if (product?.refundPolicy == null && Object.keys(merged).length === 0) return null;
|
|
1850
|
+
return merged;
|
|
1851
|
+
}
|
|
1852
|
+
/** `undefined` 값을 빼고 얕게 복사한다 — 전개 순서로 덮어쓸 때 `undefined`가 기본값을 지우지 않게 */
|
|
1853
|
+
function dropUndefined(patch) {
|
|
1854
|
+
if (!patch) return {};
|
|
1855
|
+
return Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== void 0));
|
|
1856
|
+
}
|
|
1857
|
+
/**
|
|
1858
|
+
* 수량 단위 부분 취소의 환불 기준액 — **누적 내림의 차분**이다.
|
|
1859
|
+
*
|
|
1860
|
+
* 원 단위 반올림 규칙: `floor(주문상품 금액 × 누적 수량 ÷ 전체 수량)`을 두 번 구해 그 차를 쓴다.
|
|
1861
|
+
* 부분 취소를 몇 번 나눠도 합이 주문상품 금액과 정확히 같아서 1원이 남거나 넘치지 않는다.
|
|
1862
|
+
* 할인은 이미 단가에 들어 있어(주문 단위 쿠폰이 없다) 별도 안분이 없다.
|
|
1863
|
+
*
|
|
1864
|
+
* @param totalPrice 주문상품 금액 (할인 반영 단가 × 전체 수량)
|
|
1865
|
+
* @param quantity 주문상품 전체 수량
|
|
1866
|
+
* @param settledQuantity 이미 취소·반품된 누적 수량
|
|
1867
|
+
* @param cancelQuantity 이번에 취소·반품할 수량
|
|
1868
|
+
*/
|
|
1869
|
+
function proratedRefundBase(totalPrice, quantity, settledQuantity, cancelQuantity) {
|
|
1870
|
+
if (quantity <= 0 || cancelQuantity <= 0) return 0;
|
|
1871
|
+
const before = Math.floor(totalPrice * settledQuantity / quantity);
|
|
1872
|
+
const after = Math.floor(totalPrice * (settledQuantity + cancelQuantity) / quantity);
|
|
1873
|
+
return Math.max(0, after - before);
|
|
1874
|
+
}
|
|
1875
|
+
//#endregion
|
|
1696
1876
|
//#region src/schemas/upload.ts
|
|
1697
1877
|
/**
|
|
1698
1878
|
* 업로드 용도. 허용 확장자와 크기 상한이 용도별로 다르다.
|
|
@@ -1858,6 +2038,7 @@ const productSchema = productSummarySchema.extend({
|
|
|
1858
2038
|
conditionalFreeAmount: z.number().int().nullable().optional(),
|
|
1859
2039
|
returnFee: z.number().int().optional(),
|
|
1860
2040
|
exchangeFee: z.number().int().optional(),
|
|
2041
|
+
refundPolicy: refundPolicyPatchSchema.nullable().optional().describe("상품별 환불 정책 덮어쓰기. null이면 스토어 기본 환불 정책을 쓴다"),
|
|
1861
2042
|
shippingAddressId: z.string().nullable().optional(),
|
|
1862
2043
|
returnAddressId: z.string().nullable().optional(),
|
|
1863
2044
|
createdAt: z.string().optional()
|
|
@@ -1999,8 +2180,9 @@ const productCreateRequestSchema = z.object({
|
|
|
1999
2180
|
deliveryType: deliveryTypeSchema.default("PAID").describe("배송비 유형. FREE 무료, PAID 유료, CONDITIONAL_FREE 조건부 무료"),
|
|
2000
2181
|
deliveryFee: z.number().int().default(0).describe("배송비. 원 단위"),
|
|
2001
2182
|
conditionalFreeAmount: z.number().int().optional().describe("CONDITIONAL_FREE일 때 무료 배송이 되는 주문 금액. 원 단위"),
|
|
2002
|
-
returnFee: z.number().int().default(0).describe("반품 배송비. 원
|
|
2003
|
-
exchangeFee: z.number().int().default(0).describe("교환 배송비. 원
|
|
2183
|
+
returnFee: z.number().int().default(0).describe("반품 배송비. 원 단위. `refundPolicy.returnDeliveryFee`와 같은 값이다"),
|
|
2184
|
+
exchangeFee: z.number().int().default(0).describe("교환 배송비. 원 단위. `refundPolicy.exchangeDeliveryFee`와 같은 값이다"),
|
|
2185
|
+
refundPolicy: refundPolicyPatchSchema.nullish().describe("상품별 환불 정책 — 준 항목만 스토어 기본을 덮어쓴다. `null`이나 생략은 스토어 기본을 그대로 쓴다는 뜻이다. `returnDeliveryFee`·`exchangeDeliveryFee`를 주면 `returnFee`·`exchangeFee`도 같은 값으로 맞춘다"),
|
|
2004
2186
|
shippingAddressId: z.string().optional(),
|
|
2005
2187
|
returnAddressId: z.string().optional()
|
|
2006
2188
|
}).extend(optionModelRequestSchema.shape);
|
|
@@ -2116,6 +2298,16 @@ const analyticsOriginSchema = z.string().trim().max(255).refine(isWebOrigin, "ht
|
|
|
2116
2298
|
const MAX_ANALYTICS_ALLOWED_ORIGINS = 20;
|
|
2117
2299
|
/** 자동 배송완료·자동 구매확정 대기일 상한 */
|
|
2118
2300
|
const MAX_AUTO_TRANSITION_DAYS = 30;
|
|
2301
|
+
/**
|
|
2302
|
+
* 약관 버전 — 스토어가 정하는 문자열이다(`1`·`2`·`2026-09-26`·`v1.2` 등). 형식은 강제하지 않고 값이 다르면 다른 버전이다.
|
|
2303
|
+
* 올리면 그 약관에 동의한 구매자의 `reconsentRequired`가 켜지고, 재동의가 이력에 남는다. 되돌리면 재동의 요구도 풀린다.
|
|
2304
|
+
*/
|
|
2305
|
+
const policyVersionSchema = z.string().trim().min(1).max(20).describe("약관 버전 문자열(1~20자). 예: `1`, `2026-09-26`");
|
|
2306
|
+
/**
|
|
2307
|
+
* 약관 문서 주소 — 구매자에게 보여 주는 약관 본문의 주소다. 동의 시점 값이 이력 행에 복사되므로
|
|
2308
|
+
* 나중에 주소를 바꿔도 "무엇에 동의했는지"가 남는다. `null`로 지울 수 있다.
|
|
2309
|
+
*/
|
|
2310
|
+
const policyDocumentUrlSchema = z.url().max(500).refine((value) => value.startsWith("https://"), "https 주소만 쓸 수 있어요").nullable();
|
|
2119
2311
|
const autoDeliverDaysDescription = "발송 후 자동 배송완료까지의 일수(0~30, 기본 7). 발송(`DISPATCHED`)·배송중(`DELIVERING`) 주문상품을 이 기간이 지나면 배송완료(`DELIVERED`)로 바꾼다. `0`이면 자동 배송완료를 하지 않는다";
|
|
2120
2312
|
const autoConfirmDaysDescription = "배송완료 후 자동 구매확정까지의 일수(0~30, 기본 7). 배송완료 시점에 구매확정 예정일(`autoDecisionDate`)을 이 값으로 잡고, 그 날짜가 지나면 구매확정(`PURCHASE_DECIDED`)으로 바꾼다. 진행 중인 클레임이 있으면 건너뛴다. `0`이면 자동 구매확정을 하지 않는다";
|
|
2121
2313
|
/** `PATCH /v1/store` 본문 — 바꿀 필드만 보낸다 */
|
|
@@ -2128,7 +2320,12 @@ const updateStoreRequestSchema = z.object({
|
|
|
2128
2320
|
storefrontOrigins: z.array(analyticsOriginSchema).max(20).optional().describe("스토어프론트 도메인(최대 20개) — 소셜 로그인 뒤 돌아갈 주소와 방문 분석 수집을 함께 제한한다. `analyticsAllowedOrigins`와 같은 목록이다(둘 다 주면 이 값이 이긴다)"),
|
|
2129
2321
|
guestCheckoutEnabled: z.boolean().optional().describe("비회원 주문 허용. false(회원만)면 로그인하지 않은 구매자의 주문서 생성·결제 요청이 403 `GUEST_CHECKOUT_DISABLED`다. 장바구니 담기와 이미 받은 비회원 주문의 조회·취소는 막지 않는다"),
|
|
2130
2322
|
autoDeliverDays: z.number().int().min(0).max(30).optional().describe(autoDeliverDaysDescription),
|
|
2131
|
-
autoConfirmDays: z.number().int().min(0).max(30).optional().describe(autoConfirmDaysDescription)
|
|
2323
|
+
autoConfirmDays: z.number().int().min(0).max(30).optional().describe(autoConfirmDaysDescription),
|
|
2324
|
+
refundPolicy: refundPolicyPatchSchema.optional().describe("스토어 기본 환불 정책 — 준 항목만 바꾼다. 상품별 정책(`products.refundPolicy`)이 없는 상품에 적용된다"),
|
|
2325
|
+
termsVersion: policyVersionSchema.optional().describe("이용약관 버전. 올리면 이 약관에 동의한 구매자에게 재동의를 요구한다(`GET /storefront/v1/me`의 `reconsentRequired`)"),
|
|
2326
|
+
privacyVersion: policyVersionSchema.optional().describe("개인정보 수집이용 동의 버전. 올리면 구매자에게 재동의를 요구한다"),
|
|
2327
|
+
termsUrl: policyDocumentUrlSchema.optional().describe("이용약관 문서 주소(https). 동의 시점의 값이 동의 이력에 복사된다. `null`을 주면 지운다"),
|
|
2328
|
+
privacyUrl: policyDocumentUrlSchema.optional().describe("개인정보 수집이용 동의 문서 주소(https). `null`을 주면 지운다")
|
|
2132
2329
|
}).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
|
|
2133
2330
|
const storeSchema = z.object({
|
|
2134
2331
|
storeId: z.string(),
|
|
@@ -2148,6 +2345,13 @@ const storeSchema = z.object({
|
|
|
2148
2345
|
guestCheckoutEnabled: z.boolean().describe("비회원 주문 허용. false면 회원만 주문할 수 있다"),
|
|
2149
2346
|
autoDeliverDays: z.number().int().describe(autoDeliverDaysDescription),
|
|
2150
2347
|
autoConfirmDays: z.number().int().describe(autoConfirmDaysDescription),
|
|
2348
|
+
refundPolicy: refundPolicySchema.describe("스토어 기본 환불 정책. 스토어가 정하지 않은 항목은 플랫폼 기본값으로 채워 항상 전부 싣는다"),
|
|
2349
|
+
termsVersion: z.string().describe("현재 이용약관 버전. 가입·재동의가 이 값으로 이력에 남는다"),
|
|
2350
|
+
privacyVersion: z.string().describe("현재 개인정보 수집이용 동의 버전"),
|
|
2351
|
+
termsVersionUpdatedAt: z.string().nullable().describe("이용약관 버전을 마지막으로 바꾼 시각. 바꾼 적이 없으면 null"),
|
|
2352
|
+
privacyVersionUpdatedAt: z.string().nullable(),
|
|
2353
|
+
termsUrl: z.string().nullable().describe("이용약관 문서 주소. 정하지 않았으면 null이고 동의 이력에도 주소가 남지 않는다"),
|
|
2354
|
+
privacyUrl: z.string().nullable().describe("개인정보 수집이용 동의 문서 주소"),
|
|
2151
2355
|
memberCount: z.number().int(),
|
|
2152
2356
|
createdAt: z.string()
|
|
2153
2357
|
});
|
|
@@ -2500,6 +2704,8 @@ function createStoreClient(options) {
|
|
|
2500
2704
|
list: (params) => storeHttp.request("GET", "/customers", pageSchema(customerSummarySchema), { query: params }),
|
|
2501
2705
|
get: (customerId) => storeHttp.request("GET", path`/customers/${customerId}`, customerDetailSchema),
|
|
2502
2706
|
orders: (customerId, params) => storeHttp.request("GET", path`/customers/${customerId}/orders`, pageSchema(customerOrderSchema), { query: params }),
|
|
2707
|
+
/** 동의 이력 — 최근 순. 가입·재동의·마케팅 변경이 한 줄씩 남는다 */
|
|
2708
|
+
consents: (customerId, params) => storeHttp.request("GET", path`/customers/${customerId}/consents`, pageSchema(customerConsentSchema), { query: params }),
|
|
2503
2709
|
withdraw: (customerId, body) => storeHttp.requestVoid("POST", path`/customers/${customerId}/withdraw`, { body: withdrawCustomerRequestSchema.parse(body) })
|
|
2504
2710
|
},
|
|
2505
2711
|
customerInquiries: {
|
|
@@ -2875,6 +3081,11 @@ const claimWebhookEventDataSchema = z.object({
|
|
|
2875
3081
|
orderItemId: z.string().describe("클레임 대상 주문 상품 ID"),
|
|
2876
3082
|
claimType: claimTypeSchema.describe("클레임 유형"),
|
|
2877
3083
|
status: claimStatusSchema.describe("이벤트 발생 시점의 클레임 상태"),
|
|
3084
|
+
quantity: z.number().int().optional().default(0).describe("클레임 대상 수량. 이 필드가 없는 이전 이벤트는 0으로 읽는다"),
|
|
3085
|
+
refundAmount: z.number().int().nullable().optional().default(null).describe("환불액 (원). 배송비 환불을 포함하고 배송비 차감·추가 차감을 뺀 실제 금액이다. 환불이 확정되지 않은 접수 이벤트는 예상 환불액이고, 교환처럼 환불이 없으면 null이다"),
|
|
3086
|
+
deliveryFeeRefundAmount: z.number().int().optional().default(0).describe("환불액에 포함된 배송비 (원). 이 필드가 없는 이전 이벤트는 0으로 읽는다"),
|
|
3087
|
+
deliveryFeeChargeAmount: z.number().int().optional().default(0).describe("환불액에서 뺀 배송비 (원) — 반품·교환 배송비와 조건부 무료배송 미달 차감의 합. 셀러가 승인에 넣은 추가 차감은 `deductAmount`로 따로 온다. 이 필드가 없는 이전 이벤트는 0으로 읽는다"),
|
|
3088
|
+
deductAmount: z.number().int().optional().default(0).describe("환불액에서 뺀 추가 차감 (원) — 셀러가 클레임 승인에 넣은 금액이다(상품 훼손 등). 배송비 차감과 별개이므로 `deliveryFeeChargeAmount`와 더해서 뺀다. 접수 이벤트와 이 필드가 없는 이전 이벤트는 0이다"),
|
|
2878
3089
|
testPayment: z.boolean().optional().default(false).describe("테스트 결제(샌드박스 결제) 주문의 클레임인가. 이 필드가 없는 이전 이벤트는 false로 읽는다")
|
|
2879
3090
|
});
|
|
2880
3091
|
const inquiryWebhookEventDataSchema = z.object({
|
|
@@ -3085,4 +3296,4 @@ function createStoreSession(options) {
|
|
|
3085
3296
|
};
|
|
3086
3297
|
}
|
|
3087
3298
|
//#endregion
|
|
3088
|
-
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, 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, createPkcePair, createStoreClient, createStoreSession, customerAddressSchema, 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, portOneChannelSchema, portOneCredentialsInputSchema, productCreateRequestSchema, productImageRejection, productImageUrlSchema, productListQuerySchema, productOutOfStockWebhookEventDataSchema, productOutOfStockWebhookEventSchema, productPatchRequestSchema, productSchema, productSortSchema, productStatusSchema, productSummarySchema, productVariantRequestSchema, productVariantSchema, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, refreshUserToken, rejectClaimRequestSchema, 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 };
|
|
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 };
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -70,6 +70,8 @@ import {
|
|
|
70
70
|
} from "./schemas/claim";
|
|
71
71
|
import { bulkResultSchema, type PageParams, pageSchema } from "./schemas/common";
|
|
72
72
|
import {
|
|
73
|
+
type ConsentKind,
|
|
74
|
+
customerConsentSchema,
|
|
73
75
|
customerDetailSchema,
|
|
74
76
|
type customerListQuerySchema,
|
|
75
77
|
customerOrderSchema,
|
|
@@ -708,6 +710,14 @@ export function createStoreClient(options: StoreClientOptions) {
|
|
|
708
710
|
query: params as Query,
|
|
709
711
|
},
|
|
710
712
|
),
|
|
713
|
+
/** 동의 이력 — 최근 순. 가입·재동의·마케팅 변경이 한 줄씩 남는다 */
|
|
714
|
+
consents: (customerId: string, params?: PageParams & { kind?: ConsentKind }) =>
|
|
715
|
+
storeHttp.request(
|
|
716
|
+
"GET",
|
|
717
|
+
path`/customers/${customerId}/consents`,
|
|
718
|
+
pageSchema(customerConsentSchema),
|
|
719
|
+
{ query: params as Query },
|
|
720
|
+
),
|
|
711
721
|
withdraw: (customerId: string, body: WithdrawCustomerRequest) =>
|
|
712
722
|
storeHttp.requestVoid("POST", path`/customers/${customerId}/withdraw`, {
|
|
713
723
|
body: withdrawCustomerRequestSchema.parse(body),
|
package/src/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ export * from "./schemas/misc";
|
|
|
24
24
|
export * from "./schemas/order";
|
|
25
25
|
export * from "./schemas/payment";
|
|
26
26
|
export * from "./schemas/product";
|
|
27
|
+
export * from "./schemas/refund-policy";
|
|
27
28
|
export * from "./schemas/scope";
|
|
28
29
|
export * from "./schemas/store";
|
|
29
30
|
export * from "./schemas/upload";
|
package/src/schemas/claim.ts
CHANGED
|
@@ -41,8 +41,24 @@ export const claimSchema = z.object({
|
|
|
41
41
|
reason: claimReasonSchema,
|
|
42
42
|
reasonDetail: z.string().nullable(),
|
|
43
43
|
responsibility: z.enum(["BUYER", "SELLER"]),
|
|
44
|
-
claimDeliveryFee: z.number().int(),
|
|
45
|
-
expectedRefundAmount: z
|
|
44
|
+
claimDeliveryFee: z.number().int().describe("구매자가 부담하는 반품·교환 배송비. 원 단위"),
|
|
45
|
+
expectedRefundAmount: z
|
|
46
|
+
.number()
|
|
47
|
+
.int()
|
|
48
|
+
.nullable()
|
|
49
|
+
.describe(
|
|
50
|
+
"접수 시점에 계산한 예상 환불액 — 수량 비율 상품 금액 − 반품 배송비 − 조건부 무료배송 미달 차감. " +
|
|
51
|
+
"**배송비 환불은 포함되지 않고 `expectedDeliveryFeeRefundAmount`로 따로 온다**" +
|
|
52
|
+
"(승인 시점의 배송 묶음 상태로 확정되기 때문이다). 교환은 환불이 없어 null이다",
|
|
53
|
+
),
|
|
54
|
+
expectedDeliveryFeeRefundAmount: z
|
|
55
|
+
.number()
|
|
56
|
+
.int()
|
|
57
|
+
.nullable()
|
|
58
|
+
.describe(
|
|
59
|
+
"접수 시점에 계산한 예상 배송비 환불액. 배송 묶음(같은 상품의 주문상품)이 모두 취소되거나 " +
|
|
60
|
+
"판매자 귀책일 때만 0보다 크다. 이 필드가 생기기 전에 접수된 클레임은 null이다",
|
|
61
|
+
),
|
|
46
62
|
exchangeOption: z.object({ optionId: z.string(), optionName: z.string() }).nullable(),
|
|
47
63
|
collect: z
|
|
48
64
|
.object({
|
|
@@ -119,8 +135,26 @@ export type RejectClaimRequest = z.infer<typeof rejectClaimRequestSchema>;
|
|
|
119
135
|
|
|
120
136
|
export const approveClaimResultSchema = z.object({
|
|
121
137
|
claimId: z.string(),
|
|
122
|
-
refundAmount: z
|
|
123
|
-
|
|
138
|
+
refundAmount: z
|
|
139
|
+
.number()
|
|
140
|
+
.int()
|
|
141
|
+
.describe(
|
|
142
|
+
"실제 환불한 금액 — 수량 비율 상품 금액 + 배송비 환불 − 반품 배송비 − 조건부 무료배송 미달 차감 − " +
|
|
143
|
+
"추가 차감(`deductAmount`)",
|
|
144
|
+
),
|
|
145
|
+
deductAmount: z.number().int().describe("승인 때 셀러가 추가로 차감한 금액"),
|
|
146
|
+
quantity: z.number().int().describe("환불한 수량"),
|
|
147
|
+
deliveryFeeRefundAmount: z
|
|
148
|
+
.number()
|
|
149
|
+
.int()
|
|
150
|
+
.describe("환불에 포함된 배송비. 배송 묶음 전량 취소나 판매자 귀책일 때만 0보다 크다"),
|
|
151
|
+
deliveryFeeChargeAmount: z
|
|
152
|
+
.number()
|
|
153
|
+
.int()
|
|
154
|
+
.describe(
|
|
155
|
+
"환불액에서 뺀 **배송비** — 반품·교환 배송비 + 조건부 무료배송 미달 차감. " +
|
|
156
|
+
"추가 차감(`deductAmount`)은 포함하지 않는다",
|
|
157
|
+
),
|
|
124
158
|
refundedAt: z.string(),
|
|
125
159
|
});
|
|
126
160
|
|
package/src/schemas/customer.ts
CHANGED
|
@@ -58,6 +58,75 @@ export const customerAddressSchema = z.object({
|
|
|
58
58
|
address2: z.string().nullable(),
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
+
// ── 동의 이력 (이슈 #26) ────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
/** 동의 종류 — 이용약관·개인정보 수집이용은 가입 필수, 마케팅 수신은 선택 */
|
|
64
|
+
export const consentKindSchema = z.enum(["TERMS", "PRIVACY", "MARKETING"]);
|
|
65
|
+
export type ConsentKind = z.infer<typeof consentKindSchema>;
|
|
66
|
+
|
|
67
|
+
export const consentActionSchema = z.enum(["AGREED", "WITHDRAWN"]);
|
|
68
|
+
export type ConsentAction = z.infer<typeof consentActionSchema>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 동의가 일어난 경로. 값이 추가될 수 있어 모르는 값은 그대로 보여 준다.
|
|
72
|
+
* `SIGNUP` 비밀번호 가입 · `SOCIAL_SIGNUP` 소셜 가입 · `DELEGATED` 셀러 자체 회원 연동 ·
|
|
73
|
+
* `RECONSENT` 약관 개정 재동의 · `MEMBER_UPDATE` 구매자가 직접 변경 · `SELLER` 셀러가 처리
|
|
74
|
+
*/
|
|
75
|
+
export const consentSourceSchema = z.enum([
|
|
76
|
+
"SIGNUP",
|
|
77
|
+
"SOCIAL_SIGNUP",
|
|
78
|
+
"DELEGATED",
|
|
79
|
+
"RECONSENT",
|
|
80
|
+
"MEMBER_UPDATE",
|
|
81
|
+
"SELLER",
|
|
82
|
+
]);
|
|
83
|
+
export type ConsentSource = z.infer<typeof consentSourceSchema>;
|
|
84
|
+
|
|
85
|
+
/** 동의 이력 한 줄 — 추가만 되고 지워지지 않는다(구매자 탈퇴 시에만 함께 지워진다) */
|
|
86
|
+
export const customerConsentSchema = z.object({
|
|
87
|
+
consentId: z.string(),
|
|
88
|
+
kind: consentKindSchema,
|
|
89
|
+
/** 동의한 약관 버전. 마케팅은 버전이 없어 null */
|
|
90
|
+
version: z.string().nullable(),
|
|
91
|
+
/** 동의 시점의 약관 문서 주소. 스토어가 주소를 정하지 않았거나 마케팅이면 null */
|
|
92
|
+
documentUrl: z.string().nullable(),
|
|
93
|
+
action: consentActionSchema,
|
|
94
|
+
source: consentSourceSchema,
|
|
95
|
+
occurredAt: z.string(),
|
|
96
|
+
});
|
|
97
|
+
export type CustomerConsent = z.infer<typeof customerConsentSchema>;
|
|
98
|
+
|
|
99
|
+
/** 종류별 현재 동의 상태 */
|
|
100
|
+
export const customerConsentStateSchema = z.object({
|
|
101
|
+
kind: consentKindSchema,
|
|
102
|
+
agreed: z.boolean(),
|
|
103
|
+
/** 동의한 약관 버전. 마케팅이거나 이력이 없으면 null */
|
|
104
|
+
agreedVersion: z.string().nullable(),
|
|
105
|
+
/** 스토어의 현재 약관 버전. 마케팅은 null */
|
|
106
|
+
currentVersion: z.string().nullable(),
|
|
107
|
+
/** 스토어가 정한 현재 약관 문서 주소. 정하지 않았거나 마케팅이면 null */
|
|
108
|
+
currentDocumentUrl: z.string().nullable(),
|
|
109
|
+
updatedAt: z.string().nullable(),
|
|
110
|
+
/** 약관이 개정돼 다시 받아야 하는가. 마케팅은 항상 false */
|
|
111
|
+
reconsentRequired: z.boolean(),
|
|
112
|
+
});
|
|
113
|
+
export type CustomerConsentState = z.infer<typeof customerConsentStateSchema>;
|
|
114
|
+
|
|
115
|
+
export const customerConsentsSchema = z.object({
|
|
116
|
+
terms: customerConsentStateSchema,
|
|
117
|
+
privacy: customerConsentStateSchema,
|
|
118
|
+
marketing: customerConsentStateSchema,
|
|
119
|
+
/** 필수 동의 중 하나라도 현재 버전이 아니면 true */
|
|
120
|
+
reconsentRequired: z.boolean(),
|
|
121
|
+
});
|
|
122
|
+
export type CustomerConsents = z.infer<typeof customerConsentsSchema>;
|
|
123
|
+
|
|
124
|
+
/** `GET /v1/customers/{id}/consents` 쿼리 — 최근 순이다 */
|
|
125
|
+
export const customerConsentListQuerySchema = z.object({
|
|
126
|
+
kind: consentKindSchema.optional().describe("동의 종류 필터. 생략하면 전체"),
|
|
127
|
+
...pageQueryShape(),
|
|
128
|
+
});
|
|
129
|
+
|
|
61
130
|
/** 구매자 상세 — 휴대폰 전체를 보여 준다 */
|
|
62
131
|
export const customerDetailSchema = z.object({
|
|
63
132
|
customerId: z.string(),
|
|
@@ -76,6 +145,9 @@ export const customerDetailSchema = z.object({
|
|
|
76
145
|
}),
|
|
77
146
|
)
|
|
78
147
|
.describe("로그인 방법 — 이메일·비밀번호(`password`)와 연결된 소셜 계정"),
|
|
148
|
+
consents: customerConsentsSchema.describe(
|
|
149
|
+
"약관·개인정보·마케팅 동의의 현재 상태. 이력은 `GET /v1/customers/{customerId}/consents`",
|
|
150
|
+
),
|
|
79
151
|
addresses: z.array(customerAddressSchema),
|
|
80
152
|
stats: customerStatsSchema.extend({
|
|
81
153
|
canceledOrReturnedCount: z.number().int().describe("취소된 주문 상품 + 완료된 반품 수"),
|
package/src/schemas/order.ts
CHANGED
|
@@ -40,10 +40,18 @@ export const orderItemSchema = z.object({
|
|
|
40
40
|
optionId: z.string().nullable(),
|
|
41
41
|
optionName: z.string().nullable(),
|
|
42
42
|
sellerCode: z.string().nullable(),
|
|
43
|
-
quantity: z.number().int(),
|
|
43
|
+
quantity: z.number().int().describe("주문 수량"),
|
|
44
|
+
canceledQuantity: z
|
|
45
|
+
.number()
|
|
46
|
+
.int()
|
|
47
|
+
.describe("취소·반품으로 환불된 누적 수량. 수량 단위 부분 취소가 없었으면 0이다"),
|
|
48
|
+
activeQuantity: z
|
|
49
|
+
.number()
|
|
50
|
+
.int()
|
|
51
|
+
.describe("살아 있는 수량 (`quantity` − `canceledQuantity`). 0이면 주문상품이 전량 취소됐다"),
|
|
44
52
|
unitPrice: z.number().int(),
|
|
45
53
|
discountAmount: z.number().int(),
|
|
46
|
-
totalPrice: z.number().int(),
|
|
54
|
+
totalPrice: z.number().int().describe("주문상품 금액 (할인 반영 단가 × 주문 수량)"),
|
|
47
55
|
hold: z.object({ reason: z.string(), expectedDispatchDate: z.string() }).nullable(),
|
|
48
56
|
autoDecisionDate: z.string().nullable(),
|
|
49
57
|
sellerMemo: z.string().nullable(),
|
|
@@ -256,6 +264,15 @@ export type HoldOrderItemRequest = z.infer<typeof holdOrderItemRequestSchema>;
|
|
|
256
264
|
export const cancelBySellerRequestSchema = z.object({
|
|
257
265
|
reason: z.enum(["OUT_OF_STOCK", "PRICE_ERROR", "DELIVERY_IMPOSSIBLE", "ETC"]),
|
|
258
266
|
detail: z.string().max(500).optional(),
|
|
267
|
+
quantity: z
|
|
268
|
+
.number()
|
|
269
|
+
.int()
|
|
270
|
+
.min(1)
|
|
271
|
+
.optional()
|
|
272
|
+
.describe(
|
|
273
|
+
"취소할 수량. 생략하면 남은 수량 전체다. 남은 수량보다 크면 400 `INVALID_QUANTITY`. " +
|
|
274
|
+
"일부만 취소하면 주문상품은 상태를 유지한 채 `canceledQuantity`가 늘고, 전 수량이 소진되면 `CANCELED`가 된다",
|
|
275
|
+
),
|
|
259
276
|
});
|
|
260
277
|
|
|
261
278
|
export type CancelBySellerRequest = z.infer<typeof cancelBySellerRequestSchema>;
|
|
@@ -263,7 +280,22 @@ export type CancelBySellerRequest = z.infer<typeof cancelBySellerRequestSchema>;
|
|
|
263
280
|
/** `POST /v1/order-items/{orderItemId}/cancel` 응답 — 셀러 직권취소 환불 결과 */
|
|
264
281
|
export const cancelBySellerResultSchema = z.object({
|
|
265
282
|
orderItemId: z.string(),
|
|
266
|
-
refundAmount: z
|
|
283
|
+
refundAmount: z
|
|
284
|
+
.number()
|
|
285
|
+
.int()
|
|
286
|
+
.describe("실제 환불한 금액 — 수량 비율 상품 금액 + 배송비 환불 − 조건부 무료배송 미달 차감"),
|
|
287
|
+
quantity: z.number().int().describe("취소한 수량"),
|
|
288
|
+
canceledQuantity: z.number().int().describe("취소 후 누적 취소 수량"),
|
|
289
|
+
deliveryFeeRefundAmount: z
|
|
290
|
+
.number()
|
|
291
|
+
.int()
|
|
292
|
+
.describe(
|
|
293
|
+
"환불에 포함된 배송비. 배송 묶음(같은 상품)이 모두 취소됐고 환불 정책이 켜져 있을 때만 0보다 크다",
|
|
294
|
+
),
|
|
295
|
+
deliveryFeeChargeAmount: z
|
|
296
|
+
.number()
|
|
297
|
+
.int()
|
|
298
|
+
.describe("조건부 무료배송 기준 미달로 환불액에서 뺀 배송비. 정책이 꺼져 있으면 항상 0이다"),
|
|
267
299
|
refundedAt: z.string(),
|
|
268
300
|
});
|
|
269
301
|
|