@sayren/store-sdk 0.30.4 → 0.30.5

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.mjs CHANGED
@@ -932,7 +932,8 @@ const approveClaimResultSchema = z.object({
932
932
  couponChargeAmount: z.number().int().optional().default(0).describe("환불액에서 뺀 쿠폰 조건 미달 차감. 남은 주문상품이 쿠폰 조건을 잃었을 때만 0보다 크다. 서버는 항상 싣는다"),
933
933
  couponChargeRefundAmount: z.number().int().optional().default(0).describe("환불액에 더한, 앞선 환불에서 뺀 쿠폰 차감을 되돌린 몫. 서버는 항상 싣는다"),
934
934
  pointRefundAmount: z.number().int().optional().default(0).describe("돌려준 적립금 (원, #93) — 결제에 쓴 적립금 중 이번 취소·반품 수량의 몫이다. 현금 환불(`refundAmount`)과 별개다. 차감은 현금에서 먼저 빼고 모자란 몫만 여기서 뺀다. 적립금을 쓰지 않은 주문과 이 필드가 없는 이전 응답·이벤트는 0으로 읽는다"),
935
- refundedAt: z.string()
935
+ refundedAt: z.string(),
936
+ refundHeld: z.boolean().optional().default(false).describe("결제 환불을 대기로 남겼다(`holdRefund`, #115). 결제 상세에서 환불 처리한다")
936
937
  });
937
938
  //#endregion
938
939
  //#region src/schemas/fulfillment.ts
@@ -2737,8 +2738,8 @@ const flowPresetSummarySchema = z.object({
2737
2738
  description: z.string(),
2738
2739
  availability: z.enum(["AVAILABLE", "BLOCKED"]).describe("BLOCKED면 의존 이슈(dependsOn)가 끝나야 설치할 수 있다"),
2739
2740
  dependsOn: z.array(z.string()),
2740
- requires: flowDocumentSchema.describe("프리셋이 쓰는 Core 기능(진행 단위·이행 방식·주문 입력 등)"),
2741
- variables: z.array(flowDocumentSchema).describe("셀러가 값만 입력하는 변수 정의")
2741
+ requires: flowDocumentSchema.describe("흐름 설정(진행 단위·이행 방식)"),
2742
+ variables: z.array(flowDocumentSchema).describe("늘 빈 목록이다 — 프리셋은 빈 흐름을 편집한 그래프이고 값은 노드 설정 안에 있다(#115)")
2742
2743
  });
2743
2744
  const commerceFlowSummarySchema = z.object({
2744
2745
  flowId: z.string(),
@@ -2797,12 +2798,12 @@ const createCommerceFlowRequestSchema = z.object({
2797
2798
  key: z.string().regex(/^[a-z][a-z0-9-]{1,48}$/).describe("상점 안 유일한 키(소문자·숫자·하이픈)"),
2798
2799
  name: z.string().min(1).max(60).optional(),
2799
2800
  presetKey: z.string().optional().describe("설치할 프리셋. 없으면 빈 플로우"),
2800
- variables: z.record(z.string(), z.unknown()).optional().describe("프리셋 변수 값")
2801
+ variables: z.record(z.string(), z.unknown()).optional().describe("쓰지 않는다(무시). 값은 그래프의 노드 설정 안에 있다(#115)")
2801
2802
  });
2802
2803
  const saveFlowDraftRequestSchema = z.object({
2803
2804
  graph: flowDocumentSchema,
2804
- definition: flowDocumentSchema.optional(),
2805
- variables: z.record(z.string(), z.unknown()).optional()
2805
+ definition: flowDocumentSchema.optional().describe("흐름 설정 `requires`(progression·fulfillmentMethods)와 행동 입력 칸 `actionInputs`"),
2806
+ variables: z.record(z.string(), z.unknown()).optional().describe("쓰지 않는다(무시). 값은 그래프의 노드 설정 안에 있다(#115)")
2806
2807
  });
2807
2808
  const flowIssueSchema = z.object({
2808
2809
  code: z.string(),
@@ -2925,7 +2926,21 @@ const flowNodeTypesSchema = z.object({
2925
2926
  version: z.number().int(),
2926
2927
  effect: z.string().describe("local 같은 트랜잭션 · afterCommit 커밋 뒤 · external 트랜잭션 밖"),
2927
2928
  configSchema: z.record(z.string(), z.unknown())
2928
- }))
2929
+ })),
2930
+ platformActions: z.array(z.object({
2931
+ key: z.string(),
2932
+ side: z.enum(["buyer", "seller"]),
2933
+ label: z.string(),
2934
+ mode: z.enum([
2935
+ "INSTANT",
2936
+ "REQUEST",
2937
+ "VIEW"
2938
+ ]),
2939
+ subflow: z.string().optional().describe("켜면 붙는 클레임 하위 흐름"),
2940
+ window: z.boolean().describe("기간(within, 단계 진입 뒤 N일)을 둘 수 있다"),
2941
+ fee: z.boolean().describe("수수료(deduct)를 둘 수 있다"),
2942
+ listed: z.boolean().describe("권한 표에 행으로 보인다")
2943
+ })).optional().default([]).describe("노드 권한 표에 켤 수 있는 플랫폼 행동(#115) — 편집기는 이 목록으로 행을 그린다")
2929
2944
  });
2930
2945
  //#endregion
2931
2946
  //#region src/schemas/promotion.ts
@@ -4575,6 +4590,7 @@ const paymentRecordSchema = z.object({
4575
4590
  status: paymentRecordStatusSchema,
4576
4591
  amount: z.number().int().describe("결제 금액"),
4577
4592
  refundedAmount: z.number().int().describe("환불 완료 금액 합계. 실패한 환불은 빼고 센다"),
4593
+ heldRefundAmount: z.number().int().optional().default(0).describe("환불 대기 금액 합계(#115) — 주문만 취소하고 아직 환불하지 않은 몫. 결제 상세에서 환불 처리한다"),
4578
4594
  provider: pgProviderSchema.nullable().describe("승인한 PG. 승인 전에 끝났으면 마지막 시도의 PG"),
4579
4595
  method: pgPaymentMethodSchema.nullable().describe("실제 결제수단. 모르면 요청 수단"),
4580
4596
  easyPayProvider: easyPayProviderResponseSchema.nullable().optional().default(null).describe("간편결제사. `method`가 `EASY_PAY`일 때만 값이 있고, PG가 알려 주지 않았으면 요청한 간편결제사다. 그 밖의 결제수단과 간편결제 이전 결제는 null. 서버는 항상 싣는다. 현재 값은 `NAVERPAY`·`KAKAOPAY`·`TOSSPAY`·`PAYCO`이고 값이 추가될 수 있어 문자열로 받는다"),
@@ -4615,7 +4631,7 @@ const paymentRefundRecordSchema = z.object({
4615
4631
  pointRefundAmount: z.number().int().optional().default(0).describe("같은 환불에서 돌려준 적립금 (#93). 적립금을 쓰지 않은 결제는 0"),
4616
4632
  reason: z.string().describe("환불 사유 코드"),
4617
4633
  kind: z.string().describe("환불 원인 — SELLER_CANCEL·CLAIM·COMPENSATION·DUPLICATE. 새 값이 추가될 수 있다"),
4618
- status: z.string().describe("SUCCEEDED·FAILED"),
4634
+ status: z.string().describe("SUCCEEDED 환불됨 · FAILED 실패 · HELD 환불 대기(주문만 취소, #115) · PROCESSING 처리 중. 합계(`refundedAmount`)는 SUCCEEDED만 센다"),
4619
4635
  failMessage: z.string().nullable(),
4620
4636
  requestedAt: z.string(),
4621
4637
  completedAt: z.string().nullable()
@@ -4636,6 +4652,7 @@ const paymentListQuerySchema = z.object({
4636
4652
  method: z.string().optional().describe("실제 결제수단 필터"),
4637
4653
  keyword: z.string().optional().describe("결제 id·주문 id·PG 거래 id·시도 id·PG 주문번호(일치), 구매자명(포함)"),
4638
4654
  includeTest: z.string().optional().describe("테스트 결제 포함 여부 (`true`·`false`. 기본 false — 실결제만)"),
4655
+ refundHeld: z.string().optional().describe("`true`면 환불 대기가 있는 결제만(#115)"),
4639
4656
  page: z.string().optional().describe("페이지 번호 (1부터)"),
4640
4657
  size: z.string().optional().describe("페이지 크기 (기본 20, 최대 100)")
4641
4658
  });
@@ -4869,7 +4886,8 @@ const cancelBySellerRequestSchema = z.object({
4869
4886
  "ETC"
4870
4887
  ]),
4871
4888
  detail: z.string().max(500).optional(),
4872
- quantity: z.number().int().min(1).optional().describe("취소할 수량. 생략하면 남은 수량 전체다. 남은 수량보다 크면 400 `INVALID_QUANTITY`. 일부만 취소하면 주문상품은 상태를 유지한 채 `canceledQuantity`가 늘고, 전 수량이 소진되면 `CANCELED`가 된다")
4889
+ quantity: z.number().int().min(1).optional().describe("취소할 수량. 생략하면 남은 수량 전체다. 남은 수량보다 크면 400 `INVALID_QUANTITY`. 일부만 취소하면 주문상품은 상태를 유지한 채 `canceledQuantity`가 늘고, 전 수량이 소진되면 `CANCELED`가 된다"),
4890
+ holdRefund: z.boolean().optional().describe("true면 주문만 취소하고 결제 환불은 대기로 남긴다(#115). 정산·재고·적립금 반환은 그대로 하고, PG 환불은 결제 상세의 `POST /v1/payments/refunds/{refundId}/process`로 따로 한다. 생략하면 취소와 함께 환불한다")
4873
4891
  });
4874
4892
  /**
4875
4893
  * 제공 처리 요청 (이슈 #48) — `POST /v1/order-items/{orderItemId}/fulfill`. 배송 없는 주문상품(`MANUAL`)을
@@ -4892,7 +4910,8 @@ const cancelBySellerResultSchema = z.object({
4892
4910
  couponChargeAmount: z.number().int().optional().default(0).describe("쿠폰 조건 미달 차감. 판매자 취소는 차감하지 않으므로 늘 0이다. 서버는 항상 싣는다"),
4893
4911
  couponChargeRefundAmount: z.number().int().optional().default(0).describe("환불액에 더한, 앞선 환불에서 뺀 쿠폰 차감을 되돌린 몫. 서버는 항상 싣는다"),
4894
4912
  pointRefundAmount: z.number().int().optional().default(0).describe("돌려준 적립금 (원, #93) — 결제에 쓴 적립금 중 이번 취소·반품 수량의 몫이다. 현금 환불(`refundAmount`)과 별개다. 차감은 현금에서 먼저 빼고 모자란 몫만 여기서 뺀다. 적립금을 쓰지 않은 주문과 이 필드가 없는 이전 응답·이벤트는 0으로 읽는다"),
4895
- refundedAt: z.string()
4913
+ refundedAt: z.string().describe("환불을 요청한 시각. `refundHeld`면 취소 시각이고 환불은 아직 하지 않았다"),
4914
+ refundHeld: z.boolean().optional().default(false).describe("결제 환불을 대기로 남겼다(`holdRefund`). 결제 상세에서 환불 처리한다")
4896
4915
  });
4897
4916
  /** `PUT /v1/order-items/{orderItemId}/memo` 응답 — 빈 문자열로 저장하면 메모가 지워져 `null`이다 */
4898
4917
  const orderItemMemoResultSchema = z.object({
@@ -7141,8 +7160,12 @@ function createStoreClient(options) {
7141
7160
  status: Array.isArray(params?.status) ? params.status.join(",") : params?.status
7142
7161
  } }),
7143
7162
  get: (claimId) => storeHttp.request("GET", path`/claims/${claimId}`, claimDetailSchema),
7144
- approve: (claimId, deductAmount, idempotencyKey) => storeHttp.request("POST", path`/claims/${claimId}/approve`, approveClaimResultSchema, {
7145
- body: deductAmount !== void 0 ? { deductAmount } : {},
7163
+ /** `holdRefund`(#115)면 승인만 하고 결제 환불은 대기로 남긴다 — `payments.processRefund`로 따로 환불한다 */
7164
+ approve: (claimId, deductAmount, idempotencyKey, options = {}) => storeHttp.request("POST", path`/claims/${claimId}/approve`, approveClaimResultSchema, {
7165
+ body: {
7166
+ ...deductAmount !== void 0 ? { deductAmount } : {},
7167
+ ...options.holdRefund ? { holdRefund: true } : {}
7168
+ },
7146
7169
  headers: idempotency(idempotencyKey)
7147
7170
  }),
7148
7171
  reject: (claimId, body) => storeHttp.requestVoid("POST", path`/claims/${claimId}/reject`, { body: rejectClaimRequestSchema.parse(body) }),
@@ -7287,7 +7310,9 @@ get: (params) => storeHttp.request("GET", "/sales-report", salesReportSchema, {
7287
7310
  */
7288
7311
  list: (params = {}) => storeHttp.request("GET", "/payments", paymentRecordPageSchema, { query: params }),
7289
7312
  /** `GET /v1/payments/{paymentId}` — 시도·환불 이력 포함. 404 `PAYMENT_NOT_FOUND` */
7290
- get: (paymentId) => storeHttp.request("GET", path`/payments/${paymentId}`, paymentRecordDetailSchema)
7313
+ get: (paymentId) => storeHttp.request("GET", path`/payments/${paymentId}`, paymentRecordDetailSchema),
7314
+ /** `POST /v1/payments/refunds/{refundId}/process` — 대기 환불(`HELD`)을 PG로 환불한다(#115). 409 `REFUND_NOT_HELD` */
7315
+ processRefund: (refundId) => storeHttp.request("POST", path`/payments/refunds/${refundId}/process`, paymentRefundRecordSchema)
7291
7316
  },
7292
7317
  /**
7293
7318
  * 결제(PG) 설정 — **상점 플랫폼 OWNER 전용**. ADMIN·STAFF·PAT·M2M·3rd-party 앱 토큰은 스코프가 있어도
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sayren/store-sdk",
3
- "version": "0.30.4",
3
+ "version": "0.30.5",
4
4
  "main": "./dist/index.mjs",
5
5
  "types": "./dist/index.d.mts",
6
6
  "exports": {
package/src/client.ts CHANGED
@@ -193,6 +193,7 @@ import {
193
193
  paymentProviderVerificationSchema,
194
194
  paymentRecordDetailSchema,
195
195
  paymentRecordPageSchema,
196
+ paymentRefundRecordSchema,
196
197
  paymentSettingsSchema,
197
198
  pgEnvironmentSchema,
198
199
  pgProviderSchema,
@@ -972,9 +973,18 @@ export function createStoreClient(options: StoreClientOptions) {
972
973
  }),
973
974
  get: (claimId: string) =>
974
975
  storeHttp.request("GET", path`/claims/${claimId}`, claimDetailSchema),
975
- approve: (claimId: string, deductAmount?: number, idempotencyKey?: string) =>
976
+ /** `holdRefund`(#115)면 승인만 하고 결제 환불은 대기로 남긴다 — `payments.processRefund`로 따로 환불한다 */
977
+ approve: (
978
+ claimId: string,
979
+ deductAmount?: number,
980
+ idempotencyKey?: string,
981
+ options: { holdRefund?: boolean } = {},
982
+ ) =>
976
983
  storeHttp.request("POST", path`/claims/${claimId}/approve`, approveClaimResultSchema, {
977
- body: deductAmount !== undefined ? { deductAmount } : {},
984
+ body: {
985
+ ...(deductAmount !== undefined ? { deductAmount } : {}),
986
+ ...(options.holdRefund ? { holdRefund: true } : {}),
987
+ },
978
988
  headers: idempotency(idempotencyKey),
979
989
  }),
980
990
  reject: (claimId: string, body: RejectClaimRequest) =>
@@ -1289,6 +1299,13 @@ export function createStoreClient(options: StoreClientOptions) {
1289
1299
  /** `GET /v1/payments/{paymentId}` — 시도·환불 이력 포함. 404 `PAYMENT_NOT_FOUND` */
1290
1300
  get: (paymentId: string) =>
1291
1301
  storeHttp.request("GET", path`/payments/${paymentId}`, paymentRecordDetailSchema),
1302
+ /** `POST /v1/payments/refunds/{refundId}/process` — 대기 환불(`HELD`)을 PG로 환불한다(#115). 409 `REFUND_NOT_HELD` */
1303
+ processRefund: (refundId: string) =>
1304
+ storeHttp.request(
1305
+ "POST",
1306
+ path`/payments/refunds/${refundId}/process`,
1307
+ paymentRefundRecordSchema,
1308
+ ),
1292
1309
  },
1293
1310
 
1294
1311
  /**
@@ -224,6 +224,11 @@ export const approveClaimResultSchema = z.object({
224
224
  "차감은 현금에서 먼저 빼고 모자란 몫만 여기서 뺀다. 적립금을 쓰지 않은 주문과 이 필드가 없는 이전 응답·이벤트는 0으로 읽는다",
225
225
  ),
226
226
  refundedAt: z.string(),
227
+ refundHeld: z
228
+ .boolean()
229
+ .optional()
230
+ .default(false)
231
+ .describe("결제 환불을 대기로 남겼다(`holdRefund`, #115). 결제 상세에서 환불 처리한다"),
227
232
  });
228
233
 
229
234
  export type ApproveClaimResult = z.infer<typeof approveClaimResultSchema>;
@@ -203,10 +203,12 @@ export const flowPresetSummarySchema = z.object({
203
203
  .enum(["AVAILABLE", "BLOCKED"])
204
204
  .describe("BLOCKED면 의존 이슈(dependsOn)가 끝나야 설치할 수 있다"),
205
205
  dependsOn: z.array(z.string()),
206
- requires: flowDocumentSchema.describe(
207
- "프리셋이 쓰는 Core 기능(진행 단위·이행 방식·주문 입력 등)",
208
- ),
209
- variables: z.array(flowDocumentSchema).describe("셀러가 값만 입력하는 변수 정의"),
206
+ requires: flowDocumentSchema.describe("흐름 설정(진행 단위·이행 방식)"),
207
+ variables: z
208
+ .array(flowDocumentSchema)
209
+ .describe(
210
+ "늘 빈 목록이다 — 프리셋은 빈 흐름을 편집한 그래프이고 값은 노드 설정 안에 있다(#115)",
211
+ ),
210
212
  });
211
213
  export type FlowPresetSummary = z.infer<typeof flowPresetSummarySchema>;
212
214
 
@@ -296,14 +298,22 @@ export const createCommerceFlowRequestSchema = z.object({
296
298
  .describe("상점 안 유일한 키(소문자·숫자·하이픈)"),
297
299
  name: z.string().min(1).max(60).optional(),
298
300
  presetKey: z.string().optional().describe("설치할 프리셋. 없으면 빈 플로우"),
299
- variables: z.record(z.string(), z.unknown()).optional().describe("프리셋 변수 값"),
301
+ variables: z
302
+ .record(z.string(), z.unknown())
303
+ .optional()
304
+ .describe("쓰지 않는다(무시). 값은 그래프의 노드 설정 안에 있다(#115)"),
300
305
  });
301
306
  export type CreateCommerceFlowRequest = z.infer<typeof createCommerceFlowRequestSchema>;
302
307
 
303
308
  export const saveFlowDraftRequestSchema = z.object({
304
309
  graph: flowDocumentSchema,
305
- definition: flowDocumentSchema.optional(),
306
- variables: z.record(z.string(), z.unknown()).optional(),
310
+ definition: flowDocumentSchema
311
+ .optional()
312
+ .describe("흐름 설정 `requires`(progression·fulfillmentMethods)와 행동 입력 칸 `actionInputs`"),
313
+ variables: z
314
+ .record(z.string(), z.unknown())
315
+ .optional()
316
+ .describe("쓰지 않는다(무시). 값은 그래프의 노드 설정 안에 있다(#115)"),
307
317
  });
308
318
  export type SaveFlowDraftRequest = z.infer<typeof saveFlowDraftRequestSchema>;
309
319
 
@@ -503,5 +513,21 @@ export const flowNodeTypesSchema = z.object({
503
513
  configSchema: z.record(z.string(), z.unknown()),
504
514
  }),
505
515
  ),
516
+ platformActions: z
517
+ .array(
518
+ z.object({
519
+ key: z.string(),
520
+ side: z.enum(["buyer", "seller"]),
521
+ label: z.string(),
522
+ mode: z.enum(["INSTANT", "REQUEST", "VIEW"]),
523
+ subflow: z.string().optional().describe("켜면 붙는 클레임 하위 흐름"),
524
+ window: z.boolean().describe("기간(within, 단계 진입 뒤 N일)을 둘 수 있다"),
525
+ fee: z.boolean().describe("수수료(deduct)를 둘 수 있다"),
526
+ listed: z.boolean().describe("권한 표에 행으로 보인다"),
527
+ }),
528
+ )
529
+ .optional()
530
+ .default([])
531
+ .describe("노드 권한 표에 켤 수 있는 플랫폼 행동(#115) — 편집기는 이 목록으로 행을 그린다"),
506
532
  });
507
533
  export type FlowNodeTypes = z.infer<typeof flowNodeTypesSchema>;
@@ -513,6 +513,13 @@ export const cancelBySellerRequestSchema = z.object({
513
513
  "취소할 수량. 생략하면 남은 수량 전체다. 남은 수량보다 크면 400 `INVALID_QUANTITY`. " +
514
514
  "일부만 취소하면 주문상품은 상태를 유지한 채 `canceledQuantity`가 늘고, 전 수량이 소진되면 `CANCELED`가 된다",
515
515
  ),
516
+ holdRefund: z
517
+ .boolean()
518
+ .optional()
519
+ .describe(
520
+ "true면 주문만 취소하고 결제 환불은 대기로 남긴다(#115). 정산·재고·적립금 반환은 그대로 하고, PG 환불은 결제 상세의 " +
521
+ "`POST /v1/payments/refunds/{refundId}/process`로 따로 한다. 생략하면 취소와 함께 환불한다",
522
+ ),
516
523
  });
517
524
 
518
525
  export type CancelBySellerRequest = z.infer<typeof cancelBySellerRequestSchema>;
@@ -583,7 +590,14 @@ export const cancelBySellerResultSchema = z.object({
583
590
  "돌려준 적립금 (원, #93) — 결제에 쓴 적립금 중 이번 취소·반품 수량의 몫이다. 현금 환불(`refundAmount`)과 별개다. " +
584
591
  "차감은 현금에서 먼저 빼고 모자란 몫만 여기서 뺀다. 적립금을 쓰지 않은 주문과 이 필드가 없는 이전 응답·이벤트는 0으로 읽는다",
585
592
  ),
586
- refundedAt: z.string(),
593
+ refundedAt: z
594
+ .string()
595
+ .describe("환불을 요청한 시각. `refundHeld`면 취소 시각이고 환불은 아직 하지 않았다"),
596
+ refundHeld: z
597
+ .boolean()
598
+ .optional()
599
+ .default(false)
600
+ .describe("결제 환불을 대기로 남겼다(`holdRefund`). 결제 상세에서 환불 처리한다"),
587
601
  });
588
602
 
589
603
  export type CancelBySellerResult = z.infer<typeof cancelBySellerResultSchema>;
@@ -610,6 +610,14 @@ export const paymentRecordSchema = z.object({
610
610
  status: paymentRecordStatusSchema,
611
611
  amount: z.number().int().describe("결제 금액"),
612
612
  refundedAmount: z.number().int().describe("환불 완료 금액 합계. 실패한 환불은 빼고 센다"),
613
+ heldRefundAmount: z
614
+ .number()
615
+ .int()
616
+ .optional()
617
+ .default(0)
618
+ .describe(
619
+ "환불 대기 금액 합계(#115) — 주문만 취소하고 아직 환불하지 않은 몫. 결제 상세에서 환불 처리한다",
620
+ ),
613
621
  provider: pgProviderSchema.nullable().describe("승인한 PG. 승인 전에 끝났으면 마지막 시도의 PG"),
614
622
  method: pgPaymentMethodSchema.nullable().describe("실제 결제수단. 모르면 요청 수단"),
615
623
  easyPayProvider: easyPayProviderResponseSchema
@@ -707,7 +715,11 @@ export const paymentRefundRecordSchema = z.object({
707
715
  kind: z
708
716
  .string()
709
717
  .describe("환불 원인 — SELLER_CANCEL·CLAIM·COMPENSATION·DUPLICATE. 새 값이 추가될 수 있다"),
710
- status: z.string().describe("SUCCEEDED·FAILED"),
718
+ status: z
719
+ .string()
720
+ .describe(
721
+ "SUCCEEDED 환불됨 · FAILED 실패 · HELD 환불 대기(주문만 취소, #115) · PROCESSING 처리 중. 합계(`refundedAmount`)는 SUCCEEDED만 센다",
722
+ ),
711
723
  failMessage: z.string().nullable(),
712
724
  requestedAt: z.string(),
713
725
  completedAt: z.string().nullable(),
@@ -745,6 +757,7 @@ export const paymentListQuerySchema = z.object({
745
757
  .string()
746
758
  .optional()
747
759
  .describe("테스트 결제 포함 여부 (`true`·`false`. 기본 false — 실결제만)"),
760
+ refundHeld: z.string().optional().describe("`true`면 환불 대기가 있는 결제만(#115)"),
748
761
  page: z.string().optional().describe("페이지 번호 (1부터)"),
749
762
  size: z.string().optional().describe("페이지 크기 (기본 20, 최대 100)"),
750
763
  });
@@ -757,4 +770,6 @@ export interface PaymentListParams extends PageParams {
757
770
  method?: PgPaymentMethod;
758
771
  keyword?: string;
759
772
  includeTest?: boolean;
773
+ /** 환불 대기가 있는 결제만(#115) */
774
+ refundHeld?: boolean;
760
775
  }