@waffo/waffo-integrate 1.0.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.
@@ -0,0 +1,615 @@
1
+ # Java Integration Templates
2
+
3
+ ## Dependency
4
+
5
+ **Maven:**
6
+ ```xml
7
+ <dependency>
8
+ <groupId>com.waffo</groupId>
9
+ <artifactId>waffo-java</artifactId>
10
+ <version>${latest}</version>
11
+ </dependency>
12
+ ```
13
+
14
+ **Gradle:**
15
+ ```groovy
16
+ implementation 'com.waffo:waffo-java:${latest}'
17
+ ```
18
+
19
+ ---
20
+
21
+ ## SDK Initialization
22
+
23
+ ### Spring Boot Configuration
24
+
25
+ ```java
26
+ // src/main/java/com/example/config/WaffoConfiguration.java
27
+ package com.example.config;
28
+
29
+ import com.waffo.Waffo;
30
+ import com.waffo.types.config.Environment;
31
+ import com.waffo.types.config.WaffoConfig;
32
+ import org.springframework.beans.factory.annotation.Value;
33
+ import org.springframework.context.annotation.Bean;
34
+ import org.springframework.context.annotation.Configuration;
35
+
36
+ @Configuration
37
+ public class WaffoConfiguration {
38
+
39
+ @Value("${waffo.api-key}")
40
+ private String apiKey;
41
+
42
+ @Value("${waffo.private-key}")
43
+ private String privateKey;
44
+
45
+ @Value("${waffo.public-key}")
46
+ private String waffoPublicKey;
47
+
48
+ @Value("${waffo.merchant-id}")
49
+ private String merchantId;
50
+
51
+ @Value("${waffo.environment:SANDBOX}")
52
+ private String environment;
53
+
54
+ @Bean
55
+ public Waffo waffo() {
56
+ WaffoConfig config = WaffoConfig.builder()
57
+ .apiKey(apiKey)
58
+ .privateKey(privateKey)
59
+ .waffoPublicKey(waffoPublicKey)
60
+ .merchantId(merchantId)
61
+ .environment("PRODUCTION".equals(environment)
62
+ ? Environment.PRODUCTION
63
+ : Environment.SANDBOX)
64
+ .build();
65
+ return new Waffo(config);
66
+ }
67
+ }
68
+ ```
69
+
70
+ **application.yml:**
71
+ ```yaml
72
+ waffo:
73
+ api-key: ${WAFFO_API_KEY}
74
+ private-key: ${WAFFO_PRIVATE_KEY}
75
+ public-key: ${WAFFO_PUBLIC_KEY}
76
+ merchant-id: ${WAFFO_MERCHANT_ID}
77
+ environment: SANDBOX
78
+ ```
79
+
80
+ ### Plain Java (no framework)
81
+
82
+ ```java
83
+ import com.waffo.Waffo;
84
+ import com.waffo.types.config.Environment;
85
+ import com.waffo.types.config.WaffoConfig;
86
+
87
+ public class WaffoFactory {
88
+ private static volatile Waffo instance;
89
+
90
+ public static Waffo getInstance() {
91
+ if (instance == null) {
92
+ synchronized (WaffoFactory.class) {
93
+ if (instance == null) {
94
+ WaffoConfig config = WaffoConfig.builder()
95
+ .apiKey(System.getenv("WAFFO_API_KEY"))
96
+ .privateKey(System.getenv("WAFFO_PRIVATE_KEY"))
97
+ .waffoPublicKey(System.getenv("WAFFO_PUBLIC_KEY"))
98
+ .merchantId(System.getenv("WAFFO_MERCHANT_ID"))
99
+ .environment(Environment.SANDBOX)
100
+ .build();
101
+ instance = new Waffo(config);
102
+ }
103
+ }
104
+ }
105
+ return instance;
106
+ }
107
+ }
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Payment Service
113
+
114
+ ```java
115
+ // src/main/java/com/example/service/PaymentService.java
116
+ package com.example.service;
117
+
118
+ import com.waffo.Waffo;
119
+ import com.waffo.types.api.ApiResponse;
120
+ import com.waffo.types.order.*;
121
+ import org.springframework.stereotype.Service;
122
+
123
+ import java.util.UUID;
124
+
125
+ @Service
126
+ public class PaymentService {
127
+
128
+ private final Waffo waffo;
129
+
130
+ /** Generate a 32-char request ID (UUID without dashes, max length 32) */
131
+ private static String genRequestId() {
132
+ return UUID.randomUUID().toString().replace("-", "");
133
+ }
134
+
135
+ public PaymentService(Waffo waffo) {
136
+ this.waffo = waffo;
137
+ }
138
+
139
+ public CreateOrderData createPayment(String merchantOrderId, String amount,
140
+ String currency, String description,
141
+ String notifyUrl, String successRedirectUrl,
142
+ String userId, String userEmail) {
143
+ CreateOrderParams params = CreateOrderParams.builder()
144
+ .paymentRequestId(genRequestId())
145
+ .merchantOrderId(merchantOrderId)
146
+ .orderCurrency(currency)
147
+ .orderAmount(amount)
148
+ .orderDescription(description)
149
+ .notifyUrl(notifyUrl)
150
+ .successRedirectUrl(successRedirectUrl)
151
+ .userInfo(UserInfo.builder()
152
+ .userId(userId)
153
+ .userEmail(userEmail)
154
+ .userTerminal("WEB")
155
+ .build())
156
+ .paymentInfo(PaymentInfo.builder()
157
+ .productName("ONE_TIME_PAYMENT")
158
+ .build())
159
+ .build();
160
+
161
+ ApiResponse<CreateOrderData> response = waffo.order().create(params);
162
+
163
+ if (!response.isSuccess()) {
164
+ throw new RuntimeException("Payment creation failed: " +
165
+ response.getCode() + " - " + response.getMessage().orElse(""));
166
+ }
167
+
168
+ return response.getData().orElseThrow();
169
+ }
170
+
171
+ public InquiryOrderData queryOrder(String paymentRequestId) {
172
+ InquiryOrderParams params = InquiryOrderParams.builder()
173
+ .paymentRequestId(paymentRequestId)
174
+ .build();
175
+
176
+ ApiResponse<InquiryOrderData> response = waffo.order().inquiry(params);
177
+
178
+ if (!response.isSuccess()) {
179
+ throw new RuntimeException("Order inquiry failed: " +
180
+ response.getCode() + " - " + response.getMessage().orElse(""));
181
+ }
182
+
183
+ return response.getData().orElseThrow();
184
+ }
185
+
186
+ public CancelOrderData cancelOrder(String paymentRequestId) {
187
+ CancelOrderParams params = CancelOrderParams.builder()
188
+ .paymentRequestId(paymentRequestId)
189
+ .build();
190
+
191
+ ApiResponse<CancelOrderData> response = waffo.order().cancel(params);
192
+
193
+ if (!response.isSuccess()) {
194
+ throw new RuntimeException("Order cancel failed: " +
195
+ response.getCode() + " - " + response.getMessage().orElse(""));
196
+ }
197
+
198
+ return response.getData().orElseThrow();
199
+ }
200
+ }
201
+ ```
202
+
203
+ ---
204
+
205
+ ## Refund Service
206
+
207
+ ```java
208
+ // src/main/java/com/example/service/RefundService.java
209
+ package com.example.service;
210
+
211
+ import com.waffo.Waffo;
212
+ import com.waffo.types.api.ApiResponse;
213
+ import com.waffo.types.order.RefundOrderParams;
214
+ import com.waffo.types.order.RefundOrderData;
215
+ import com.waffo.types.refund.InquiryRefundParams;
216
+ import com.waffo.types.refund.InquiryRefundData;
217
+ import org.springframework.stereotype.Service;
218
+
219
+ import java.util.UUID;
220
+
221
+ @Service
222
+ public class RefundService {
223
+
224
+ private final Waffo waffo;
225
+
226
+ public RefundService(Waffo waffo) {
227
+ this.waffo = waffo;
228
+ }
229
+
230
+ public RefundOrderData refundOrder(String origPaymentRequestId,
231
+ String refundAmount, String refundReason) {
232
+ RefundOrderParams params = RefundOrderParams.builder()
233
+ .refundRequestId(UUID.randomUUID().toString().replace("-", ""))
234
+ .origPaymentRequestId(origPaymentRequestId)
235
+ .refundAmount(refundAmount)
236
+ .refundReason(refundReason)
237
+ .build();
238
+
239
+ ApiResponse<RefundOrderData> response = waffo.order().refund(params);
240
+
241
+ if (!response.isSuccess()) {
242
+ throw new RuntimeException("Refund failed: " +
243
+ response.getCode() + " - " + response.getMessage().orElse(""));
244
+ }
245
+
246
+ return response.getData().orElseThrow();
247
+ }
248
+
249
+ public InquiryRefundData queryRefund(String refundRequestId) {
250
+ InquiryRefundParams params = InquiryRefundParams.builder()
251
+ .refundRequestId(refundRequestId)
252
+ .build();
253
+
254
+ ApiResponse<InquiryRefundData> response = waffo.refund().inquiry(params);
255
+
256
+ if (!response.isSuccess()) {
257
+ throw new RuntimeException("Refund inquiry failed: " +
258
+ response.getCode() + " - " + response.getMessage().orElse(""));
259
+ }
260
+
261
+ return response.getData().orElseThrow();
262
+ }
263
+ }
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Subscription Service
269
+
270
+ ```java
271
+ // src/main/java/com/example/service/SubscriptionService.java
272
+ package com.example.service;
273
+
274
+ import com.waffo.Waffo;
275
+ import com.waffo.types.api.ApiResponse;
276
+ import com.waffo.types.subscription.*;
277
+ import org.springframework.stereotype.Service;
278
+
279
+ import java.util.UUID;
280
+
281
+ @Service
282
+ public class SubscriptionService {
283
+
284
+ private final Waffo waffo;
285
+
286
+ public SubscriptionService(Waffo waffo) {
287
+ this.waffo = waffo;
288
+ }
289
+
290
+ public CreateSubscriptionData createSubscription(String merchantSubscriptionId,
291
+ String amount, String currency,
292
+ String description, String notifyUrl,
293
+ String successRedirectUrl,
294
+ String userId, String userEmail,
295
+ String productId, String productName,
296
+ String goodsId, String goodsName,
297
+ String goodsUrl) {
298
+ CreateSubscriptionParams params = CreateSubscriptionParams.builder()
299
+ .subscriptionRequest(UUID.randomUUID().toString().replace("-", ""))
300
+ .merchantSubscriptionId(merchantSubscriptionId)
301
+ .currency(CurrencyCode.USD)
302
+ .amount(amount)
303
+ .orderDescription(description)
304
+ .notifyUrl(notifyUrl)
305
+ .successRedirectUrl(successRedirectUrl)
306
+ .productInfo(ProductInfo.builder()
307
+ .productId(productId)
308
+ .productName(productName)
309
+ .description(description)
310
+ .periodType(PeriodType.MONTHLY)
311
+ .periodInterval("1")
312
+ .build())
313
+ .goodsInfo(GoodsInfo.builder()
314
+ .goodsId(goodsId)
315
+ .goodsName(goodsName)
316
+ .goodsUrl(goodsUrl)
317
+ .build())
318
+ .userInfo(UserInfo.builder()
319
+ .userId(userId)
320
+ .userEmail(userEmail)
321
+ .userTerminal("WEB") // WEB for PC, APP for mobile/tablet
322
+ .build())
323
+ .paymentInfo(PaymentInfo.builder()
324
+ .productName("SUBSCRIPTION")
325
+ .payMethodType("CREDITCARD,DEBITCARD,APPLEPAY,GOOGLEPAY")
326
+ .build())
327
+ .build();
328
+
329
+ ApiResponse<CreateSubscriptionData> response = waffo.subscription().create(params);
330
+
331
+ if (!response.isSuccess()) {
332
+ throw new RuntimeException("Subscription creation failed: " +
333
+ response.getCode() + " - " + response.getMessage().orElse(""));
334
+ }
335
+
336
+ return response.getData().orElseThrow();
337
+ }
338
+
339
+ public InquirySubscriptionData querySubscription(String subscriptionRequest) {
340
+ InquirySubscriptionParams params = InquirySubscriptionParams.builder()
341
+ .subscriptionRequest(subscriptionRequest)
342
+ .build();
343
+
344
+ ApiResponse<InquirySubscriptionData> response = waffo.subscription().inquiry(params);
345
+
346
+ if (!response.isSuccess()) {
347
+ throw new RuntimeException("Subscription inquiry failed: " +
348
+ response.getCode() + " - " + response.getMessage().orElse(""));
349
+ }
350
+
351
+ return response.getData().orElseThrow();
352
+ }
353
+
354
+ public CancelSubscriptionData cancelSubscription(String subscriptionRequest) {
355
+ CancelSubscriptionParams params = CancelSubscriptionParams.builder()
356
+ .subscriptionRequest(subscriptionRequest)
357
+ .build();
358
+
359
+ ApiResponse<CancelSubscriptionData> response = waffo.subscription().cancel(params);
360
+
361
+ if (!response.isSuccess()) {
362
+ throw new RuntimeException("Subscription cancel failed: " +
363
+ response.getCode() + " - " + response.getMessage().orElse(""));
364
+ }
365
+
366
+ return response.getData().orElseThrow();
367
+ }
368
+
369
+ /**
370
+ * Get the management URL for an ACTIVE subscription.
371
+ * manage() only works when subscription status is ACTIVE.
372
+ *
373
+ * @param subscriptionId the subscription ID (or use subscriptionRequest instead)
374
+ */
375
+ public String manageSubscription(String subscriptionId) {
376
+ ManageSubscriptionParams params = ManageSubscriptionParams.builder()
377
+ .subscriptionId(subscriptionId)
378
+ .build();
379
+
380
+ ApiResponse<ManageSubscriptionData> response = waffo.subscription().manage(params);
381
+
382
+ if (!response.isSuccess()) {
383
+ throw new RuntimeException("Subscription manage failed: " +
384
+ response.getCode() + " - " + response.getMessage().orElse(""));
385
+ }
386
+
387
+ return response.getData().orElseThrow().getManagementUrl();
388
+ }
389
+ }
390
+ ```
391
+
392
+ ---
393
+
394
+ ## Webhook Controller (Spring Boot)
395
+
396
+ ```java
397
+ // src/main/java/com/example/controller/WaffoWebhookController.java
398
+ package com.example.controller;
399
+
400
+ import com.waffo.Waffo;
401
+ import com.waffo.core.WebhookHandler;
402
+ import com.waffo.core.WebhookHandler.WebhookResult;
403
+ import org.springframework.http.ResponseEntity;
404
+ import org.springframework.web.bind.annotation.*;
405
+
406
+ @RestController
407
+ @RequestMapping("/waffo")
408
+ public class WaffoWebhookController {
409
+
410
+ private final Waffo waffo;
411
+
412
+ public WaffoWebhookController(Waffo waffo) {
413
+ this.waffo = waffo;
414
+ }
415
+
416
+ @PostMapping("/webhook")
417
+ public ResponseEntity<String> handleWebhook(
418
+ @RequestBody String body,
419
+ @RequestHeader("X-SIGNATURE") String signature) {
420
+
421
+ WebhookHandler handler = waffo.webhook()
422
+ .onPayment(notification -> {
423
+ var result = notification.getResult();
424
+ System.out.println("Payment " + result.getOrderStatus() +
425
+ ": orderId=" + result.getAcquiringOrderId());
426
+ // TODO: Update your order status in database
427
+ })
428
+ .onRefund(notification -> {
429
+ var result = notification.getResult();
430
+ System.out.println("Refund " + result.getRefundStatus() +
431
+ ": refundId=" + result.getAcquiringRefundOrderId());
432
+ // TODO: Update your refund status in database
433
+ })
434
+ .onSubscriptionStatus(notification -> {
435
+ var result = notification.getResult();
436
+ System.out.println("Subscription " + result.getSubscriptionStatus() +
437
+ ": subId=" + result.getSubscriptionId());
438
+ // TODO: Update your subscription status in database
439
+ })
440
+ .onSubscriptionPeriodChanged(notification -> {
441
+ var result = notification.getResult();
442
+ System.out.println("Period changed: subId=" + result.getSubscriptionId());
443
+ // TODO: Record billing period result
444
+ })
445
+ .onSubscriptionChange(notification -> {
446
+ var result = notification.getResult();
447
+ System.out.println("Subscription change: " + result.getSubscriptionChangeStatus());
448
+ // TODO: Handle subscription upgrade/downgrade result
449
+ });
450
+
451
+ WebhookResult webhookResult = handler.handleWebhook(body, signature);
452
+
453
+ return ResponseEntity.ok()
454
+ .header("X-SIGNATURE", webhookResult.getResponseSignature())
455
+ .body(webhookResult.getResponseBody());
456
+ }
457
+ }
458
+ ```
459
+
460
+ ---
461
+
462
+ ## Test Template (Sandbox Integration)
463
+
464
+ ```java
465
+ // src/test/java/com/example/WaffoIntegrationTest.java
466
+ package com.example;
467
+
468
+ import com.waffo.Waffo;
469
+ import com.waffo.types.api.ApiResponse;
470
+ import com.waffo.types.config.Environment;
471
+ import com.waffo.types.config.WaffoConfig;
472
+ import com.waffo.types.order.*;
473
+ import org.junit.jupiter.api.BeforeAll;
474
+ import org.junit.jupiter.api.Test;
475
+ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
476
+
477
+ import java.util.UUID;
478
+
479
+ import static org.junit.jupiter.api.Assertions.*;
480
+
481
+ @EnabledIfEnvironmentVariable(named = "WAFFO_API_KEY", matches = ".+")
482
+ class WaffoIntegrationTest {
483
+
484
+ private static Waffo waffo;
485
+
486
+ @BeforeAll
487
+ static void setup() {
488
+ WaffoConfig config = WaffoConfig.builder()
489
+ .apiKey(System.getenv("WAFFO_API_KEY"))
490
+ .privateKey(System.getenv("WAFFO_PRIVATE_KEY"))
491
+ .waffoPublicKey(System.getenv("WAFFO_PUBLIC_KEY"))
492
+ .merchantId(System.getenv("WAFFO_MERCHANT_ID"))
493
+ .environment(Environment.SANDBOX)
494
+ .build();
495
+ waffo = new Waffo(config);
496
+ }
497
+
498
+ private static String genRequestId() {
499
+ return UUID.randomUUID().toString().replace("-", "");
500
+ }
501
+
502
+ @Test
503
+ void testCreateOrder() {
504
+ String paymentRequestId = genRequestId();
505
+
506
+ CreateOrderParams params = CreateOrderParams.builder()
507
+ .paymentRequestId(paymentRequestId)
508
+ .merchantOrderId("test-" + System.currentTimeMillis())
509
+ .orderCurrency("USD")
510
+ .orderAmount("1.00")
511
+ .orderDescription("Integration test order")
512
+ .notifyUrl("https://example.com/webhook")
513
+ .successRedirectUrl("https://example.com/success")
514
+ .userInfo(UserInfo.builder()
515
+ .userId("test-user")
516
+ .userEmail("test@example.com")
517
+ .userTerminal("WEB")
518
+ .build())
519
+ .paymentInfo(PaymentInfo.builder()
520
+ .productName("ONE_TIME_PAYMENT")
521
+ .build())
522
+ .build();
523
+
524
+ ApiResponse<CreateOrderData> response = waffo.order().create(params);
525
+
526
+ assertTrue(response.isSuccess(), String.format(
527
+ "Create order failed:\n [Request] paymentRequestId=%s\n [Response] Code=%s, Message=%s, Data=%s",
528
+ paymentRequestId,
529
+ response.getCode(),
530
+ response.getMessage().orElse("(none)"),
531
+ response.getData().orElse(null)));
532
+
533
+ assertNotNull(response.getData().orElseThrow().getAcquiringOrderId());
534
+ }
535
+
536
+ @Test
537
+ void testQueryOrder() {
538
+ String paymentRequestId = genRequestId();
539
+
540
+ // Create first
541
+ waffo.order().create(CreateOrderParams.builder()
542
+ .paymentRequestId(paymentRequestId)
543
+ .merchantOrderId("test-" + System.currentTimeMillis())
544
+ .orderCurrency("USD")
545
+ .orderAmount("1.00")
546
+ .orderDescription("Test")
547
+ .notifyUrl("https://example.com/webhook")
548
+ .successRedirectUrl("https://example.com/success")
549
+ .userInfo(UserInfo.builder().userId("test-user").userEmail("test@example.com").userTerminal("WEB").build())
550
+ .paymentInfo(PaymentInfo.builder().productName("ONE_TIME_PAYMENT").build())
551
+ .build());
552
+
553
+ // Then query
554
+ ApiResponse<InquiryOrderData> response = waffo.order().inquiry(
555
+ InquiryOrderParams.builder().paymentRequestId(paymentRequestId).build());
556
+
557
+ assertTrue(response.isSuccess(), String.format(
558
+ "Inquiry failed:\n [Request] paymentRequestId=%s\n [Response] Code=%s, Message=%s",
559
+ paymentRequestId,
560
+ response.getCode(),
561
+ response.getMessage().orElse("(none)")));
562
+ }
563
+ }
564
+ ```
565
+
566
+ ---
567
+
568
+ ## Merchant Config & Payment Method Query
569
+
570
+ ```java
571
+ // src/main/java/com/example/service/ConfigService.java
572
+ package com.example.service;
573
+
574
+ import com.waffo.Waffo;
575
+ import com.waffo.types.api.ApiResponse;
576
+ import com.waffo.types.merchant.InquiryMerchantConfigParams;
577
+ import com.waffo.types.merchant.InquiryMerchantConfigData;
578
+ import com.waffo.types.paymethod.InquiryPayMethodConfigParams;
579
+ import com.waffo.types.paymethod.InquiryPayMethodConfigData;
580
+ import org.springframework.stereotype.Service;
581
+
582
+ @Service
583
+ public class ConfigService {
584
+
585
+ private final Waffo waffo;
586
+
587
+ public ConfigService(Waffo waffo) {
588
+ this.waffo = waffo;
589
+ }
590
+
591
+ public InquiryMerchantConfigData getMerchantConfig() {
592
+ ApiResponse<InquiryMerchantConfigData> response =
593
+ waffo.merchantConfig().inquiry(InquiryMerchantConfigParams.builder().build());
594
+
595
+ if (!response.isSuccess()) {
596
+ throw new RuntimeException("Merchant config inquiry failed: " +
597
+ response.getCode() + " - " + response.getMessage().orElse(""));
598
+ }
599
+
600
+ return response.getData().orElseThrow();
601
+ }
602
+
603
+ public InquiryPayMethodConfigData getPaymentMethods() {
604
+ ApiResponse<InquiryPayMethodConfigData> response =
605
+ waffo.payMethodConfig().inquiry(InquiryPayMethodConfigParams.builder().build());
606
+
607
+ if (!response.isSuccess()) {
608
+ throw new RuntimeException("Pay method inquiry failed: " +
609
+ response.getCode() + " - " + response.getMessage().orElse(""));
610
+ }
611
+
612
+ return response.getData().orElseThrow();
613
+ }
614
+ }
615
+ ```