diff --git a/.gitignore b/.gitignore index 9c45b58..0936194 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,7 @@ ExhaustiveVerify.java *-result.md *test-result* *.log + +apache-maven-3.9.6 + +src/main/docker \ No newline at end of file diff --git a/pom.xml b/pom.xml index b7b6742..3c92a24 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,13 @@ org.mockito mockito-core - 5.8.0 + 5.11.0 + test + + + org.mockito + mockito-junit-jupiter + 5.11.0 test @@ -81,7 +87,17 @@ maven-surefire-plugin ${surefire-plugin.version} + + integration + + -XX:+EnableDynamicAgentLoading + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.io=ALL-UNNAMED + --add-opens java.base/java.net=ALL-UNNAMED + + - \ No newline at end of file + diff --git a/src/main/java/com/tapsilat/TapsilatClient.java b/src/main/java/com/tapsilat/TapsilatClient.java index 549d339..812d786 100644 --- a/src/main/java/com/tapsilat/TapsilatClient.java +++ b/src/main/java/com/tapsilat/TapsilatClient.java @@ -58,7 +58,7 @@ public OrganizationService organization() { /** * Backward compatibility method for createOrder. */ - public com.tapsilat.model.order.OrderResponse createOrder(com.tapsilat.model.order.OrderRequest request) + public com.tapsilat.model.order.OrderResponse createOrder(com.tapsilat.model.order.OrderCreateRequest request) throws TapsilatException { return orders.create(request); } diff --git a/src/main/java/com/tapsilat/builder/OrderRequestBuilder.java b/src/main/java/com/tapsilat/builder/OrderRequestBuilder.java index e5c1ff2..9a944ab 100644 --- a/src/main/java/com/tapsilat/builder/OrderRequestBuilder.java +++ b/src/main/java/com/tapsilat/builder/OrderRequestBuilder.java @@ -10,7 +10,7 @@ import java.util.List; /** - * Builder class for creating OrderRequest objects easily. + * Builder class for creating OrderCreateRequest objects easily. */ public class OrderRequestBuilder { @@ -18,8 +18,6 @@ public class OrderRequestBuilder { private String currency; private String locale; private Buyer buyer; - private String description; - private String callbackUrl; private String conversationId; private List metadata = new ArrayList<>(); private ShippingAddress shippingAddress; @@ -132,29 +130,8 @@ public OrderRequestBuilder buyer(String name, String surname, String email) { * @return This builder */ public OrderRequestBuilder buyer(String name, String surname, String email, String phone, String identityNumber) { - this.buyer = new Buyer(name, surname, email, phone, identityNumber); - return this; - } - - /** - * Set the order description. - * - * @param description The description - * @return This builder - */ - public OrderRequestBuilder description(String description) { - this.description = description; - return this; - } - - /** - * Set the callback URL. - * - * @param callbackUrl The callback URL - * @return This builder - */ - public OrderRequestBuilder callbackUrl(String callbackUrl) { - this.callbackUrl = callbackUrl; + this.buyer = new Buyer(name, surname, email, identityNumber); + this.buyer.setGsmNumber(phone); return this; } @@ -316,7 +293,7 @@ public OrderRequestBuilder paymentOptions(List paymentOptions) { private CheckoutDesign checkoutDesign; private List enabledInstallments = new ArrayList<>(); private String externalReferenceId; - private OrderCard orderCards; + private List orderCards = new ArrayList<>(); private BigDecimal paidAmount; private String paymentFailureUrl; private String paymentMode; @@ -348,8 +325,13 @@ public OrderRequestBuilder externalReferenceId(String externalReferenceId) { return this; } - public OrderRequestBuilder orderCards(OrderCard orderCards) { - this.orderCards = orderCards; + public OrderRequestBuilder orderCards(List orderCards) { + this.orderCards = orderCards == null ? new ArrayList<>() : new ArrayList<>(orderCards); + return this; + } + + public OrderRequestBuilder addOrderCard(OrderCard orderCard) { + this.orderCards.add(orderCard); return this; } @@ -404,18 +386,16 @@ public OrderRequestBuilder submerchants(List submerchants) { } /** - * Build the OrderRequest object. + * Build the OrderCreateRequest object. * - * @return The constructed OrderRequest + * @return The constructed OrderCreateRequest */ - public OrderRequest build() { - OrderRequest orderRequest = new OrderRequest(); + public OrderCreateRequest build() { + OrderCreateRequest orderRequest = new OrderCreateRequest(); orderRequest.setAmount(amount); orderRequest.setCurrency(currency); orderRequest.setLocale(locale); orderRequest.setBuyer(buyer); - orderRequest.setDescription(description); - orderRequest.setCallbackUrl(callbackUrl); orderRequest.setConversationId(conversationId); orderRequest.setMetadata(metadata.isEmpty() ? null : metadata); orderRequest.setShippingAddress(shippingAddress); @@ -451,4 +431,4 @@ public OrderRequest build() { public static OrderRequestBuilder newBuilder() { return new OrderRequestBuilder(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/tapsilat/model/common/BasketItem.java b/src/main/java/com/tapsilat/model/common/BasketItem.java index 43104e3..6797d33 100644 --- a/src/main/java/com/tapsilat/model/common/BasketItem.java +++ b/src/main/java/com/tapsilat/model/common/BasketItem.java @@ -61,6 +61,9 @@ public class BasketItem { @JsonProperty("sub_merchant_price") private String subMerchantPrice; + @JsonProperty("mcc") + private String mcc; + // Default constructor for Jackson public BasketItem() { } @@ -145,6 +148,70 @@ public void setQuantityUnit(String quantityUnit) { this.quantityUnit = quantityUnit; } + public Double getCommissionAmount() { + return commissionAmount; + } + + public void setCommissionAmount(Double commissionAmount) { + this.commissionAmount = commissionAmount; + } + + public String getCoupon() { + return coupon; + } + + public void setCoupon(String coupon) { + this.coupon = coupon; + } + + public Double getPaidAmount() { + return paidAmount; + } + + public void setPaidAmount(Double paidAmount) { + this.paidAmount = paidAmount; + } + + public BasketItemPayer getPayer() { + return payer; + } + + public void setPayer(BasketItemPayer payer) { + this.payer = payer; + } + + public Double getQuantityFloat() { + return quantityFloat; + } + + public void setQuantityFloat(Double quantityFloat) { + this.quantityFloat = quantityFloat; + } + + public String getSubMerchantKey() { + return subMerchantKey; + } + + public void setSubMerchantKey(String subMerchantKey) { + this.subMerchantKey = subMerchantKey; + } + + public String getSubMerchantPrice() { + return subMerchantPrice; + } + + public void setSubMerchantPrice(String subMerchantPrice) { + this.subMerchantPrice = subMerchantPrice; + } + + public String getMcc() { + return mcc; + } + + public void setMcc(String mcc) { + this.mcc = mcc; + } + @Override public boolean equals(Object o) { if (this == o) @@ -161,13 +228,23 @@ public boolean equals(Object o) { Objects.equals(itemType, that.itemType) && Objects.equals(couponDiscount, that.couponDiscount) && Objects.equals(data, that.data) && - Objects.equals(quantityUnit, that.quantityUnit); + Objects.equals(quantityUnit, that.quantityUnit) && + Objects.equals(commissionAmount, that.commissionAmount) && + Objects.equals(coupon, that.coupon) && + Objects.equals(paidAmount, that.paidAmount) && + Objects.equals(payer, that.payer) && + Objects.equals(quantityFloat, that.quantityFloat) && + Objects.equals(subMerchantKey, that.subMerchantKey) && + Objects.equals(subMerchantPrice, that.subMerchantPrice) && + Objects.equals(mcc, that.mcc); } @Override public int hashCode() { return Objects.hash(id, name, category1, category2, price, quantity, - itemType, couponDiscount, data, quantityUnit); + itemType, couponDiscount, data, quantityUnit, commissionAmount, + coupon, paidAmount, payer, quantityFloat, subMerchantKey, + subMerchantPrice, mcc); } @Override @@ -183,6 +260,14 @@ public String toString() { ", couponDiscount=" + couponDiscount + ", data='" + data + '\'' + ", quantityUnit='" + quantityUnit + '\'' + + ", commissionAmount=" + commissionAmount + + ", coupon='" + coupon + '\'' + + ", paidAmount=" + paidAmount + + ", payer=" + payer + + ", quantityFloat=" + quantityFloat + + ", subMerchantKey='" + subMerchantKey + '\'' + + ", subMerchantPrice='" + subMerchantPrice + '\'' + + ", mcc='" + mcc + '\'' + '}'; } } diff --git a/src/main/java/com/tapsilat/model/common/BillingAddress.java b/src/main/java/com/tapsilat/model/common/BillingAddress.java index c2f0a7d..168c99b 100644 --- a/src/main/java/com/tapsilat/model/common/BillingAddress.java +++ b/src/main/java/com/tapsilat/model/common/BillingAddress.java @@ -36,86 +36,166 @@ public class BillingAddress { @JsonProperty("vat_number") private String vatNumber; - + + @JsonProperty("citizenship") + private String citizenship; + + @JsonProperty("title") + private String title; + + @JsonProperty("tax_office") + private String taxOffice; + + @JsonProperty("neighbourhood") + private String neighbourhood; + + @JsonProperty("street1") + private String street1; + + @JsonProperty("street2") + private String street2; + + @JsonProperty("street3") + private String street3; + // Default constructor for Jackson - public BillingAddress() {} - + public BillingAddress() { + } + public String getAddress() { return address; } - + public void setAddress(String address) { this.address = address; } - + public String getCity() { return city; } - + public void setCity(String city) { this.city = city; } - + public String getContactName() { return contactName; } - + public void setContactName(String contactName) { this.contactName = contactName; } - + public String getCountry() { return country; } - + public void setCountry(String country) { this.country = country; } - + public String getZipCode() { return zipCode; } - + public void setZipCode(String zipCode) { this.zipCode = zipCode; } - + public String getBillingType() { return billingType; } - + public void setBillingType(String billingType) { this.billingType = billingType; } - + public String getContactPhone() { return contactPhone; } - + public void setContactPhone(String contactPhone) { this.contactPhone = contactPhone; } - + public String getDistrict() { return district; } - + public void setDistrict(String district) { this.district = district; } - + public String getVatNumber() { return vatNumber; } - + public void setVatNumber(String vatNumber) { this.vatNumber = vatNumber; } - + + public String getCitizenship() { + return citizenship; + } + + public void setCitizenship(String citizenship) { + this.citizenship = citizenship; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getTaxOffice() { + return taxOffice; + } + + public void setTaxOffice(String taxOffice) { + this.taxOffice = taxOffice; + } + + public String getNeighbourhood() { + return neighbourhood; + } + + public void setNeighbourhood(String neighbourhood) { + this.neighbourhood = neighbourhood; + } + + public String getStreet1() { + return street1; + } + + public void setStreet1(String street1) { + this.street1 = street1; + } + + public String getStreet2() { + return street2; + } + + public void setStreet2(String street2) { + this.street2 = street2; + } + + public String getStreet3() { + return street3; + } + + public void setStreet3(String street3) { + this.street3 = street3; + } + @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; BillingAddress that = (BillingAddress) o; return Objects.equals(address, that.address) && Objects.equals(city, that.city) && @@ -125,13 +205,21 @@ public boolean equals(Object o) { Objects.equals(billingType, that.billingType) && Objects.equals(contactPhone, that.contactPhone) && Objects.equals(district, that.district) && - Objects.equals(vatNumber, that.vatNumber); + Objects.equals(vatNumber, that.vatNumber) && + Objects.equals(citizenship, that.citizenship) && + Objects.equals(title, that.title) && + Objects.equals(taxOffice, that.taxOffice) && + Objects.equals(neighbourhood, that.neighbourhood) && + Objects.equals(street1, that.street1) && + Objects.equals(street2, that.street2) && + Objects.equals(street3, that.street3); } @Override public int hashCode() { - return Objects.hash(address, city, contactName, country, zipCode, - billingType, contactPhone, district, vatNumber); + return Objects.hash(address, city, contactName, country, zipCode, + billingType, contactPhone, district, vatNumber, citizenship, title, + taxOffice, neighbourhood, street1, street2, street3); } @Override @@ -146,6 +234,13 @@ public String toString() { ", contactPhone='" + contactPhone + '\'' + ", district='" + district + '\'' + ", vatNumber='" + vatNumber + '\'' + + ", citizenship='" + citizenship + '\'' + + ", title='" + title + '\'' + + ", taxOffice='" + taxOffice + '\'' + + ", neighbourhood='" + neighbourhood + '\'' + + ", street1='" + street1 + '\'' + + ", street2='" + street2 + '\'' + + ", street3='" + street3 + '\'' + '}'; } } diff --git a/src/main/java/com/tapsilat/model/common/Buyer.java b/src/main/java/com/tapsilat/model/common/Buyer.java index f8821ab..c6cecb6 100644 --- a/src/main/java/com/tapsilat/model/common/Buyer.java +++ b/src/main/java/com/tapsilat/model/common/Buyer.java @@ -21,9 +21,6 @@ public class Buyer { @JsonProperty("email") private String email; - @JsonProperty("phone") - private String phone; - @JsonProperty("identity_number") private String identityNumber; @@ -79,20 +76,19 @@ public Buyer(String name, String surname, String email) { } /** - * Constructor with all fields. - * + * Constructor with required fields and optional identity number. + * * @param name Buyer's first name (required) * @param surname Buyer's last name (required) * @param email Buyer's email address (required) - * @param phone Buyer's phone number (optional) * @param identityNumber Buyer's identity number (optional) * @throws NullPointerException if any required parameter is null + * @see #setGsmNumber(String) to set buyer GSM number when needed */ - public Buyer(String name, String surname, String email, String phone, String identityNumber) { + public Buyer(String name, String surname, String email, String identityNumber) { this.name = Objects.requireNonNull(name, "Buyer name cannot be null"); this.surname = Objects.requireNonNull(surname, "Buyer surname cannot be null"); this.email = Objects.requireNonNull(email, "Buyer email cannot be null"); - this.phone = phone; this.identityNumber = identityNumber; } @@ -121,14 +117,6 @@ public void setEmail(String email) { this.email = Objects.requireNonNull(email, "Buyer email cannot be null"); } - public String getPhone() { - return phone; - } - - public void setPhone(String phone) { - this.phone = phone; - } - public String getIdentityNumber() { return identityNumber; } @@ -235,13 +223,12 @@ public boolean equals(Object o) { return Objects.equals(name, buyer.name) && Objects.equals(surname, buyer.surname) && Objects.equals(email, buyer.email) && - Objects.equals(phone, buyer.phone) && Objects.equals(identityNumber, buyer.identityNumber); } @Override public int hashCode() { - return Objects.hash(name, surname, email, phone, identityNumber); + return Objects.hash(name, surname, email, identityNumber); } @Override @@ -250,8 +237,7 @@ public String toString() { "name='" + name + '\'' + ", surname='" + surname + '\'' + ", email='" + email + '\'' + - ", phone='" + phone + '\'' + ", identityNumber='" + identityNumber + '\'' + '}'; } -} \ No newline at end of file +} diff --git a/src/main/java/com/tapsilat/model/common/OrderPFSubMerchant.java b/src/main/java/com/tapsilat/model/common/OrderPFSubMerchant.java index e37aaf0..1bc4977 100644 --- a/src/main/java/com/tapsilat/model/common/OrderPFSubMerchant.java +++ b/src/main/java/com/tapsilat/model/common/OrderPFSubMerchant.java @@ -41,6 +41,12 @@ public class OrderPFSubMerchant { @JsonProperty("terminal_no") private String terminalNo; + @JsonProperty("national_id") + private String nationalId; + + @JsonProperty("switch_id") + private String switchId; + public String getAddress() { return address; } @@ -136,4 +142,20 @@ public String getTerminalNo() { public void setTerminalNo(String terminalNo) { this.terminalNo = terminalNo; } + + public String getNationalId() { + return nationalId; + } + + public void setNationalId(String nationalId) { + this.nationalId = nationalId; + } + + public String getSwitchId() { + return switchId; + } + + public void setSwitchId(String switchId) { + this.switchId = switchId; + } } diff --git a/src/main/java/com/tapsilat/model/common/ShippingAddress.java b/src/main/java/com/tapsilat/model/common/ShippingAddress.java index 6d1b038..6cabdac 100644 --- a/src/main/java/com/tapsilat/model/common/ShippingAddress.java +++ b/src/main/java/com/tapsilat/model/common/ShippingAddress.java @@ -24,12 +24,19 @@ public class ShippingAddress { @JsonProperty("zip_code") private String zipCode; - + + @JsonProperty("tracking_code") + private String trackingCode; + + @JsonProperty("shipping_date") + private String shippingDate; + // Default constructor for Jackson - public ShippingAddress() {} - + public ShippingAddress() { + } + /** - * Constructor with all fields. + * Constructor with required fields. */ public ShippingAddress(String address, String city, String contactName, String country, String zipCode) { this.address = address; @@ -38,62 +45,82 @@ public ShippingAddress(String address, String city, String contactName, String c this.country = country; this.zipCode = zipCode; } - + public String getAddress() { return address; } - + public void setAddress(String address) { this.address = address; } - + public String getCity() { return city; } - + public void setCity(String city) { this.city = city; } - + public String getContactName() { return contactName; } - + public void setContactName(String contactName) { this.contactName = contactName; } - + public String getCountry() { return country; } - + public void setCountry(String country) { this.country = country; } - + public String getZipCode() { return zipCode; } - + public void setZipCode(String zipCode) { this.zipCode = zipCode; } - + + public String getTrackingCode() { + return trackingCode; + } + + public void setTrackingCode(String trackingCode) { + this.trackingCode = trackingCode; + } + + public String getShippingDate() { + return shippingDate; + } + + public void setShippingDate(String shippingDate) { + this.shippingDate = shippingDate; + } + @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; ShippingAddress that = (ShippingAddress) o; return Objects.equals(address, that.address) && Objects.equals(city, that.city) && Objects.equals(contactName, that.contactName) && Objects.equals(country, that.country) && - Objects.equals(zipCode, that.zipCode); + Objects.equals(zipCode, that.zipCode) && + Objects.equals(trackingCode, that.trackingCode) && + Objects.equals(shippingDate, that.shippingDate); } @Override public int hashCode() { - return Objects.hash(address, city, contactName, country, zipCode); + return Objects.hash(address, city, contactName, country, zipCode, trackingCode, shippingDate); } @Override @@ -104,6 +131,8 @@ public String toString() { ", contactName='" + contactName + '\'' + ", country='" + country + '\'' + ", zipCode='" + zipCode + '\'' + + ", trackingCode='" + trackingCode + '\'' + + ", shippingDate='" + shippingDate + '\'' + '}'; } } diff --git a/src/main/java/com/tapsilat/model/order/OrderRequest.java b/src/main/java/com/tapsilat/model/order/OrderCreateRequest.java similarity index 92% rename from src/main/java/com/tapsilat/model/order/OrderRequest.java rename to src/main/java/com/tapsilat/model/order/OrderCreateRequest.java index 92117e4..1e0ed97 100644 --- a/src/main/java/com/tapsilat/model/order/OrderRequest.java +++ b/src/main/java/com/tapsilat/model/order/OrderCreateRequest.java @@ -17,7 +17,7 @@ * billingAddress, basketItems, taxAmount, threeDForce, partialPayment, * paymentMethods, paymentOptions. */ -public class OrderRequest { +public class OrderCreateRequest { @JsonProperty("amount") private BigDecimal amount; @@ -31,12 +31,6 @@ public class OrderRequest { @JsonProperty("buyer") private Buyer buyer; - @JsonProperty("description") - private String description; - - @JsonProperty("callback_url") - private String callbackUrl; - @JsonProperty("conversation_id") private String conversationId; @@ -77,7 +71,7 @@ public class OrderRequest { private String externalReferenceId; @JsonProperty("order_cards") - private OrderCard orderCards; + private List orderCards; @JsonProperty("paid_amount") private BigDecimal paidAmount; @@ -112,8 +106,9 @@ public class OrderRequest { @JsonProperty("consents") private List consents; + // Default constructor for Jackson deserialization - public OrderRequest() { + public OrderCreateRequest() { } /** @@ -125,7 +120,7 @@ public OrderRequest() { * @param buyer Buyer information (required) * @throws NullPointerException if any required parameter is null */ - public OrderRequest(BigDecimal amount, String currency, String locale, Buyer buyer) { + public OrderCreateRequest(BigDecimal amount, String currency, String locale, Buyer buyer) { this.amount = Objects.requireNonNull(amount, "Amount cannot be null"); this.currency = Objects.requireNonNull(currency, "Currency cannot be null"); this.locale = Objects.requireNonNull(locale, "Locale cannot be null"); @@ -165,22 +160,6 @@ public void setBuyer(Buyer buyer) { this.buyer = Objects.requireNonNull(buyer, "Buyer cannot be null"); } - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getCallbackUrl() { - return callbackUrl; - } - - public void setCallbackUrl(String callbackUrl) { - this.callbackUrl = callbackUrl; - } - public String getConversationId() { return conversationId; } @@ -325,11 +304,11 @@ public void setExternalReferenceId(String externalReferenceId) { this.externalReferenceId = externalReferenceId; } - public OrderCard getOrderCards() { + public List getOrderCards() { return orderCards; } - public void setOrderCards(OrderCard orderCards) { + public void setOrderCards(List orderCards) { this.orderCards = orderCards; } @@ -421,15 +400,14 @@ public void setConsents(List consents) { this.consents = consents; } + @Override public String toString() { - return "OrderRequest{" + + return "OrderCreateRequest{" + "amount=" + amount + ", currency='" + currency + '\'' + ", locale='" + locale + '\'' + ", buyer=" + buyer + - ", description='" + description + '\'' + - ", callbackUrl='" + callbackUrl + '\'' + ", conversationId='" + conversationId + '\'' + ", metadata=" + metadata + ", shippingAddress=" + shippingAddress + diff --git a/src/main/java/com/tapsilat/model/organization/GetVposRequest.java b/src/main/java/com/tapsilat/model/organization/GetVposRequest.java index eaa2870..56ebe3e 100644 --- a/src/main/java/com/tapsilat/model/organization/GetVposRequest.java +++ b/src/main/java/com/tapsilat/model/organization/GetVposRequest.java @@ -3,25 +3,15 @@ import com.fasterxml.jackson.annotation.JsonProperty; public class GetVposRequest { - @JsonProperty("currency") - private String currency; - @JsonProperty("currency_id") private String currencyId; public GetVposRequest() {} - public GetVposRequest(String currency) { - this.currency = currency; - } - - public String getCurrency() { - return currency; + public GetVposRequest(String currencyId) { + this.currencyId = currencyId; } - public void setCurrency(String currency) { - this.currency = currency; - } public String getCurrencyId() { return currencyId; diff --git a/src/main/java/com/tapsilat/model/organization/OrgCreateUserReq.java b/src/main/java/com/tapsilat/model/organization/OrgCreateUserRequest.java similarity index 96% rename from src/main/java/com/tapsilat/model/organization/OrgCreateUserReq.java rename to src/main/java/com/tapsilat/model/organization/OrgCreateUserRequest.java index 07ee99e..cd03c13 100644 --- a/src/main/java/com/tapsilat/model/organization/OrgCreateUserReq.java +++ b/src/main/java/com/tapsilat/model/organization/OrgCreateUserRequest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; -public class OrgCreateUserReq { +public class OrgCreateUserRequest { @JsonProperty("email") private String email; @@ -27,7 +27,7 @@ public class OrgCreateUserReq { @JsonProperty("reference_id") private String referenceId; - public OrgCreateUserReq() {} + public OrgCreateUserRequest() {} public String getEmail() { return email; diff --git a/src/main/java/com/tapsilat/model/organization/OrgUserMobileVerifyReq.java b/src/main/java/com/tapsilat/model/organization/OrgUserMobileVerifyReq.java deleted file mode 100644 index 710e403..0000000 --- a/src/main/java/com/tapsilat/model/organization/OrgUserMobileVerifyReq.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.tapsilat.model.organization; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class OrgUserMobileVerifyReq { - @JsonProperty("phone") - private String phone; - - @JsonProperty("code") - private String code; - - public OrgUserMobileVerifyReq() {} - - public OrgUserMobileVerifyReq(String phone, String code) { - this.phone = phone; - this.code = code; - } - - public String getPhone() { - return phone; - } - - public void setPhone(String phone) { - this.phone = phone; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } -} diff --git a/src/main/java/com/tapsilat/model/organization/OrgUserMobileVerifyRequest.java b/src/main/java/com/tapsilat/model/organization/OrgUserMobileVerifyRequest.java new file mode 100644 index 0000000..3def82e --- /dev/null +++ b/src/main/java/com/tapsilat/model/organization/OrgUserMobileVerifyRequest.java @@ -0,0 +1,22 @@ +package com.tapsilat.model.organization; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class OrgUserMobileVerifyRequest { + @JsonProperty("user_id") + private String userId; + + public OrgUserMobileVerifyRequest() {} + + public OrgUserMobileVerifyRequest(String userId) { + this.userId = userId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } +} diff --git a/src/main/java/com/tapsilat/model/organization/OrgUserVerifyReq.java b/src/main/java/com/tapsilat/model/organization/OrgUserVerifyReq.java deleted file mode 100644 index c854280..0000000 --- a/src/main/java/com/tapsilat/model/organization/OrgUserVerifyReq.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.tapsilat.model.organization; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class OrgUserVerifyReq { - @JsonProperty("email") - private String email; - - @JsonProperty("code") - private String code; - - public OrgUserVerifyReq() {} - - public OrgUserVerifyReq(String email, String code) { - this.email = email; - this.code = code; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } -} diff --git a/src/main/java/com/tapsilat/model/organization/OrgUserVerifyRequest.java b/src/main/java/com/tapsilat/model/organization/OrgUserVerifyRequest.java new file mode 100644 index 0000000..cb91caf --- /dev/null +++ b/src/main/java/com/tapsilat/model/organization/OrgUserVerifyRequest.java @@ -0,0 +1,22 @@ +package com.tapsilat.model.organization; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class OrgUserVerifyRequest { + @JsonProperty("user_id") + private String userId; + + public OrgUserVerifyRequest() {} + + public OrgUserVerifyRequest(String userId) { + this.userId = userId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } +} diff --git a/src/main/java/com/tapsilat/model/organization/SetLimitUserRequest.java b/src/main/java/com/tapsilat/model/organization/SetLimitUserRequest.java index 7e933ea..16ffcde 100644 --- a/src/main/java/com/tapsilat/model/organization/SetLimitUserRequest.java +++ b/src/main/java/com/tapsilat/model/organization/SetLimitUserRequest.java @@ -7,17 +7,14 @@ public class SetLimitUserRequest { @JsonProperty("user_id") private String userId; - @JsonProperty("limit") - private BigDecimal limit; - @JsonProperty("limit_id") private String limitId; public SetLimitUserRequest() {} - public SetLimitUserRequest(String userId, BigDecimal limit) { + public SetLimitUserRequest(String userId, String limitId) { this.userId = userId; - this.limit = limit; + this.limitId = limitId; } public String getUserId() { @@ -28,13 +25,6 @@ public void setUserId(String userId) { this.userId = userId; } - public BigDecimal getLimit() { - return limit; - } - - public void setLimit(BigDecimal limit) { - this.limit = limit; - } public String getLimitId() { return limitId; diff --git a/src/main/java/com/tapsilat/model/subscription/SubscriptionCreateRequest.java b/src/main/java/com/tapsilat/model/subscription/SubscriptionCreateRequest.java index 3d9d5c6..a5a5a9f 100644 --- a/src/main/java/com/tapsilat/model/subscription/SubscriptionCreateRequest.java +++ b/src/main/java/com/tapsilat/model/subscription/SubscriptionCreateRequest.java @@ -34,6 +34,13 @@ public class SubscriptionCreateRequest { @JsonProperty("period") private Integer period; + /** + * @deprecated Use amount/cycle/period fields according to latest API shape. + */ + @Deprecated + @JsonProperty("price_option") + private SubscriptionPriceOption priceOption; + @JsonProperty("success_url") private String successUrl; @@ -43,9 +50,6 @@ public class SubscriptionCreateRequest { @JsonProperty("user") private SubscriptionUser user; - @JsonProperty("price_option") - private SubscriptionPriceOption priceOption; - public BigDecimal getAmount() { return amount; } @@ -118,6 +122,22 @@ public void setPeriod(Integer period) { this.period = period; } + /** + * @deprecated Use amount/cycle/period fields according to latest API shape. + */ + @Deprecated + public SubscriptionPriceOption getPriceOption() { + return priceOption; + } + + /** + * @deprecated Use amount/cycle/period fields according to latest API shape. + */ + @Deprecated + public void setPriceOption(SubscriptionPriceOption priceOption) { + this.priceOption = priceOption; + } + public String getSuccessUrl() { return successUrl; } @@ -141,12 +161,4 @@ public SubscriptionUser getUser() { public void setUser(SubscriptionUser user) { this.user = user; } - - public SubscriptionPriceOption getPriceOption() { - return priceOption; - } - - public void setPriceOption(SubscriptionPriceOption priceOption) { - this.priceOption = priceOption; - } } diff --git a/src/main/java/com/tapsilat/model/subscription/SubscriptionPriceOption.java b/src/main/java/com/tapsilat/model/subscription/SubscriptionPriceOption.java index 1db0d63..0e3cca5 100644 --- a/src/main/java/com/tapsilat/model/subscription/SubscriptionPriceOption.java +++ b/src/main/java/com/tapsilat/model/subscription/SubscriptionPriceOption.java @@ -4,8 +4,9 @@ import java.math.BigDecimal; /** - * Represents a price option for a subscription. + * @deprecated Use amount/cycle/period fields in SubscriptionCreateRequest. */ +@Deprecated public class SubscriptionPriceOption { @JsonProperty("count") private Integer count; @@ -36,12 +37,4 @@ public BigDecimal getPrice() { public void setPrice(BigDecimal price) { this.price = price; } - - @Override - public String toString() { - return "SubscriptionPriceOption{" + - "count=" + count + - ", price=" + price + - '}'; - } } diff --git a/src/main/java/com/tapsilat/service/OrderService.java b/src/main/java/com/tapsilat/service/OrderService.java index 48c2289..0c2c5cf 100644 --- a/src/main/java/com/tapsilat/service/OrderService.java +++ b/src/main/java/com/tapsilat/service/OrderService.java @@ -20,7 +20,7 @@ public OrderService(CloseableHttpClient httpClient, TapsilatConfig config, Objec super(httpClient, config, objectMapper); } - public OrderResponse create(OrderRequest orderRequest) throws TapsilatException { + public OrderResponse create(OrderCreateRequest orderRequest) throws TapsilatException { try { OrderRequestValidator.validateOrThrow(orderRequest); OrderResponse response = executeRequest( diff --git a/src/main/java/com/tapsilat/service/OrganizationService.java b/src/main/java/com/tapsilat/service/OrganizationService.java index f29e865..6ccfbf9 100644 --- a/src/main/java/com/tapsilat/service/OrganizationService.java +++ b/src/main/java/com/tapsilat/service/OrganizationService.java @@ -124,7 +124,7 @@ public Map getSuborganizations(Integer page, Integer perPage) th } @SuppressWarnings("unchecked") - public Map createUser(OrgCreateUserReq request) throws TapsilatException { + public Map createUser(OrgCreateUserRequest request) throws TapsilatException { try { return executeRequest(buildRequest("POST", TapsilatConstants.ENDPOINT_ORGANIZATION_USER_CREATE, request, null), Map.class); } catch (IOException | ParseException e) { @@ -133,7 +133,7 @@ public Map createUser(OrgCreateUserReq request) throws TapsilatE } @SuppressWarnings("unchecked") - public Map verifyUser(OrgUserVerifyReq request) throws TapsilatException { + public Map verifyUser(OrgUserVerifyRequest request) throws TapsilatException { try { return executeRequest(buildRequest("POST", TapsilatConstants.ENDPOINT_ORGANIZATION_USER_VERIFY, request, null), Map.class); } catch (IOException | ParseException e) { @@ -142,7 +142,7 @@ public Map verifyUser(OrgUserVerifyReq request) throws TapsilatE } @SuppressWarnings("unchecked") - public Map verifyUserMobile(OrgUserMobileVerifyReq request) throws TapsilatException { + public Map verifyUserMobile(OrgUserMobileVerifyRequest request) throws TapsilatException { try { return executeRequest(buildRequest("POST", TapsilatConstants.ENDPOINT_ORGANIZATION_USER_VERIFY_MOBILE, request, null), Map.class); } catch (IOException | ParseException e) { diff --git a/src/main/java/com/tapsilat/service/SubscriptionService.java b/src/main/java/com/tapsilat/service/SubscriptionService.java index f1f8fa0..d3d2a26 100644 --- a/src/main/java/com/tapsilat/service/SubscriptionService.java +++ b/src/main/java/com/tapsilat/service/SubscriptionService.java @@ -9,6 +9,8 @@ import org.apache.hc.core5.http.ParseException; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -38,6 +40,25 @@ public SubscriptionDetail get(SubscriptionGetRequest request) throws TapsilatExc } public List list(Integer page, Integer perPage) throws TapsilatException { + Map response = listResponse(page, perPage); + if (response == null) { + return Collections.emptyList(); + } + + Object itemsObject = response.get("items"); + if (!(itemsObject instanceof List items)) { + return Collections.emptyList(); + } + + List results = new ArrayList<>(items.size()); + for (Object item : items) { + results.add(objectMapper.convertValue(item, SubscriptionListItem.class)); + } + return results; + } + + @SuppressWarnings("unchecked") + public Map listResponse(Integer page, Integer perPage) throws TapsilatException { try { Map params = new HashMap<>(); if (page != null) @@ -45,10 +66,9 @@ public List list(Integer page, Integer perPage) throws Tap if (perPage != null) params.put("per_page", String.valueOf(perPage)); - SubscriptionListItem[] items = executeRequest( + return executeRequest( buildRequest("GET", TapsilatConstants.ENDPOINT_SUBSCRIPTION_LIST, null, params), - SubscriptionListItem[].class); - return items != null ? java.util.Arrays.asList(items) : java.util.Collections.emptyList(); + Map.class); } catch (IOException | ParseException e) { throw new TapsilatException("Failed to list subscriptions", e); } diff --git a/src/main/java/com/tapsilat/validation/OrderRequestValidator.java b/src/main/java/com/tapsilat/validation/OrderRequestValidator.java index f6c2132..0adfd49 100644 --- a/src/main/java/com/tapsilat/validation/OrderRequestValidator.java +++ b/src/main/java/com/tapsilat/validation/OrderRequestValidator.java @@ -2,14 +2,14 @@ import com.tapsilat.constants.TapsilatConstants; import com.tapsilat.model.common.Buyer; -import com.tapsilat.model.order.OrderRequest; +import com.tapsilat.model.order.OrderCreateRequest; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; /** - * Validates OrderRequest objects before sending to Tapsilat API. + * Validates OrderCreateRequest objects before sending to Tapsilat API. * Provides detailed validation error messages with field context. */ public final class OrderRequestValidator { @@ -21,16 +21,16 @@ private OrderRequestValidator() { } /** - * Validates an OrderRequest and returns list of validation errors. + * Validates an OrderCreateRequest and returns list of validation errors. * Empty list indicates valid request. * * @param request The order request to validate * @return List of validation error messages, empty if valid * @throws ValidationException if request is null */ - public static List validate(OrderRequest request) { + public static List validate(OrderCreateRequest request) { if (request == null) { - throw new ValidationException("OrderRequest cannot be null"); + throw new ValidationException("OrderCreateRequest cannot be null"); } List errors = new ArrayList<>(); @@ -39,8 +39,6 @@ public static List validate(OrderRequest request) { validateCurrency(request.getCurrency(), errors); validateLocale(request.getLocale(), errors); validateBuyer(request.getBuyer(), errors); - validateDescription(request.getDescription(), errors); - validateCallbackUrl(request.getCallbackUrl(), errors); validateConversationId(request.getConversationId(), errors); // Parity with Python: Clean GSM number if present @@ -51,7 +49,7 @@ public static List validate(OrderRequest request) { } } - // Parity with Python: Validate installments + // Parity with other SDKs: Validate installments if (request.getEnabledInstallments() != null) { validateInstallmentsList(request.getEnabledInstallments(), errors); } @@ -60,12 +58,12 @@ public static List validate(OrderRequest request) { } /** - * Validates an OrderRequest and throws ValidationException if invalid. + * Validates an OrderCreateRequest and throws ValidationException if invalid. * * @param request The order request to validate * @throws ValidationException if validation fails */ - public static void validateOrThrow(OrderRequest request) { + public static void validateOrThrow(OrderCreateRequest request) { List errors = validate(request); if (!errors.isEmpty()) { throw new ValidationException("Order request validation failed", errors); @@ -94,7 +92,6 @@ private static void validateLocale(String locale, List errors) { private static void validateBuyer(Buyer buyer, List errors) { if (buyer == null) { - errors.add("Buyer information is required and cannot be null"); return; } @@ -113,21 +110,6 @@ private static void validateBuyer(Buyer buyer, List errors) { } } - private static void validateDescription(String description, List errors) { - if (description != null && description.length() > TapsilatConstants.MAX_DESCRIPTION_LENGTH) { - errors.add("Description exceeds maximum length of " + TapsilatConstants.MAX_DESCRIPTION_LENGTH - + " characters, got: " + description.length()); - } - } - - private static void validateCallbackUrl(String callbackUrl, List errors) { - if (callbackUrl != null && !callbackUrl.trim().isEmpty()) { - if (!isValidUrl(callbackUrl)) { - errors.add("Callback URL format is invalid: " + callbackUrl); - } - } - } - private static void validateConversationId(String conversationId, List errors) { if (conversationId != null && conversationId.length() > TapsilatConstants.MAX_CONVERSATION_ID_LENGTH) { errors.add("Conversation ID exceeds maximum length of " + TapsilatConstants.MAX_CONVERSATION_ID_LENGTH @@ -140,34 +122,29 @@ private static boolean isValidEmail(String email) { return email != null && email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"); } - private static boolean isValidUrl(String url) { - // Basic URL validation - checks for http/https scheme - return url != null && (url.startsWith("http://") || url.startsWith("https://")); - } - + /** + * Cleans GSM number by removing non-digit characters and enforcing minimum + * length. + * Universal logic: keeps only digits (and + prefix if present), min length 5. + */ public static String cleanGsmNumber(String phone, List errors) { if (phone == null || phone.isEmpty()) return phone; - String cleanPhone = phone.replaceAll("[\\s\\-\\(\\)]", ""); - - if (!cleanPhone.replaceAll("\\+", "").matches("\\d+")) { - errors.add("Invalid phone number format: " + phone); - return cleanPhone; + boolean hasPlusPrefix = phone.trim().startsWith("+"); + StringBuilder digitsBuilder = new StringBuilder(); + for (char c : phone.toCharArray()) { + if (Character.isDigit(c)) { + digitsBuilder.append(c); + } } + String digitsOnly = digitsBuilder.toString(); + String cleanPhone = hasPlusPrefix ? "+" + digitsOnly : digitsOnly; - if (cleanPhone.startsWith("+")) { - if (cleanPhone.length() < 8) - errors.add("International phone number too short: " + phone); - } else if (cleanPhone.startsWith("00")) { - if (cleanPhone.length() < 9) - errors.add("International phone number (00 format) too short: " + phone); - } else if (cleanPhone.startsWith("0")) { - if (cleanPhone.length() < 7) - errors.add("National phone number too short: " + phone); - } else { - if (cleanPhone.length() < 6) - errors.add("Local phone number too short: " + phone); + // Enforce minimum length of 5 digits + if (digitsOnly.length() < 5) { + errors.add("Phone number too short (minimum 5 digits required): " + phone); + return cleanPhone; } return cleanPhone; diff --git a/src/test/java/com/tapsilat/EnumTest.java b/src/test/java/com/tapsilat/EnumTest.java deleted file mode 100644 index 5f3464b..0000000 --- a/src/test/java/com/tapsilat/EnumTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.tapsilat; - -import com.tapsilat.enums.BillingType; -import com.tapsilat.enums.ItemType; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * Unit tests for enum classes. - */ -class EnumTest { - - @Test - void testBillingTypeEnum() { - // Test enum values - assertEquals("PERSONAL", BillingType.PERSONAL.getCode()); - assertEquals("BUSINESS", BillingType.BUSINESS.getCode()); - - // Test fromCode - assertEquals(BillingType.PERSONAL, BillingType.fromCode("PERSONAL")); - assertEquals(BillingType.PERSONAL, BillingType.fromCode("personal")); - assertEquals(BillingType.BUSINESS, BillingType.fromCode("BUSINESS")); - assertEquals(BillingType.BUSINESS, BillingType.fromCode("business")); - - // Test invalid codes - assertNull(BillingType.fromCode("INVALID")); - assertNull(BillingType.fromCode(null)); - assertNull(BillingType.fromCode("")); - - // Test toString - assertEquals("PERSONAL", BillingType.PERSONAL.toString()); - assertEquals("BUSINESS", BillingType.BUSINESS.toString()); - } - - @Test - void testItemTypeEnum() { - // Test enum values - assertEquals("PHYSICAL", ItemType.PHYSICAL.getCode()); - assertEquals("DIGITAL", ItemType.DIGITAL.getCode()); - assertEquals("SERVICE", ItemType.SERVICE.getCode()); - - // Test fromCode - assertEquals(ItemType.PHYSICAL, ItemType.fromCode("PHYSICAL")); - assertEquals(ItemType.PHYSICAL, ItemType.fromCode("physical")); - assertEquals(ItemType.DIGITAL, ItemType.fromCode("DIGITAL")); - assertEquals(ItemType.DIGITAL, ItemType.fromCode("digital")); - assertEquals(ItemType.SERVICE, ItemType.fromCode("SERVICE")); - assertEquals(ItemType.SERVICE, ItemType.fromCode("service")); - - // Test invalid codes - assertNull(ItemType.fromCode("INVALID")); - assertNull(ItemType.fromCode(null)); - assertNull(ItemType.fromCode("")); - - // Test toString - assertEquals("PHYSICAL", ItemType.PHYSICAL.toString()); - assertEquals("DIGITAL", ItemType.DIGITAL.toString()); - assertEquals("SERVICE", ItemType.SERVICE.toString()); - } -} diff --git a/src/test/java/com/tapsilat/IntegrationTest.java b/src/test/java/com/tapsilat/IntegrationTest.java deleted file mode 100644 index 80b98aa..0000000 --- a/src/test/java/com/tapsilat/IntegrationTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.tapsilat; - -import com.tapsilat.config.TapsilatConfig; -import com.tapsilat.model.order.OrderRequest; -import com.tapsilat.model.order.OrderResponse; -import com.tapsilat.model.common.Buyer; -import com.tapsilat.model.common.BillingAddress; -import com.tapsilat.model.common.BasketItem; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; -import static org.junit.jupiter.api.Assertions.*; - -public class IntegrationTest { - - private TapsilatClient client; - private String token; - - @BeforeEach - public void setUp() { - token = System.getenv("TAPSILAT_API_KEY"); - if (token == null) { - System.out.println("Warning: TAPSILAT_API_KEY not set. Skipping setup."); - return; - } - - TapsilatConfig config = new TapsilatConfig(); - config.setBaseUrl("https://panel.tapsilat.dev/api/v1"); - config.setBearerToken(token); - - client = new TapsilatClient(config); - } - - @Test - public void testCreateOrder() throws Exception { - if (token == null) { - System.out.println("Skipping testCreateOrder: No API Key"); - return; - } - - OrderRequest order = new OrderRequest(); - order.setAmount(BigDecimal.valueOf(10.0)); - order.setCurrency("TRY"); - order.setLocale("tr"); - - Buyer buyer = new Buyer(); - buyer.setId("123456"); - buyer.setName("John"); - buyer.setSurname("Doe"); - buyer.setEmail("john@doe.com"); - buyer.setGsmNumber("5321234567"); - buyer.setIdentityNumber("12345678901"); - buyer.setCity("Istanbul"); - buyer.setCountry("Turkey"); - buyer.setZipCode("34732"); - buyer.setIp("127.0.0.1"); - order.setBuyer(buyer); - - BillingAddress billing = new BillingAddress(); - billing.setContactName("John Doe"); - billing.setCity("Istanbul"); - billing.setCountry("Turkey"); - billing.setAddress("Test Address"); - billing.setZipCode("34732"); - order.setBillingAddress(billing); - - List items = new ArrayList<>(); - BasketItem item1 = new BasketItem(); - item1.setId("1"); - item1.setName("Item 1"); - item1.setPrice(5.0); - item1.setItemType("PHYSICAL"); - items.add(item1); - - BasketItem item2 = new BasketItem(); - item2.setId("2"); - item2.setName("Item 2"); - item2.setPrice(5.0); - item2.setItemType("PHYSICAL"); - items.add(item2); - - order.setBasketItems(items); - - OrderResponse response = client.orders().create(order); - assertNotNull(response); - assertNotNull(response.getReferenceId()); - System.out.println("Order Created: " + response.getReferenceId()); - } -} diff --git a/src/test/java/com/tapsilat/integration/IntegrationTest.java b/src/test/java/com/tapsilat/integration/IntegrationTest.java new file mode 100644 index 0000000..db04053 --- /dev/null +++ b/src/test/java/com/tapsilat/integration/IntegrationTest.java @@ -0,0 +1,363 @@ +package com.tapsilat.integration; + +import com.tapsilat.TapsilatClient; +import com.tapsilat.config.TapsilatConfig; +import com.tapsilat.exception.TapsilatException; +import com.tapsilat.model.order.*; +import com.tapsilat.model.common.*; +import com.tapsilat.model.subscription.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Integration tests that run against the real Tapsilat API. + * Reads TAPSILAT_API_KEY from environment variable or .env file. + * Mirrors tapsilat-py/tests/integration/integration_test.py + */ +@Tag("integration") +public class IntegrationTest { + + private TapsilatClient client; + private String token; + + @BeforeEach + public void setUp() { + token = System.getenv("TAPSILAT_API_KEY"); + + if (token == null) { + token = loadFromEnvFile("TAPSILAT_API_KEY"); + } + + if (token == null) { + System.out.println("Warning: TAPSILAT_API_KEY not set. Skipping setup."); + return; + } + + TapsilatConfig config = new TapsilatConfig(); + config.setBaseUrl("https://panel.tapsilat.dev/api/v1"); + config.setBearerToken(token); + + client = new TapsilatClient(config); + } + + /** + * Reads a key from the .env file in the project root. + * Supports KEY=VALUE format (no quotes handling needed for simple values). + */ + private String loadFromEnvFile(String key) { + // Try multiple possible .env locations + String[] paths = { ".env", "../.env" }; + for (String path : paths) { + File envFile = new File(path); + if (envFile.exists()) { + try (BufferedReader reader = new BufferedReader(new FileReader(envFile))) { + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (line.isEmpty() || line.startsWith("#")) + continue; + int eqIndex = line.indexOf('='); + if (eqIndex > 0) { + String k = line.substring(0, eqIndex).trim(); + String v = line.substring(eqIndex + 1).trim(); + if (k.equals(key)) { + return v; + } + } + } + } catch (IOException e) { + // Silently ignore read errors + } + } + } + return null; + } + + // ==================== Scenario 1: Basic Order ==================== + + @Test + public void testScenario1_BasicOrder() throws Exception { + if (token == null) { + skipTest("testScenario1_BasicOrder"); + return; + } + + OrderCreateRequest order = new OrderCreateRequest(); + order.setAmount(BigDecimal.valueOf(100.00)); + order.setCurrency("TRY"); + order.setLocale("tr"); + order.setBuyer(new Buyer("John", "Doe", "test@example.com")); + + OrderResponse response = client.orders().create(order); + assertNotNull(response); + assertNotNull(response.getReferenceId()); + } + + // ==================== Scenario 2: Order with Basket Items ==================== + + @Test + public void testScenario2_OrderWithBasketItems() throws Exception { + if (token == null) { + skipTest("testScenario2_OrderWithBasketItems"); + return; + } + + OrderCreateRequest order = new OrderCreateRequest(); + order.setAmount(BigDecimal.valueOf(30.49)); + order.setCurrency("TRY"); + order.setLocale("tr"); + order.setBuyer(new Buyer("John", "Doe", "test@example.com")); + + BasketItem item1 = new BasketItem(); + item1.setId("B001"); + item1.setName("Item 1"); + item1.setPrice(10.00); + item1.setItemType("PHYSICAL"); + + BasketItem item2 = new BasketItem(); + item2.setId("B002"); + item2.setName("Item 2"); + item2.setPrice(20.49); + item2.setItemType("PHYSICAL"); + + order.setBasketItems(Arrays.asList(item1, item2)); + + OrderResponse response = client.orders().create(order); + assertNotNull(response); + assertNotNull(response.getReferenceId()); + } + + // ==================== Scenario 3: Order with Addresses ==================== + + @Test + public void testScenario3_OrderWithAddresses() throws Exception { + if (token == null) { + skipTest("testScenario3_OrderWithAddresses"); + return; + } + + OrderCreateRequest order = new OrderCreateRequest(); + order.setAmount(BigDecimal.valueOf(25.00)); + order.setCurrency("TRY"); + order.setLocale("tr"); + order.setBuyer(new Buyer("John", "Doe", "test@example.com")); + + BillingAddress billing = new BillingAddress(); + billing.setAddress("123 Main St"); + billing.setCity("Istanbul"); + billing.setCountry("TR"); + billing.setContactName("John Doe"); + billing.setZipCode("34000"); + order.setBillingAddress(billing); + + ShippingAddress shipping = new ShippingAddress(); + shipping.setAddress("456 Oak Ave"); + shipping.setCity("Istanbul"); + shipping.setCountry("TR"); + shipping.setContactName("Jane Doe"); + shipping.setZipCode("34001"); + order.setShippingAddress(shipping); + + OrderResponse response = client.orders().create(order); + assertNotNull(response); + assertNotNull(response.getReferenceId()); + } + + // ==================== Scenario 4: Installments ==================== + + @Test + public void testScenario4_Installments() throws Exception { + if (token == null) { + skipTest("testScenario4_Installments"); + return; + } + + OrderCreateRequest order = new OrderCreateRequest(); + order.setAmount(BigDecimal.valueOf(1200.00)); + order.setCurrency("TRY"); + order.setLocale("tr"); + order.setBuyer(new Buyer("John", "Doe", "test@example.com")); + order.setEnabledInstallments(Arrays.asList(2, 3, 6, 9)); + order.setPaymentMethods(true); + order.setPaymentOptions(Arrays.asList("credit_card", "cash")); + + OrderResponse response = client.orders().create(order); + assertNotNull(response); + assertNotNull(response.getReferenceId()); + } + + // ==================== Scenario 5: Order List ==================== + + @Test + public void testScenario5_GetOrders() throws Exception { + if (token == null) { + skipTest("testScenario5_GetOrders"); + return; + } + + try { + Map response = client.orders().list(1, 10, null, null, null, null, null); + assertNotNull(response); + } catch (TapsilatException e) { + fail("API Error: " + e.getMessage()); + } + } + + // ==================== Scenario 6: Organization Settings ==================== + + @Test + public void testScenario6_OrganizationSettings() throws Exception { + if (token == null) { + skipTest("testScenario6_OrganizationSettings"); + return; + } + + Map settings = client.orders().getOrganizationSettings(); + assertNotNull(settings); + } + + // ==================== Scenario 7: Subscription Lifecycle ==================== + + @Test + public void testScenario7_SubscriptionLifecycle() throws Exception { + if (token == null) { + skipTest("testScenario7_SubscriptionLifecycle"); + return; + } + + // Create Subscription + SubscriptionCreateRequest subRequest = new SubscriptionCreateRequest(); + subRequest.setAmount(new BigDecimal("100.0")); + subRequest.setCurrency("TRY"); + subRequest.setCycle(12); + subRequest.setPeriod(1); + subRequest.setPaymentDate(1); + subRequest.setTitle("Monthly Subscription"); + subRequest.setExternalReferenceId("ext_ref_java_test"); + subRequest.setSuccessUrl("https://example.com/success"); + subRequest.setFailureUrl("https://example.com/failure"); + + SubscriptionUser user = new SubscriptionUser(); + user.setFirstName("John"); + user.setLastName("Doe"); + user.setEmail("john.doe@example.com"); + user.setPhone("+905551234567"); + user.setIdentityNumber("12345678901"); + subRequest.setUser(user); + + SubscriptionCreateResponse createResponse = client.subscriptions().create(subRequest); + assertNotNull(createResponse); + assertNotNull(createResponse.getReferenceId()); + + String subRefId = createResponse.getReferenceId(); + + // Get Subscription + SubscriptionGetRequest getRequest = new SubscriptionGetRequest(); + getRequest.setReferenceId(subRefId); + SubscriptionDetail subscription = client.subscriptions().get(getRequest); + assertNotNull(subscription); + + // List Subscriptions + List subscriptions = client.subscriptions().list(1, 10); + assertNotNull(subscriptions); + + // Redirect Subscription + SubscriptionRedirectRequest redirectRequest = new SubscriptionRedirectRequest(); + redirectRequest.setSubscriptionId(subRefId); + SubscriptionRedirectResponse redirectResponse = client.subscriptions().redirect(redirectRequest); + assertNotNull(redirectResponse); + assertNotNull(redirectResponse.getUrl()); + + // Cancel Subscription + SubscriptionCancelRequest cancelRequest = new SubscriptionCancelRequest(); + cancelRequest.setReferenceId(subRefId); + Map cancelResponse = client.subscriptions().cancel(cancelRequest); + assertNotNull(cancelResponse); + } + + // ==================== Scenario 8: Order Operations Smoke Test + // ==================== + + @Test + public void testScenario8_OrderOperationsSmoke() throws Exception { + if (token == null) { + skipTest("testScenario8_OrderOperationsSmoke"); + return; + } + + // get_system_order_statuses + try { + Map statuses = client.orders().getSystemOrderStatuses(); + assertNotNull(statuses); + } catch (TapsilatException ignored) { + } + + // get_order_submerchants + try { + Map merchants = client.orders().getSubmerchants(1, 10); + assertNotNull(merchants); + } catch (TapsilatException ignored) { + } + + String dummyRef = "dummy_ref_123"; + + // get_order_by_conversation_id + try { + client.orders().getByConversationId(dummyRef); + } catch (TapsilatException ignored) { + } + + // order_accounting + try { + client.orders().accounting(new OrderAccountingRequest(dummyRef)); + } catch (TapsilatException ignored) { + } + + // order_postauth + try { + client.orders().postAuth(new OrderPostAuthRequest(new BigDecimal("10.0"), dummyRef)); + } catch (TapsilatException ignored) { + } + + // get_order_status + try { + client.orders().getStatus(dummyRef); + } catch (TapsilatException ignored) { + } + + // get_order_transactions + try { + client.orders().getTransactions(dummyRef); + } catch (TapsilatException ignored) { + } + + // cancel_order + try { + client.orders().cancel(dummyRef); + } catch (TapsilatException ignored) { + } + + // get_order_payment_details + try { + client.orders().getPaymentDetails(dummyRef, null); + } catch (TapsilatException ignored) { + } + } + + private void skipTest(String testName) { + System.out.println("Skipping " + testName + ": No API Key"); + } +} diff --git a/src/test/java/com/tapsilat/TapsilatClientComprehensiveExample.java b/src/test/java/com/tapsilat/integration/TapsilatClientComprehensiveExample.java similarity index 91% rename from src/test/java/com/tapsilat/TapsilatClientComprehensiveExample.java rename to src/test/java/com/tapsilat/integration/TapsilatClientComprehensiveExample.java index 7b10fde..6815447 100644 --- a/src/test/java/com/tapsilat/TapsilatClientComprehensiveExample.java +++ b/src/test/java/com/tapsilat/integration/TapsilatClientComprehensiveExample.java @@ -1,9 +1,11 @@ -package com.tapsilat; +package com.tapsilat.integration; + +import com.tapsilat.TapsilatClient; import com.tapsilat.config.TapsilatConfig; import com.tapsilat.enums.Currency; import com.tapsilat.enums.Locale; -import com.tapsilat.model.common.*; import com.tapsilat.model.order.*; import com.tapsilat.model.subscription.*; +import com.tapsilat.model.common.*; import com.tapsilat.model.order.*; import java.math.BigDecimal; import java.util.Arrays; @@ -25,7 +27,7 @@ public static void main(String[] args) { // Create buyer information Buyer buyer = new Buyer("John", "Doe", "johndoe@example.com"); - buyer.setPhone("+905321234567"); + buyer.setGsmNumber("+905321234567"); buyer.setIdentityNumber("12345678901"); // Create shipping address @@ -79,15 +81,13 @@ public static void main(String[] args) { Metadata metadata2 = new Metadata("customer_segment", "premium"); // Build the complete order request - OrderRequest orderRequest = new OrderRequest( + OrderCreateRequest orderRequest = new OrderCreateRequest( new BigDecimal("150.00"), Currency.TRY.getCode(), Locale.TR.getCode(), buyer ); - orderRequest.setDescription("Test Order with Complete Information"); - orderRequest.setCallbackUrl("https://example.com/callback"); orderRequest.setConversationId("test-order-" + System.currentTimeMillis()); orderRequest.setShippingAddress(shippingAddress); orderRequest.setBillingAddress(billingAddress); @@ -96,7 +96,7 @@ public static void main(String[] args) { orderRequest.setTaxAmount(0.0); orderRequest.setThreeDForce(true); orderRequest.setPartialPayment(false); - orderRequest.setPaymentMethods(Arrays.asList("CREDIT_CARD", "DEBIT_CARD")); + orderRequest.setPaymentMethods(true); orderRequest.setPaymentOptions(Arrays.asList("INSTALLMENT")); // Create the order diff --git a/src/test/java/com/tapsilat/TapsilatClientExample.java b/src/test/java/com/tapsilat/integration/TapsilatClientExample.java similarity index 87% rename from src/test/java/com/tapsilat/TapsilatClientExample.java rename to src/test/java/com/tapsilat/integration/TapsilatClientExample.java index 072e0f0..a49730a 100644 --- a/src/test/java/com/tapsilat/TapsilatClientExample.java +++ b/src/test/java/com/tapsilat/integration/TapsilatClientExample.java @@ -1,4 +1,6 @@ -package com.tapsilat; +package com.tapsilat.integration; + +import com.tapsilat.TapsilatClient; import com.tapsilat.builder.OrderRequestBuilder; import com.tapsilat.config.TapsilatConfig; @@ -7,11 +9,10 @@ import com.tapsilat.exception.TapsilatException; import com.tapsilat.model.common.Buyer; import com.tapsilat.model.common.Metadata; -import com.tapsilat.model.order.OrderRequest; +import com.tapsilat.model.order.OrderCreateRequest; import com.tapsilat.model.order.OrderResponse; import java.math.BigDecimal; -import java.util.Arrays; /** * Example usage of the Tapsilat Java SDK. @@ -48,16 +49,15 @@ private static void basicExample() { TapsilatClient client = new TapsilatClient(config); // Create buyer - Buyer buyer = new Buyer("John", "Doe", "john.doe@example.com", "+9099999999", "11111111111"); + Buyer buyer = new Buyer("John", "Doe", "john.doe@example.com", "11111111111"); + buyer.setGsmNumber("+9099999999"); // Create order request - OrderRequest orderRequest = new OrderRequest(); + OrderCreateRequest orderRequest = new OrderCreateRequest(); orderRequest.setAmount(new BigDecimal("150.75")); orderRequest.setCurrency("TRY"); orderRequest.setLocale("tr"); orderRequest.setBuyer(buyer); - orderRequest.setDescription("Premium Subscription - Annual Plan"); - orderRequest.setCallbackUrl("https://your-website.com/payment-complete"); orderRequest.setConversationId("order-" + System.currentTimeMillis()); // Create order @@ -90,13 +90,11 @@ private static void builderExample() { TapsilatClient client = new TapsilatClient(config); // Create order request using builder - OrderRequest orderRequest = OrderRequestBuilder.newBuilder() + OrderCreateRequest orderRequest = OrderRequestBuilder.newBuilder() .amount(150.75) .currency("TRY") .locale("tr") .buyer("John", "Doe", "john.doe@example.com", "+9099999999", "11111111111") - .description("Premium Subscription - Annual Plan") - .callbackUrl("https://your-website.com/payment-complete") .conversationId("order-" + System.currentTimeMillis()) .build(); @@ -130,13 +128,11 @@ private static void enumExample() { TapsilatClient client = new TapsilatClient(config); // Create order request using enums - OrderRequest orderRequest = OrderRequestBuilder.newBuilder() + OrderCreateRequest orderRequest = OrderRequestBuilder.newBuilder() .amount(new BigDecimal("99.99")) .currency(Currency.USD) .locale(Locale.EN) .buyer("Jane", "Smith", "jane.smith@example.com") - .description("Monthly Subscription") - .callbackUrl("https://your-website.com/payment-complete") .conversationId("order-" + System.currentTimeMillis()) .build(); @@ -175,13 +171,11 @@ private static void metadataExample() { Metadata campaignMetadata = new Metadata("campaign", "summer2025"); // Create order request with metadata - OrderRequest orderRequest = OrderRequestBuilder.newBuilder() + OrderCreateRequest orderRequest = OrderRequestBuilder.newBuilder() .amount(150.75) .currency(Currency.TRY) .locale(Locale.TR) .buyer("John", "Doe", "john.doe@example.com", "+9099999999", "11111111111") - .description("Premium Subscription - Annual Plan") - .callbackUrl("https://your-website.com/payment-complete") .conversationId("order-" + System.currentTimeMillis()) .metadata(productMetadata) .metadata(customerMetadata) diff --git a/src/test/java/com/tapsilat/TapsilatClientLiveExample.java b/src/test/java/com/tapsilat/integration/TapsilatClientLiveExample.java similarity index 89% rename from src/test/java/com/tapsilat/TapsilatClientLiveExample.java rename to src/test/java/com/tapsilat/integration/TapsilatClientLiveExample.java index d3bbce9..115f70c 100644 --- a/src/test/java/com/tapsilat/TapsilatClientLiveExample.java +++ b/src/test/java/com/tapsilat/integration/TapsilatClientLiveExample.java @@ -1,11 +1,13 @@ -package com.tapsilat; +package com.tapsilat.integration; + +import com.tapsilat.TapsilatClient; import com.tapsilat.builder.OrderRequestBuilder; import com.tapsilat.config.TapsilatConfig; import com.tapsilat.enums.Currency; import com.tapsilat.enums.Locale; import com.tapsilat.exception.TapsilatException; -import com.tapsilat.model.order.OrderRequest; +import com.tapsilat.model.order.OrderCreateRequest; import com.tapsilat.model.order.OrderResponse; import java.math.BigDecimal; @@ -36,13 +38,11 @@ public static void main(String[] args) { TapsilatClient client = new TapsilatClient(config); try { - OrderRequest orderRequest = OrderRequestBuilder.newBuilder() + OrderCreateRequest orderRequest = OrderRequestBuilder.newBuilder() .amount(new BigDecimal("10.00")) .currency(Currency.TRY) .locale(Locale.TR) .buyer("John", "Doe", "john.doe@example.com", "+9099999999", "11111111111") - .description("Live API test order") - .callbackUrl("https://example.com/payment-complete") .conversationId("order-" + System.currentTimeMillis()) .build(); diff --git a/src/test/java/com/tapsilat/TapsilatClientTest.java b/src/test/java/com/tapsilat/unit/TapsilatClientTest.java similarity index 87% rename from src/test/java/com/tapsilat/TapsilatClientTest.java rename to src/test/java/com/tapsilat/unit/TapsilatClientTest.java index 5b9d144..d9bb377 100644 --- a/src/test/java/com/tapsilat/TapsilatClientTest.java +++ b/src/test/java/com/tapsilat/unit/TapsilatClientTest.java @@ -1,4 +1,6 @@ -package com.tapsilat; +package com.tapsilat.unit; + +import com.tapsilat.TapsilatClient; import com.fasterxml.jackson.databind.ObjectMapper; import com.tapsilat.builder.OrderRequestBuilder; @@ -8,8 +10,9 @@ import com.tapsilat.exception.TapsilatException; import com.tapsilat.model.common.Buyer; import com.tapsilat.model.common.Metadata; -import com.tapsilat.model.order.OrderRequest; +import com.tapsilat.model.order.OrderCreateRequest; import com.tapsilat.model.order.OrderResponse; +import com.tapsilat.validation.OrderRequestValidator; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -36,13 +39,11 @@ void setUp() { @Test void testOrderRequestBuilder() { // Test builder pattern - OrderRequest orderRequest = OrderRequestBuilder.newBuilder() + OrderCreateRequest orderRequest = OrderRequestBuilder.newBuilder() .amount(150.75) .currency(Currency.TRY) .locale(Locale.TR) .buyer("John", "Doe", "john.doe@example.com") - .description("Test Order") - .callbackUrl("https://example.com/callback") .conversationId("test-order-123") .metadata("testKey", "testValue") .build(); @@ -57,8 +58,6 @@ void testOrderRequestBuilder() { assertEquals("john.doe@example.com", orderRequest.getBuyer().getEmail()); // Verify optional fields - assertEquals("Test Order", orderRequest.getDescription()); - assertEquals("https://example.com/callback", orderRequest.getCallbackUrl()); assertEquals("test-order-123", orderRequest.getConversationId()); assertNotNull(orderRequest.getMetadata()); assertEquals(1, orderRequest.getMetadata().size()); @@ -73,15 +72,16 @@ void testBuyerConstructor() { assertEquals("John", buyer1.getName()); assertEquals("Doe", buyer1.getSurname()); assertEquals("john.doe@example.com", buyer1.getEmail()); - assertNull(buyer1.getPhone()); + assertNull(buyer1.getGsmNumber()); assertNull(buyer1.getIdentityNumber()); // Test buyer with all fields - Buyer buyer2 = new Buyer("Jane", "Smith", "jane.smith@example.com", "+1234567890", "123456789"); + Buyer buyer2 = new Buyer("Jane", "Smith", "jane.smith@example.com", "123456789"); + buyer2.setGsmNumber("+1234567890"); assertEquals("Jane", buyer2.getName()); assertEquals("Smith", buyer2.getSurname()); assertEquals("jane.smith@example.com", buyer2.getEmail()); - assertEquals("+1234567890", buyer2.getPhone()); + assertEquals("+1234567890", buyer2.getGsmNumber()); assertEquals("123456789", buyer2.getIdentityNumber()); } @@ -163,7 +163,7 @@ void testOrderRequestValidation() { }); // Test order request with null amount - OrderRequest invalidRequest1 = new OrderRequest(); + OrderCreateRequest invalidRequest1 = new OrderCreateRequest(); invalidRequest1.setCurrency("TRY"); invalidRequest1.setLocale("tr"); invalidRequest1.setBuyer(new Buyer("John", "Doe", "john@example.com")); @@ -172,15 +172,17 @@ void testOrderRequestValidation() { client.createOrder(invalidRequest1); }); - // Test order request with null buyer - OrderRequest invalidRequest2 = new OrderRequest(); - invalidRequest2.setAmount(new BigDecimal("100")); - invalidRequest2.setCurrency("TRY"); - invalidRequest2.setLocale("tr"); - - assertThrows(TapsilatException.class, () -> { - client.createOrder(invalidRequest2); - }); + // Buyer is optional for order validation + OrderCreateRequest requestWithoutBuyer = new OrderCreateRequest(); + requestWithoutBuyer.setAmount(new BigDecimal("100")); + requestWithoutBuyer.setCurrency("TRY"); + requestWithoutBuyer.setLocale("tr"); + assertTrue(OrderRequestValidator.validate(requestWithoutBuyer).isEmpty()); + } + + @Test + void testOrderBuilderAcceptsNullOrderCardsList() { + assertDoesNotThrow(() -> OrderRequestBuilder.newBuilder().orderCards(null)); } @Test @@ -208,4 +210,4 @@ void testOrderResponseMapping() throws Exception { assertEquals("0d058ce3-3e55-47d8-8ea1-2b42a60b362c", response.getOrderId()); assertEquals("497b0212-3a51-4c52-aa75-0f93f613dd7c", response.getReferenceId()); } -} \ No newline at end of file +} diff --git a/src/test/java/com/tapsilat/ModelTest.java b/src/test/java/com/tapsilat/unit/model/CommonModelTest.java similarity index 97% rename from src/test/java/com/tapsilat/ModelTest.java rename to src/test/java/com/tapsilat/unit/model/CommonModelTest.java index 56e1442..8590e58 100644 --- a/src/test/java/com/tapsilat/ModelTest.java +++ b/src/test/java/com/tapsilat/unit/model/CommonModelTest.java @@ -1,4 +1,4 @@ -package com.tapsilat; +package com.tapsilat.unit.model; import com.tapsilat.model.common.*; import com.tapsilat.model.order.*; import com.tapsilat.model.subscription.*; import org.junit.jupiter.api.Test; @@ -27,8 +27,10 @@ void testBuyerEqualsAndHashCode() { assertNotEquals(buyer1.hashCode(), buyer3.hashCode()); // Test with optional fields - Buyer buyer4 = new Buyer("John", "Doe", "john@example.com", "+123", "123"); - Buyer buyer5 = new Buyer("John", "Doe", "john@example.com", "+123", "123"); + Buyer buyer4 = new Buyer("John", "Doe", "john@example.com", "123"); + buyer4.setGsmNumber("+123"); + Buyer buyer5 = new Buyer("John", "Doe", "john@example.com", "123"); + buyer5.setGsmNumber("+123"); assertEquals(buyer4, buyer5); assertEquals(buyer4.hashCode(), buyer5.hashCode()); } diff --git a/src/test/java/com/tapsilat/unit/model/OrderDTOSerializationTest.java b/src/test/java/com/tapsilat/unit/model/OrderDTOSerializationTest.java new file mode 100644 index 0000000..a5531c9 --- /dev/null +++ b/src/test/java/com/tapsilat/unit/model/OrderDTOSerializationTest.java @@ -0,0 +1,354 @@ +package com.tapsilat.unit.model; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tapsilat.model.common.*; +import com.tapsilat.model.order.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests JSON serialization of all order-related request and response DTOs. + * Mirrors test_order.py DTO serialization tests. + */ +class OrderDTOSerializationTest { + + private ObjectMapper objectMapper; + + @BeforeEach + void setUp() { + objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL); + } + + // ==================== OrderCreateRequest ==================== + + @Test + void testOrderCreateRequest_BasicSerialization() throws Exception { + OrderCreateRequest request = new OrderCreateRequest(); + request.setAmount(new BigDecimal("100")); + request.setCurrency("TRY"); + request.setLocale("tr"); + request.setBuyer(new Buyer("John", "Doe", "test@example.com")); + + String json = objectMapper.writeValueAsString(request); + @SuppressWarnings("unchecked") + Map map = objectMapper.readValue(json, Map.class); + + assertEquals(100, ((Number) map.get("amount")).intValue()); + assertEquals("TRY", map.get("currency")); + assertEquals("tr", map.get("locale")); + + @SuppressWarnings("unchecked") + Map buyer = (Map) map.get("buyer"); + assertEquals("John", buyer.get("name")); + assertEquals("Doe", buyer.get("surname")); + assertEquals("test@example.com", buyer.get("email")); + } + + @Test + void testOrderCreateRequest_OmitsNullFields() throws Exception { + OrderCreateRequest request = new OrderCreateRequest(); + request.setAmount(new BigDecimal("50")); + request.setCurrency("USD"); + request.setLocale("en"); + request.setBuyer(new Buyer("Jane", "Smith", "jane@test.com")); + + String json = objectMapper.writeValueAsString(request); + + assertFalse(json.contains("conversation_id")); + assertFalse(json.contains("metadata")); + assertFalse(json.contains("basket_items")); + assertFalse(json.contains("shipping_address")); + } + + @Test + @SuppressWarnings("unchecked") + void testOrderCreateRequest_FullSerialization() throws Exception { + OrderCreateRequest request = new OrderCreateRequest(); + request.setAmount(new BigDecimal("150")); + request.setCurrency("TRY"); + request.setLocale("tr"); + request.setBuyer(new Buyer("John", "Doe", "test@example.com")); + request.setConversationId("conv-id-123"); + request.setEnabledInstallments(Arrays.asList(3, 6)); + request.setExternalReferenceId("ext-ref"); + request.setPaymentMode("card"); + request.setRedirectSuccessUrl("https://example.com/success"); + request.setRedirectFailureUrl("https://example.com/fail"); + request.setThreeDForce(true); + + String json = objectMapper.writeValueAsString(request); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("conv-id-123", map.get("conversation_id")); + assertEquals("ext-ref", map.get("external_reference_id")); + assertEquals("card", map.get("payment_mode")); + assertEquals("https://example.com/success", map.get("redirect_success_url")); + assertEquals("https://example.com/fail", map.get("redirect_failure_url")); + assertTrue((Boolean) map.get("three_d_force")); + } + + // ==================== OrderResponse ==================== + + @Test + void testOrderResponse_Deserialization() throws Exception { + String json = "{\"order_id\":\"o123\", \"reference_id\":\"r456\", \"checkout_url\":\"https://checkout.test\"}"; + OrderResponse response = objectMapper.readValue(json, OrderResponse.class); + + assertEquals("o123", response.getOrderId()); + assertEquals("r456", response.getReferenceId()); + assertEquals("https://checkout.test", response.getCheckoutUrl()); + } + + @Test + void testOrderResponse_IgnoresUnknownFields() throws Exception { + String json = "{\"order_id\":\"o123\", \"unknown_field\":\"value\"}"; + OrderResponse response = objectMapper.readValue(json, OrderResponse.class); + assertEquals("o123", response.getOrderId()); + } + + // ==================== BasketItem ==================== + + @Test + @SuppressWarnings("unchecked") + void testBasketItem_Serialization() throws Exception { + BasketItem item = new BasketItem(); + item.setId("BI101"); + item.setName("Binocular"); + item.setPrice(19.99); + item.setItemType("PHYSICAL"); + + String json = objectMapper.writeValueAsString(item); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("BI101", map.get("id")); + assertEquals("Binocular", map.get("name")); + assertEquals(19.99, ((Number) map.get("price")).doubleValue()); + assertEquals("PHYSICAL", map.get("item_type")); + assertNull(map.get("category1")); + } + + @Test + @SuppressWarnings("unchecked") + void testBasketItem_AllFields() throws Exception { + BasketItemPayer payer = new BasketItemPayer(); + payer.setTitle("Company"); + + BasketItem item = new BasketItem(); + item.setId("item1"); + item.setPrice(100.0); + item.setName("Product"); + item.setCategory1("C1"); + item.setCategory2("C2"); + item.setItemType("PHYSICAL"); + item.setSubMerchantKey("key1"); + item.setSubMerchantPrice("100.0"); + item.setCoupon("SAVE10"); + item.setCouponDiscount(10.0); + item.setQuantity(1); + item.setQuantityFloat(1.0); + item.setQuantityUnit("pcs"); + item.setPaidAmount(90.0); + item.setData("extra"); + item.setPayer(payer); + item.setCommissionAmount(5.0); + item.setMcc("1234"); + + String json = objectMapper.writeValueAsString(item); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("item1", map.get("id")); + assertEquals(5.0, ((Number) map.get("commission_amount")).doubleValue()); + assertEquals(1.0, ((Number) map.get("quantity_float")).doubleValue()); + assertEquals("Company", ((Map) map.get("payer")).get("title")); + } + + // ==================== BillingAddress ==================== + + @Test + @SuppressWarnings("unchecked") + void testBillingAddress_Serialization() throws Exception { + BillingAddress billing = new BillingAddress(); + billing.setAddress("uskudar"); + billing.setCity("Istanbul"); + billing.setCountry("TR"); + billing.setContactName("Jane Doe"); + + String json = objectMapper.writeValueAsString(billing); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("uskudar", map.get("address")); + assertEquals("Istanbul", map.get("city")); + assertEquals("TR", map.get("country")); + assertEquals("Jane Doe", map.get("contact_name")); + assertNull(map.get("zip_code")); + } + + // ==================== Metadata ==================== + + @Test + @SuppressWarnings("unchecked") + void testMetadata_Serialization() throws Exception { + Metadata meta = new Metadata("key", "value"); + + String json = objectMapper.writeValueAsString(meta); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("key", map.get("key")); + assertEquals("value", map.get("value")); + } + + // ==================== OrderCard ==================== + + @Test + @SuppressWarnings("unchecked") + void testOrderCard_Serialization() throws Exception { + OrderCard card = new OrderCard(); + card.setCardId("123456789"); + card.setCardSequence(1); + + String json = objectMapper.writeValueAsString(card); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("123456789", map.get("card_id")); + assertEquals(1, ((Number) map.get("card_sequence")).intValue()); + } + + // ==================== RefundOrderRequest ==================== + + @Test + @SuppressWarnings("unchecked") + void testRefundOrderRequest_Serialization() throws Exception { + RefundOrderRequest request = new RefundOrderRequest(); + request.setAmount(new BigDecimal("50.0")); + request.setReferenceId("ref123"); + request.setOrderItemId("item001"); + + String json = objectMapper.writeValueAsString(request); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("ref123", map.get("reference_id")); + assertEquals("item001", map.get("order_item_id")); + } + + @Test + @SuppressWarnings("unchecked") + void testRefundOrderRequest_FullSerialization() throws Exception { + RefundOrderRequest request = new RefundOrderRequest(); + request.setAmount(new BigDecimal("100.0")); + request.setReferenceId("ref456"); + request.setOrderItemId("item002"); + request.setOrderItemPaymentId("payment002"); + + String json = objectMapper.writeValueAsString(request); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("ref456", map.get("reference_id")); + assertEquals("item002", map.get("order_item_id")); + assertEquals("payment002", map.get("order_item_payment_id")); + } + + // ==================== OrderAccountingRequest ==================== + + @Test + @SuppressWarnings("unchecked") + void testOrderAccountingRequest_Serialization() throws Exception { + OrderAccountingRequest request = new OrderAccountingRequest("ref123"); + + String json = objectMapper.writeValueAsString(request); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("ref123", map.get("order_reference_id")); + } + + // ==================== OrderPostAuthRequest ==================== + + @Test + @SuppressWarnings("unchecked") + void testOrderPostAuthRequest_Serialization() throws Exception { + OrderPostAuthRequest request = new OrderPostAuthRequest(new BigDecimal("50.0"), "ref123"); + + String json = objectMapper.writeValueAsString(request); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("ref123", map.get("reference_id")); + } + + // ==================== OrderPaymentTermCreateRequest ==================== + + @Test + @SuppressWarnings("unchecked") + void testOrderPaymentTermCreateRequest_Serialization() throws Exception { + OrderPaymentTermCreateRequest request = new OrderPaymentTermCreateRequest(); + request.setOrderId("order123"); + request.setTermReferenceId("term-ref-create"); + request.setAmount(new BigDecimal("200")); + request.setDueDate("2025-10-10 00:00:00"); + request.setTermSequence(2); + request.setRequired(false); + request.setStatus("active"); + + String json = objectMapper.writeValueAsString(request); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("order123", map.get("order_id")); + assertEquals("term-ref-create", map.get("term_reference_id")); + assertEquals(2, ((Number) map.get("term_sequence")).intValue()); + assertEquals(false, map.get("required")); + assertEquals("active", map.get("status")); + } + + // ==================== OrderManualCallbackRequest ==================== + + @Test + @SuppressWarnings("unchecked") + void testOrderManualCallbackRequest_Serialization() throws Exception { + OrderManualCallbackRequest request = new OrderManualCallbackRequest("ref-id"); + request.setConversationId("conv-id"); + + String json = objectMapper.writeValueAsString(request); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("ref-id", map.get("reference_id")); + assertEquals("conv-id", map.get("conversation_id")); + } + + // ==================== AddBasketItemRequest ==================== + + @Test + @SuppressWarnings("unchecked") + void testAddBasketItemRequest_Serialization() throws Exception { + BasketItem item = new BasketItem(); + item.setId("item-1"); + item.setName("Widget"); + item.setPrice(9.99); + + AddBasketItemRequest request = new AddBasketItemRequest("order-ref", item); + + String json = objectMapper.writeValueAsString(request); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("order-ref", map.get("order_reference_id")); + assertNotNull(map.get("basket_item")); + } + + // ==================== RemoveBasketItemRequest ==================== + + @Test + @SuppressWarnings("unchecked") + void testRemoveBasketItemRequest_Serialization() throws Exception { + RemoveBasketItemRequest request = new RemoveBasketItemRequest("order-ref", "item-1"); + + String json = objectMapper.writeValueAsString(request); + Map map = objectMapper.readValue(json, Map.class); + + assertEquals("order-ref", map.get("order_reference_id")); + assertEquals("item-1", map.get("basket_item_id")); + } +} diff --git a/src/test/java/com/tapsilat/unit/model/OrderModelTest.java b/src/test/java/com/tapsilat/unit/model/OrderModelTest.java new file mode 100644 index 0000000..9d8775b --- /dev/null +++ b/src/test/java/com/tapsilat/unit/model/OrderModelTest.java @@ -0,0 +1,144 @@ +package com.tapsilat.unit.model; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tapsilat.enums.Currency; +import com.tapsilat.enums.Locale; +import com.tapsilat.model.common.*; +import com.tapsilat.model.order.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.*; + +class OrderModelTest { + private ObjectMapper mapper; + + @BeforeEach + void setUp() { + mapper = new ObjectMapper(); + mapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL); + } + + @Test + void testOrderCreateRequestSerializationFull() throws JsonProcessingException { + Buyer buyer = new Buyer("John", "Doe", "test@example.com"); + buyer.setGsmNumber("+905551234567"); + buyer.setIdentityNumber("11111111111"); + buyer.setCity("Istanbul"); + buyer.setCountry("TR"); + buyer.setRegistrationAddress("Reg Address"); + buyer.setIp("127.0.0.1"); + + BasketItemPayer payer = new BasketItemPayer(); + payer.setAddress("Payer Addr"); + payer.setReferenceId("payer-ref"); + payer.setTaxOffice("TaxOfc"); + payer.setType("PERSONAL"); + BasketItem item = new BasketItem(); + item.setId("itm-1"); + item.setName("Laptop"); + item.setItemType("PHYSICAL"); + item.setPrice(100.0); + item.setQuantity(1); + item.setPayer(payer); + + BillingAddress billing = new BillingAddress(); + billing.setAddress("Bill Addr"); + billing.setBillingType("PERSONAL"); + billing.setCountry("TR"); + billing.setCity("Istanbul"); + billing.setContactName("Contact"); + + OrderConsent consent = new OrderConsent("Consent Title", "http://consent"); + + OrderCard card = new OrderCard(); + card.setCardId("card-1"); + card.setCardSequence(1); + + PaymentTerm term = new PaymentTerm(); + term.setAmount(new BigDecimal("50.0")); + term.setTermReferenceId("term-ref"); + term.setTermSequence(1); + term.setStatus("PENDING"); + + OrderPFSubMerchant pfSub = new OrderPFSubMerchant(); + pfSub.setId("pf-1"); + pfSub.setName("PF Name"); + pfSub.setMcc("1234"); + + ShippingAddress shipping = new ShippingAddress("Ship Addr", "City", "Contact Name", "TR", "34000"); + + SubOrganization subOrg = new SubOrganization(); + subOrg.setOrganizationName("Org Name"); + subOrg.setLegalCompanyTitle("Legal Title"); + subOrg.setSubMerchantKey("sm-key"); + subOrg.setAcquirer("ACQ"); + + Submerchant subMerch = new Submerchant(); + subMerch.setAmount(new BigDecimal("40.0")); + subMerch.setOrderBasketItemId("itm-1"); + + CheckoutDesign design = new CheckoutDesign(); + design.setInputBackgroundColor("#FFF"); + + OrderCreateRequest order = new OrderCreateRequest(); + order.setAmount(new BigDecimal("150.0")); + order.setCurrency(Currency.TRY.getCode()); + order.setLocale(Locale.TR.getCode()); + order.setBuyer(buyer); + order.setBasketItems(Collections.singletonList(item)); + order.setBillingAddress(billing); + order.setCheckoutDesign(design); + order.setConsents(Collections.singletonList(consent)); + order.setOrderCards(Collections.singletonList(card)); + order.setPaymentTerms(Collections.singletonList(term)); + order.setPfSubMerchant(pfSub); + order.setShippingAddress(shipping); + order.setSubOrganization(subOrg); + order.setSubmerchants(Collections.singletonList(subMerch)); + order.setThreeDForce(true); + + String json = mapper.writeValueAsString(order); + JsonNode node = mapper.readTree(json); + + assertEquals(150.0, node.get("amount").asDouble()); + assertEquals("TRY", node.get("currency").asText()); + assertEquals("tr", node.get("locale").asText()); + assertEquals("John", node.get("buyer").get("name").asText()); + assertEquals("TR", node.get("buyer").get("country").asText()); + assertEquals("Laptop", node.get("basket_items").get(0).get("name").asText()); + assertEquals("Payer Addr", node.get("basket_items").get(0).get("payer").get("address").asText()); + assertEquals("Bill Addr", node.get("billing_address").get("address").asText()); + assertEquals("#FFF", node.get("checkout_design").get("input_background_color").asText()); + assertEquals("Consent Title", node.get("consents").get(0).get("title").asText()); + assertEquals("card-1", node.get("order_cards").get(0).get("card_id").asText()); + assertEquals(50.0, node.get("payment_terms").get(0).get("amount").asDouble()); + assertEquals("PF Name", node.get("pf_sub_merchant").get("name").asText()); + assertEquals("Ship Addr", node.get("shipping_address").get("address").asText()); + assertEquals("ACQ", node.get("sub_organization").get("acquirer").asText()); + assertEquals(40.0, node.get("submerchants").get(0).get("amount").asDouble()); + assertTrue(node.get("three_d_force").asBoolean()); + } + + @Test + void testRefundOrderRequestSerialization() throws JsonProcessingException { + RefundOrderRequest refund = new RefundOrderRequest(); + refund.setReferenceId("ref123"); + refund.setAmount(new BigDecimal("50.0")); + refund.setOrderItemId("item001"); + + String json = mapper.writeValueAsString(refund); + JsonNode node = mapper.readTree(json); + + assertEquals("50.0", node.get("amount").asText()); + assertEquals("ref123", node.get("reference_id").asText()); + assertEquals("item001", node.get("order_item_id").asText()); + assertFalse(node.has("order_item_payment_id")); + } +} diff --git a/src/test/java/com/tapsilat/unit/model/OrganizationModelTest.java b/src/test/java/com/tapsilat/unit/model/OrganizationModelTest.java new file mode 100644 index 0000000..ef4210e --- /dev/null +++ b/src/test/java/com/tapsilat/unit/model/OrganizationModelTest.java @@ -0,0 +1,46 @@ +package com.tapsilat.unit.model; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tapsilat.model.organization.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class OrganizationModelTest { + private ObjectMapper mapper; + + @BeforeEach + void setUp() { + mapper = new ObjectMapper(); + mapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL); + } + + @Test + void testCallbackURLDTOSerialization() throws JsonProcessingException { + CallbackURLDTO dto = new CallbackURLDTO(); + dto.setCallbackUrl("http://success.url"); + dto.setFailCallbackUrl("http://fail.url"); + + String json = mapper.writeValueAsString(dto); + JsonNode node = mapper.readTree(json); + + assertEquals("http://success.url", node.get("callback_url").asText()); + assertEquals("http://fail.url", node.get("fail_callback_url").asText()); + } + + @Test + void testSetLimitUserRequestSerialization() throws JsonProcessingException { + SetLimitUserRequest request = new SetLimitUserRequest(); + request.setUserId("user-1"); + request.setLimitId("limit-1"); + + String json = mapper.writeValueAsString(request); + JsonNode node = mapper.readTree(json); + + assertEquals("user-1", node.get("user_id").asText()); + assertEquals("limit-1", node.get("limit_id").asText()); + } +} diff --git a/src/test/java/com/tapsilat/unit/model/SubscriptionModelTest.java b/src/test/java/com/tapsilat/unit/model/SubscriptionModelTest.java new file mode 100644 index 0000000..42f7ca1 --- /dev/null +++ b/src/test/java/com/tapsilat/unit/model/SubscriptionModelTest.java @@ -0,0 +1,64 @@ +package com.tapsilat.unit.model; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tapsilat.model.subscription.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +import static org.junit.jupiter.api.Assertions.*; + +class SubscriptionModelTest { + private ObjectMapper mapper; + + @BeforeEach + void setUp() { + mapper = new ObjectMapper(); + mapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL); + } + + @Test + void testSubscriptionCreateRequestSerialization() throws JsonProcessingException { + SubscriptionUser buyer = new SubscriptionUser(); + buyer.setFirstName("Sub"); + buyer.setLastName("User"); + buyer.setEmail("subuser@example.com"); + + SubscriptionCreateRequest request = new SubscriptionCreateRequest(); + request.setAmount(new BigDecimal("99.99")); + request.setCurrency("TRY"); + request.setUser(buyer); + request.setCycle(1); + request.setPeriod(1); + request.setExternalReferenceId("sub-ref-123"); + request.setSuccessUrl("http://callback.test"); + request.setPriceOption(new SubscriptionPriceOption(2, new BigDecimal("49.99"))); + + String json = mapper.writeValueAsString(request); + JsonNode node = mapper.readTree(json); + + assertEquals(99.99, node.get("amount").asDouble()); + assertEquals("TRY", node.get("currency").asText()); + assertEquals(1, node.get("cycle").asInt()); + assertEquals(1, node.get("period").asInt()); + assertEquals("sub-ref-123", node.get("external_reference_id").asText()); + assertEquals("http://callback.test", node.get("success_url").asText()); + assertEquals("Sub", node.get("user").get("first_name").asText()); + assertEquals(2, node.get("price_option").get("count").asInt()); + assertEquals(49.99, node.get("price_option").get("price").asDouble()); + } + + @Test + void testSubscriptionCancelRequestSerialization() throws JsonProcessingException { + SubscriptionCancelRequest request = new SubscriptionCancelRequest(); + request.setReferenceId("ref123"); + + String json = mapper.writeValueAsString(request); + JsonNode node = mapper.readTree(json); + + assertEquals("ref123", node.get("reference_id").asText()); + } +} diff --git a/src/test/java/com/tapsilat/unit/service/OrderServiceTest.java b/src/test/java/com/tapsilat/unit/service/OrderServiceTest.java new file mode 100644 index 0000000..7c16a64 --- /dev/null +++ b/src/test/java/com/tapsilat/unit/service/OrderServiceTest.java @@ -0,0 +1,704 @@ +package com.tapsilat.unit.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tapsilat.config.TapsilatConfig; +import com.tapsilat.exception.TapsilatException; +import com.tapsilat.model.common.BasketItem; +import com.tapsilat.model.common.Buyer; +import com.tapsilat.model.order.*; +import com.tapsilat.service.OrderService; +import com.tapsilat.unit.utils.MockHttpClient; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +class OrderServiceTest { + + private MockHttpClient httpClient; + private OrderService orderService; + private ObjectMapper objectMapper; + + @BeforeEach + void setUp() { + TapsilatConfig config = new TapsilatConfig(); + config.setBaseUrl("https://api.test"); + config.setBearerToken("test-token"); + + objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL); + httpClient = new MockHttpClient(); + orderService = new OrderService(httpClient, config, objectMapper); + } + + @Test + void testCreateOrderSuccess() throws Exception { + String jsonResponse = "{\"order_id\":\"mock-order-123\", \"reference_id\":\"mock-ref-123\", \"checkout_url\":\"https://checkout.test\"}"; + httpClient.setResponse(200, jsonResponse); + + OrderCreateRequest request = new OrderCreateRequest(); + request.setAmount(new BigDecimal("100")); + request.setCurrency("TRY"); + request.setLocale("tr"); + request.setBuyer(new Buyer("John", "Doe", "test@test.com")); + + OrderResponse response = orderService.create(request); + + assertNotNull(response); + assertEquals("mock-order-123", response.getOrderId()); + assertEquals("mock-ref-123", response.getReferenceId()); + assertEquals("https://checkout.test", response.getCheckoutUrl()); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/create")); + } + + @Test + void testCreateOrderWithBasketItems() throws Exception { + String jsonResponse = "{\"order_id\":\"order_basket\", \"reference_id\":\"ref_basket\", \"checkout_url\":\"https://checkout.test\"}"; + httpClient.setResponse(200, jsonResponse); + + OrderCreateRequest request = new OrderCreateRequest(); + request.setAmount(new BigDecimal("30.49")); + request.setCurrency("TRY"); + request.setLocale("tr"); + request.setBuyer(new Buyer("Test", "User", "test@test.com")); + + BasketItem item1 = new BasketItem(); + item1.setId("B001"); + item1.setName("Item 1"); + item1.setPrice(10.0); + item1.setItemType("PHYSICAL"); + + BasketItem item2 = new BasketItem(); + item2.setId("B002"); + item2.setName("Item 2"); + item2.setPrice(20.49); + + request.setBasketItems(Arrays.asList(item1, item2)); + + OrderResponse response = orderService.create(request); + + assertNotNull(response); + assertEquals("order_basket", response.getOrderId()); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/create")); + } + + // ==================== get ==================== + + @Test + void testGetOrderSuccess() throws Exception { + String jsonResponse = "{\"status\":8, \"reference_id\":\"mock-ref-123\", \"checkout_url\":\"https://checkout.test\"}"; + httpClient.setResponse(200, jsonResponse); + + OrderResponse response = orderService.get("mock-ref-123"); + + assertNotNull(response); + assertEquals("https://checkout.test", response.getCheckoutUrl()); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/mock-ref-123")); + } + + @Test + void testGetOrderFailure() throws Exception { + String errorJson = "{\"code\": 101160, \"error\": \"ORDER_ORDER_DETAIL_ORDER_NOT_FOUND\"}"; + httpClient.setResponse(400, errorJson); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.get("mock-failed-ref"); + }); + + assertTrue(exception.getMessage().contains("ORDER_ORDER_DETAIL_ORDER_NOT_FOUND")); + } + + // ==================== getByConversationId ==================== + + @Test + void testGetOrderByConversationIdSuccess() throws Exception { + String jsonResponse = "{\"checkout_url\":\"https://checkout.test\", \"status\":8}"; + httpClient.setResponse(200, jsonResponse); + + OrderResponse response = orderService.getByConversationId("mock-conv-id"); + + assertNotNull(response); + assertEquals("https://checkout.test", response.getCheckoutUrl()); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/conversation/mock-conv-id")); + } + + @Test + void testGetOrderByConversationIdFailure() throws Exception { + httpClient.setResponse(400, "{\"code\": 101160, \"error\": \"ORDER_ORDER_DETAIL_ORDER_NOT_FOUND\"}"); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.getByConversationId("mock-conv-fail"); + }); + assertNotNull(exception.getMessage()); + } + + // ==================== list ==================== + + @Test + void testGetOrderList() throws Exception { + String jsonResponse = "{\"page\":1, \"per_page\":3, \"rows\":[{},{},{}], \"total\":24, \"total_page\":8}"; + httpClient.setResponse(200, jsonResponse); + + Map response = orderService.list(1, 3, null, null, null, null, null); + + assertNotNull(response); + assertEquals(1, ((Number) response.get("page")).intValue()); + assertEquals(3, ((Number) response.get("per_page")).intValue()); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/list")); + assertTrue(captured.getUri().toString().contains("page=1")); + assertTrue(captured.getUri().toString().contains("per_page=3")); + } + + // ==================== getSubmerchants ==================== + + @Test + void testGetSubmerchants() throws Exception { + String jsonResponse = "{\"page\":1, \"per_page\":2, \"row\":[{},{}], \"total\":10, \"total_pages\":5}"; + httpClient.setResponse(200, jsonResponse); + + Map response = orderService.getSubmerchants(1, 2); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/submerchants")); + } + + // ==================== cancel ==================== + + @Test + void testCancelOrderSuccess() throws Exception { + String jsonResponse = "{\"is_success\":true, \"error\":\"ORDER_CANCEL_SUCCESS\", \"status\":\"101645\"}"; + httpClient.setResponse(200, jsonResponse); + + Map response = orderService.cancel("mock-ref-123"); + + assertNotNull(response); + assertTrue((Boolean) response.get("is_success")); + assertEquals("ORDER_CANCEL_SUCCESS", response.get("error")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/cancel")); + } + + @Test + void testCancelOrderNotFound() throws Exception { + httpClient.setResponse(400, "{\"code\": 101550, \"error\": \"ORDER_CANCEL_ORDER_GET_ORDER_NOT_FOUND\"}"); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.cancel("mock-not-found"); + }); + assertNotNull(exception.getMessage()); + } + + // ==================== refund ==================== + + @Test + void testRefundOrderSuccess() throws Exception { + String jsonResponse = "{\"is_success\":true, \"error\":\"REFUND_SUCCESSFUL\"}"; + httpClient.setResponse(200, jsonResponse); + + RefundOrderRequest request = new RefundOrderRequest(); + request.setReferenceId("mock-ref-123"); + request.setAmount(new BigDecimal("50.0")); + + Map response = orderService.refund(request); + + assertNotNull(response); + assertTrue((Boolean) response.get("is_success")); + assertEquals("REFUND_SUCCESSFUL", response.get("error")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/refund")); + } + + @Test + void testRefundOrderWithOptionalFields() throws Exception { + httpClient.setResponse(200, "{\"is_success\":true}"); + + RefundOrderRequest request = new RefundOrderRequest(); + request.setReferenceId("ref456"); + request.setAmount(new BigDecimal("100.0")); + request.setOrderItemId("item002"); + request.setOrderItemPaymentId("payment002"); + + Map response = orderService.refund(request); + assertNotNull(response); + } + + @Test + void testRefundOrderFailure() throws Exception { + httpClient.setResponse(400, "{\"code\": 201010, \"error\": \"REFUND_VALIDATION_ERROR\"}"); + + RefundOrderRequest request = new RefundOrderRequest(); + request.setReferenceId("order_ref_invalid"); + request.setAmount(BigDecimal.ZERO); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.refund(request); + }); + assertNotNull(exception.getMessage()); + } + + // ==================== refundAll ==================== + + @Test + void testRefundAllSuccess() throws Exception { + httpClient.setResponse(200, "{\"is_success\":true, \"error\":\"REFUND_ALL_SUCCESSFUL\"}"); + + Map response = orderService.refundAll("order_ref_xyz"); + + assertNotNull(response); + assertTrue((Boolean) response.get("is_success")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/refund-all")); + } + + @Test + void testRefundAllFailure() throws Exception { + httpClient.setResponse(400, "{\"code\": 201020, \"error\": \"ORDER_NOT_FOUND_FOR_REFUND_ALL\"}"); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.refundAll("order_ref_nonexistent"); + }); + assertNotNull(exception.getMessage()); + } + + // ==================== getPaymentDetails ==================== + + @Test + void testGetPaymentDetailsById() throws Exception { + httpClient.setResponse(200, "{\"id\":\"mock-payment-details-id\"}"); + + Map response = orderService.getPaymentDetails("mock-ref-id", null); + + assertNotNull(response); + assertEquals("mock-payment-details-id", response.get("id")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/mock-ref-id/payment-details")); + } + + @Test + void testGetPaymentDetailsWithConversationId() throws Exception { + httpClient.setResponse(200, "{\"id\":\"mock-payment-details-id-conv\"}"); + + Map response = orderService.getPaymentDetails("mock-ref-id", "mock-conv-id"); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/payment-details")); + } + + @Test + void testGetPaymentDetailsNotFound() throws Exception { + httpClient.setResponse(400, + "{\"code\": 101230, \"error\": \"ORDER_ORDER_PAYMENT_DETAIL_ORDER_DETAIL_NOT_FOUND\"}"); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.getPaymentDetails("mock-ref-id", null); + }); + assertNotNull(exception.getMessage()); + } + + // ==================== getStatus ==================== + + @Test + void testGetStatusSuccess() throws Exception { + String jsonResponse = "{\"status\":\"Refunded\"}"; + httpClient.setResponse(200, jsonResponse); + + Map response = orderService.getStatus("mock-ref-123"); + + assertNotNull(response); + assertEquals("Refunded", response.get("status")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/mock-ref-123/status")); + } + + @Test + void testGetStatusNotFound() throws Exception { + httpClient.setResponse(400, "{\"code\": 100810, \"error\": \"ORDER_GET_NOT_FOUND\"}"); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.getStatus("mock-ref-123"); + }); + assertNotNull(exception.getMessage()); + } + + // ==================== getTransactions ==================== + + @Test + void testGetTransactionsSuccess() throws Exception { + httpClient.setResponse(200, "{\"transactions\":[{\"id\":\"mock-transaction-1\"}]}"); + + Map response = orderService.getTransactions("mock-ref-123"); + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/mock-ref-123/transactions")); + } + + @Test + void testGetTransactionsNotFound() throws Exception { + httpClient.setResponse(400, "{\"code\": 101260, \"error\": \"ORDER_GET_ORDER_TXS_GET_ORDER_NOT_FOUND\"}"); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.getTransactions("mock-ref-123"); + }); + assertNotNull(exception.getMessage()); + } + + // ==================== accounting ==================== + + @Test + void testAccountingSuccess() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + OrderAccountingRequest request = new OrderAccountingRequest("mock-ref-123"); + Map response = orderService.accounting(request); + + assertNotNull(response); + assertTrue((Boolean) response.get("success")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/accounting")); + } + + // ==================== postAuth ==================== + + @Test + void testPostAuthSuccess() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + OrderPostAuthRequest request = new OrderPostAuthRequest(new BigDecimal("50.0"), "mock-ref-123"); + Map response = orderService.postAuth(request); + + assertNotNull(response); + assertTrue((Boolean) response.get("success")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/postauth")); + } + + // ==================== systemOrderStatuses ==================== + + @Test + void testGetSystemOrderStatuses() throws Exception { + httpClient.setResponse(200, "{\"statuses\":[]}"); + + Map response = orderService.getSystemOrderStatuses(); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/system/order-statuses")); + } + + // ==================== Term Operations ==================== + + @Test + void testGetTerm() throws Exception { + httpClient.setResponse(200, "{\"term_reference_id\":\"abc\"}"); + + Map response = orderService.getTerm("abc"); + + assertNotNull(response); + assertEquals("abc", response.get("term_reference_id")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/term")); + assertTrue(captured.getUri().toString().contains("term_reference_id=abc")); + } + + @Test + void testCreateTermSuccess() throws Exception { + httpClient.setResponse(200, "{\"message\":\"ORDER_ADD_PAYMENT_TERM_SUCCESS\", \"code\":156050}"); + + OrderPaymentTermCreateRequest request = new OrderPaymentTermCreateRequest(); + request.setOrderId("order123"); + request.setTermReferenceId("term-ref-create"); + request.setAmount(new BigDecimal("200")); + request.setDueDate("2025-10-10 00:00:00"); + request.setTermSequence(2); + request.setRequired(false); + request.setStatus("active"); + + Map response = orderService.createTerm(request); + + assertNotNull(response); + assertEquals("ORDER_ADD_PAYMENT_TERM_SUCCESS", response.get("message")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/term")); + } + + @Test + void testCreateTermFailure_ExceedsOrderAmount() throws Exception { + httpClient.setResponse(400, + "{\"code\": 156025, \"error\": \"ORDER_ADD_PAYMENT_TERM_AMOUNT_EXCEEDS_ORDER_AMOUNT\"}"); + + OrderPaymentTermCreateRequest request = new OrderPaymentTermCreateRequest(); + request.setOrderId("order123"); + request.setAmount(new BigDecimal("600")); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.createTerm(request); + }); + assertNotNull(exception.getMessage()); + } + + @Test + void testDeleteTerm() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + Map response = orderService.deleteTerm("order123", "term-ref-abc"); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("DELETE", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/term")); + } + + @Test + void testUpdateTerm() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + OrderPaymentTermUpdateRequest request = new OrderPaymentTermUpdateRequest(); + request.setTermReferenceId("abc"); + request.setAmount(new BigDecimal("100.0")); + request.setDueDate("2023-12-31"); + request.setRequired(true); + request.setStatus("pending"); + request.setTermSequence(1); + + Map response = orderService.updateTerm(request); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("PATCH", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/term")); + } + + @Test + void testRefundTerm() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + OrderTermRefundRequest request = new OrderTermRefundRequest(); + request.setTermId("term-id"); + request.setAmount(new BigDecimal("25")); + request.setReferenceId("ref-123"); + + Map response = orderService.refundTerm(request); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/term/refund")); + } + + @Test + void testTerminateTerm() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + Map response = orderService.terminateTerm("term-ref-id", "Cancelled by user"); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/term/terminate")); + } + + // ==================== terminate ==================== + + @Test + void testTerminateOrderSuccess() throws Exception { + httpClient.setResponse(200, "{\"message\":\"ORDER_TERMINATE_ORDER_SUCCESS\", \"code\":338100}"); + + Map response = orderService.terminate("mock-ref-id"); + + assertNotNull(response); + assertEquals("ORDER_TERMINATE_ORDER_SUCCESS", response.get("message")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/terminate")); + } + + @Test + void testTerminateOrderNotFound() throws Exception { + httpClient.setResponse(400, "{\"code\": 338000, \"error\": \"ORDER_TERMINATE_ORDER_NOT_FOUND\"}"); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.terminate("mock-ref-id"); + }); + assertNotNull(exception.getMessage()); + } + + // ==================== manualCallback ==================== + + @Test + void testManualCallbackSuccess() throws Exception { + httpClient.setResponse(200, "{\"message\":\"ORDER_MANUAL_CALLBACK_SUCCESS\", \"code\":337100}"); + + OrderManualCallbackRequest request = new OrderManualCallbackRequest("mock-ref-id"); + request.setConversationId("mock-conv-id"); + + Map response = orderService.manualCallback(request); + + assertNotNull(response); + assertEquals("ORDER_MANUAL_CALLBACK_SUCCESS", response.get("message")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/callback")); + } + + @Test + void testManualCallbackFailed() throws Exception { + httpClient.setResponse(400, "{\"code\": 12000, \"error\": \"ACTION_FAILED\"}"); + + OrderManualCallbackRequest request = new OrderManualCallbackRequest("mock-ref-id"); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.manualCallback(request); + }); + assertNotNull(exception.getMessage()); + } + + // ==================== relatedUpdate ==================== + + @Test + void testRelatedUpdateSuccess() throws Exception { + httpClient.setResponse(200, + "{\"message\":\"ORDER_UPDATE_ORDER_SUCCESS\", \"code\":156170, \"is_success\":true}"); + + Map response = orderService.relatedUpdate("mock-ref-id", "mock-related-ref-id"); + + assertNotNull(response); + assertTrue((Boolean) response.get("is_success")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("PATCH", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/releated")); + } + + @Test + void testRelatedUpdateNotFound() throws Exception { + httpClient.setResponse(400, "{\"code\": 12000, \"error\": \"ACTION_FAILED\"}"); + + TapsilatException exception = assertThrows(TapsilatException.class, () -> { + orderService.relatedUpdate("mock-ref-id", "mock-related-ref-id"); + }); + assertNotNull(exception.getMessage()); + } + + // ==================== Basket Item Operations ==================== + + @Test + void testAddBasketItem() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + BasketItem item = new BasketItem(); + item.setId("BI101"); + item.setName("Binocular"); + item.setPrice(19.99); + + AddBasketItemRequest request = new AddBasketItemRequest("order-ref-123", item); + Map response = orderService.addBasketItem(request); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/basket-item")); + } + + @Test + void testRemoveBasketItem() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + RemoveBasketItemRequest request = new RemoveBasketItemRequest("order-ref-123", "BI101"); + Map response = orderService.removeBasketItem(request); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("DELETE", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/basket-item")); + } + + @Test + void testUpdateBasketItem() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + BasketItem item = new BasketItem(); + item.setId("BI101"); + item.setName("Updated Binocular"); + item.setPrice(24.99); + + UpdateBasketItemRequest request = new UpdateBasketItemRequest("order-ref-123", item); + Map response = orderService.updateBasketItem(request); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("PATCH", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/order/basket-item")); + } + + // ==================== getOrganizationSettings ==================== + + @Test + void testGetOrganizationSettings() throws Exception { + httpClient.setResponse(200, "{\"settings\":{}}"); + + Map response = orderService.getOrganizationSettings(); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/settings")); + } +} diff --git a/src/test/java/com/tapsilat/unit/service/OrganizationServiceTest.java b/src/test/java/com/tapsilat/unit/service/OrganizationServiceTest.java new file mode 100644 index 0000000..40bb07c --- /dev/null +++ b/src/test/java/com/tapsilat/unit/service/OrganizationServiceTest.java @@ -0,0 +1,279 @@ +package com.tapsilat.unit.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tapsilat.config.TapsilatConfig; +import com.tapsilat.exception.TapsilatException; +import com.tapsilat.model.organization.*; +import com.tapsilat.service.OrganizationService; +import com.tapsilat.unit.utils.MockHttpClient; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +class OrganizationServiceTest { + + private MockHttpClient httpClient; + private OrganizationService organizationService; + private ObjectMapper objectMapper; + + @BeforeEach + void setUp() { + TapsilatConfig config = new TapsilatConfig(); + config.setBaseUrl("https://api.test"); + config.setBearerToken("test-token"); + + objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL); + httpClient = new MockHttpClient(); + organizationService = new OrganizationService(httpClient, config, objectMapper); + } + + // ==================== getCallback ==================== + + @Test + void testGetCallbackSuccess() throws Exception { + httpClient.setResponse(200, "{\"callback_url\":\"http://success.url\"}"); + + Map response = organizationService.getCallback(); + + assertNotNull(response); + assertEquals("http://success.url", response.get("callback_url")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/callback")); + } + + // ==================== updateCallback ==================== + + @Test + void testUpdateCallbackSuccess() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + CallbackURLDTO request = new CallbackURLDTO(); + request.setCallbackUrl("http://newsuccess.test"); + Map response = organizationService.updateCallback(request); + + assertNotNull(response); + assertTrue((Boolean) response.get("success")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("PATCH", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/callback")); + } + + // ==================== createBusiness ==================== + + @Test + void testCreateBusinessSuccess() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + OrgCreateBusinessRequest request = new OrgCreateBusinessRequest(); + request.setAddress("Test Address"); + request.setBusinessName("Test Business"); + request.setBusinessType(0); + request.setEmail("test@test.com"); + request.setFirstName("John"); + request.setLastName("Doe"); + request.setPhone("+905551234567"); + request.setIdentityNumber("12345678901"); + request.setTaxNumber("1234567890"); + request.setTaxOffice("Test Office"); + request.setZipCode("34000"); + + Map response = organizationService.createBusiness(request); + + assertNotNull(response); + assertTrue((Boolean) response.get("success")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/business/create")); + } + + // ==================== getCurrencies ==================== + + @Test + void testGetCurrencies() throws Exception { + httpClient.setResponse(200, "{\"currencies\":[]}"); + + Map response = organizationService.getCurrencies(); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/currencies")); + } + + // ==================== getLimitUser ==================== + + @Test + void testGetLimitUser() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + Map response = organizationService.getLimitUser("user-123"); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/limit/user")); + assertTrue(captured.getUri().toString().contains("user_id=user-123")); + } + + // ==================== setLimitUser ==================== + + @Test + void testSetLimitUser() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + SetLimitUserRequest request = new SetLimitUserRequest("user-123", "limit-1"); + Map response = organizationService.setLimitUser(request); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/limit/user")); + } + + // ==================== getLimits ==================== + + @Test + void testGetLimits() throws Exception { + httpClient.setResponse(200, "{\"limits\":[]}"); + + Map response = organizationService.getLimits(); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/limits")); + } + + // ==================== listVpos ==================== + + @Test + void testListVpos() throws Exception { + httpClient.setResponse(200, "{\"vpos\":[]}"); + + GetVposRequest request = new GetVposRequest("TRY"); + Map response = organizationService.listVpos(request); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/list-vpos")); + } + + // ==================== getMeta ==================== + + @Test + void testGetMeta() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + Map response = organizationService.getMeta("meta_name"); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/meta/meta_name")); + } + + // ==================== getScopes ==================== + + @Test + void testGetScopes() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + Map response = organizationService.getScopes(); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/scopes")); + } + + // ==================== getSuborganizations ==================== + + @Test + void testGetSuborganizations() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + Map response = organizationService.getSuborganizations(1, 10); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/suborganizations")); + assertTrue(captured.getUri().toString().contains("page=1")); + assertTrue(captured.getUri().toString().contains("per_page=10")); + } + + // ==================== createUser ==================== + + @Test + void testCreateUser() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + OrgCreateUserRequest request = new OrgCreateUserRequest(); + request.setEmail("test@test.com"); + request.setFirstName("John"); + request.setLastName("Doe"); + request.setPhone("+905551234567"); + request.setConversationId("conv-1"); + request.setIdentityNumber("12345678901"); + request.setIsMailVerified(true); + request.setReferenceId("ref-1"); + + Map response = organizationService.createUser(request); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/user/create")); + } + + // ==================== verifyUser ==================== + + @Test + void testVerifyUser() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + OrgUserVerifyRequest request = new OrgUserVerifyRequest("user-123"); + Map response = organizationService.verifyUser(request); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/user/verify")); + } + + // ==================== verifyUserMobile ==================== + + @Test + void testVerifyUserMobile() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + OrgUserMobileVerifyRequest request = new OrgUserMobileVerifyRequest("user-123"); + Map response = organizationService.verifyUserMobile(request); + + assertNotNull(response); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/organization/user/verify-mobile")); + } +} diff --git a/src/test/java/com/tapsilat/unit/service/SubscriptionServiceTest.java b/src/test/java/com/tapsilat/unit/service/SubscriptionServiceTest.java new file mode 100644 index 0000000..b108276 --- /dev/null +++ b/src/test/java/com/tapsilat/unit/service/SubscriptionServiceTest.java @@ -0,0 +1,144 @@ +package com.tapsilat.unit.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tapsilat.config.TapsilatConfig; +import com.tapsilat.model.subscription.*; +import com.tapsilat.service.SubscriptionService; +import com.tapsilat.unit.utils.MockHttpClient; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +class SubscriptionServiceTest { + + private MockHttpClient httpClient; + private SubscriptionService subscriptionService; + private ObjectMapper objectMapper; + + @BeforeEach + void setUp() { + TapsilatConfig config = new TapsilatConfig(); + config.setBaseUrl("https://api.test"); + config.setBearerToken("test-token"); + + objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL); + httpClient = new MockHttpClient(); + subscriptionService = new SubscriptionService(httpClient, config, objectMapper); + } + + // ==================== create ==================== + + @Test + void testCreateSubscriptionSuccess() throws Exception { + String jsonResponse = "{\"reference_id\":\"sub-ref-new\", \"code\":100, \"message\":\"Success\"}"; + httpClient.setResponse(200, jsonResponse); + + SubscriptionCreateRequest request = new SubscriptionCreateRequest(); + request.setTitle("Monthly Plan"); + request.setAmount(new BigDecimal("100.0")); + request.setCurrency("TRY"); + request.setPeriod(30); + + SubscriptionUser user = new SubscriptionUser(); + user.setFirstName("John"); + user.setLastName("Doe"); + user.setEmail("test@test.com"); + request.setUser(user); + + SubscriptionCreateResponse response = subscriptionService.create(request); + + assertNotNull(response); + assertEquals("sub-ref-new", response.getReferenceId()); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/subscription/create")); + } + + // ==================== get ==================== + + @Test + void testGetSubscriptionSuccess() throws Exception { + String jsonResponse = "{\"external_reference_id\":\"ext-ref-123\", \"title\":\"My Subscription\"}"; + httpClient.setResponse(200, jsonResponse); + + SubscriptionGetRequest request = new SubscriptionGetRequest(); + request.setReferenceId("sub-ref-123"); + SubscriptionDetail response = subscriptionService.get(request); + + assertNotNull(response); + assertEquals("ext-ref-123", response.getExternalReferenceId()); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/subscription")); + } + + // ==================== list ==================== + + @Test + void testListSubscriptionsSuccess() throws Exception { + String jsonResponse = "{\"page\":1, \"per_page\":10, \"items\":[], \"total\":0}"; + httpClient.setResponse(200, jsonResponse); + + List response = subscriptionService.list(1, 10); + assertNotNull(response); + assertTrue(response.isEmpty()); + + Map rawResponse = subscriptionService.listResponse(1, 10); + + assertNotNull(rawResponse); + assertEquals(1, ((Number) rawResponse.get("page")).intValue()); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("GET", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/subscription/list")); + assertTrue(captured.getUri().toString().contains("page=1")); + assertTrue(captured.getUri().toString().contains("per_page=10")); + } + + // ==================== cancel ==================== + + @Test + void testCancelSubscription() throws Exception { + httpClient.setResponse(200, "{\"success\":true}"); + + SubscriptionCancelRequest request = new SubscriptionCancelRequest(); + request.setReferenceId("sub-ref-123"); + + Map response = subscriptionService.cancel(request); + + assertNotNull(response); + assertTrue((Boolean) response.get("success")); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/subscription/cancel")); + } + + // ==================== redirect ==================== + + @Test + void testRedirectSubscription() throws Exception { + httpClient.setResponse(200, "{\"url\":\"https://redirect.example.com\"}"); + + SubscriptionRedirectRequest request = new SubscriptionRedirectRequest(); + request.setSubscriptionId("sub-ref-123"); + + SubscriptionRedirectResponse response = subscriptionService.redirect(request); + + assertNotNull(response); + assertEquals("https://redirect.example.com", response.getUrl()); + + ClassicHttpRequest captured = httpClient.getCapturedRequest(); + assertEquals("POST", captured.getMethod()); + assertTrue(captured.getUri().toString().contains("/subscription/redirect")); + } +} diff --git a/src/test/java/com/tapsilat/unit/utils/MockHttpClient.java b/src/test/java/com/tapsilat/unit/utils/MockHttpClient.java new file mode 100644 index 0000000..db2d25e --- /dev/null +++ b/src/test/java/com/tapsilat/unit/utils/MockHttpClient.java @@ -0,0 +1,50 @@ +package com.tapsilat.unit.utils; + +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponseAdapter; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.io.CloseMode; +import org.apache.hc.core5.http.message.BasicClassicHttpResponse; + +import java.io.IOException; + +/** + * A manual MockHttpClient that avoids Mockito instrumentation issues. + * Uses CloseableHttpResponseAdapter to create real instances of the final CloseableHttpResponse class. + */ +public class MockHttpClient extends CloseableHttpClient { + private ClassicHttpRequest capturedRequest; + private int stubStatusCode = 200; + private String stubResponseBody = "{}"; + + public void setResponse(int statusCode, String body) { + this.stubStatusCode = statusCode; + this.stubResponseBody = body; + } + + public ClassicHttpRequest getCapturedRequest() { + return capturedRequest; + } + + @Override + protected CloseableHttpResponse doExecute(HttpHost target, ClassicHttpRequest request, HttpContext context) throws IOException { + this.capturedRequest = request; + + // Create a real ClassicHttpResponse + BasicClassicHttpResponse response = new BasicClassicHttpResponse(stubStatusCode); + response.setEntity(new StringEntity(stubResponseBody)); + + // Adapt it to CloseableHttpResponse using our package-private adapter trick + return CloseableHttpResponseAdapter.adapt(response); + } + + @Override + public void close() throws IOException {} + + @Override + public void close(CloseMode closeMode) {} +} diff --git a/src/test/java/com/tapsilat/unit/validation/ValidatorTest.java b/src/test/java/com/tapsilat/unit/validation/ValidatorTest.java new file mode 100644 index 0000000..3734df9 --- /dev/null +++ b/src/test/java/com/tapsilat/unit/validation/ValidatorTest.java @@ -0,0 +1,215 @@ +package com.tapsilat.unit.validation; + +import com.tapsilat.model.common.Buyer; +import com.tapsilat.model.order.OrderCreateRequest; +import com.tapsilat.validation.OrderRequestValidator; +import com.tapsilat.validation.ValidationException; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class ValidatorTest { + + // ==================== GSM Number Cleaning ==================== + + @Test + void testCleanGsmNumber_InternationalPlusFormat() { + List errors = new ArrayList<>(); + String result = OrderRequestValidator.cleanGsmNumber("+905551234567", errors); + assertEquals("+905551234567", result); + assertTrue(errors.isEmpty()); + } + + @Test + void testCleanGsmNumber_InternationalDoubleZeroFormat() { + List errors = new ArrayList<>(); + String result = OrderRequestValidator.cleanGsmNumber("00905551234567", errors); + assertEquals("00905551234567", result); + assertTrue(errors.isEmpty()); + } + + + + @Test + void testCleanGsmNumber_RemovesFormattingCharacters() { + List errors = new ArrayList<>(); + String result = OrderRequestValidator.cleanGsmNumber("+90 555 123-45(67)", errors); + assertEquals("+905551234567", result); + assertTrue(errors.isEmpty()); + } + + @Test + void testCleanGsmNumber_StripsEmbeddedPlusSigns() { + List errors = new ArrayList<>(); + String result = OrderRequestValidator.cleanGsmNumber("12+34+567", errors); + assertEquals("1234567", result); + assertTrue(errors.isEmpty()); + } + + @Test + void testCleanGsmNumber_TooShort() { + List errors = new ArrayList<>(); + OrderRequestValidator.cleanGsmNumber("123", errors); + assertFalse(errors.isEmpty()); + assertTrue(errors.get(0).contains("too short")); + } + + @Test + void testCleanGsmNumber_NullReturnsNull() { + List errors = new ArrayList<>(); + assertNull(OrderRequestValidator.cleanGsmNumber(null, errors)); + assertTrue(errors.isEmpty()); + } + + @Test + void testCleanGsmNumber_EmptyReturnsEmpty() { + List errors = new ArrayList<>(); + assertEquals("", OrderRequestValidator.cleanGsmNumber("", errors)); + assertTrue(errors.isEmpty()); + } + + // ==================== Installment Validation ==================== + + @Test + void testValidateInstallmentsList_ValidValues() { + List errors = new ArrayList<>(); + OrderRequestValidator.validateInstallmentsList(Arrays.asList(1, 3, 6, 12), errors); + assertTrue(errors.isEmpty()); + } + + @Test + void testValidateInstallmentsList_SingleValid() { + List errors = new ArrayList<>(); + OrderRequestValidator.validateInstallmentsList(Arrays.asList(1), errors); + assertTrue(errors.isEmpty()); + } + + @Test + void testValidateInstallmentsList_ValueTooLow() { + List errors = new ArrayList<>(); + OrderRequestValidator.validateInstallmentsList(Arrays.asList(0, 2, 3), errors); + assertEquals(1, errors.size()); + assertTrue(errors.get(0).contains("invalid")); + } + + @Test + void testValidateInstallmentsList_ValueTooHigh() { + List errors = new ArrayList<>(); + OrderRequestValidator.validateInstallmentsList(Arrays.asList(1, 13, 3), errors); + assertEquals(1, errors.size()); + assertTrue(errors.get(0).contains("invalid")); + } + + @Test + void testValidateInstallmentsList_MultipleBadValues() { + List errors = new ArrayList<>(); + OrderRequestValidator.validateInstallmentsList(Arrays.asList(0, 13), errors); + assertEquals(2, errors.size()); + } + + @Test + void testValidateInstallmentsList_NullIsNoop() { + List errors = new ArrayList<>(); + OrderRequestValidator.validateInstallmentsList(null, errors); + assertTrue(errors.isEmpty()); + } + + @Test + void testValidateInstallmentsList_EmptyIsNoop() { + List errors = new ArrayList<>(); + OrderRequestValidator.validateInstallmentsList(new ArrayList<>(), errors); + assertTrue(errors.isEmpty()); + } + + // ==================== Full Validate ==================== + + @Test + void testValidate_NullRequestThrows() { + assertThrows(ValidationException.class, () -> OrderRequestValidator.validate(null)); + } + + @Test + void testValidate_ValidRequest() { + OrderCreateRequest request = new OrderCreateRequest(); + request.setAmount(new BigDecimal("100")); + request.setCurrency("TRY"); + request.setLocale("tr"); + request.setBuyer(new Buyer("John", "Doe", "test@example.com")); + + List errors = OrderRequestValidator.validate(request); + assertTrue(errors.isEmpty()); + } + + @Test + void testValidate_MissingAmount() { + OrderCreateRequest request = new OrderCreateRequest(); + request.setCurrency("TRY"); + request.setLocale("tr"); + request.setBuyer(new Buyer("John", "Doe", "test@example.com")); + + List errors = OrderRequestValidator.validate(request); + assertFalse(errors.isEmpty()); + assertTrue(errors.stream().anyMatch(e -> e.contains("Amount"))); + } + + @Test + void testValidate_ZeroAmount() { + OrderCreateRequest request = new OrderCreateRequest(); + request.setAmount(BigDecimal.ZERO); + request.setCurrency("TRY"); + request.setLocale("tr"); + request.setBuyer(new Buyer("John", "Doe", "test@example.com")); + + List errors = OrderRequestValidator.validate(request); + assertFalse(errors.isEmpty()); + assertTrue(errors.stream().anyMatch(e -> e.contains("greater than zero"))); + } + + @Test + void testValidate_MissingCurrency() { + OrderCreateRequest request = new OrderCreateRequest(); + request.setAmount(new BigDecimal("100")); + request.setLocale("tr"); + request.setBuyer(new Buyer("John", "Doe", "test@example.com")); + + List errors = OrderRequestValidator.validate(request); + assertFalse(errors.isEmpty()); + assertTrue(errors.stream().anyMatch(e -> e.contains("Currency"))); + } + + @Test + void testValidate_MissingBuyer() { + OrderCreateRequest request = new OrderCreateRequest(); + request.setAmount(new BigDecimal("100")); + request.setCurrency("TRY"); + request.setLocale("tr"); + + List errors = OrderRequestValidator.validate(request); + assertTrue(errors.isEmpty()); + } + + @Test + void testValidate_InvalidEmail() { + OrderCreateRequest request = new OrderCreateRequest(); + request.setAmount(new BigDecimal("100")); + request.setCurrency("TRY"); + request.setLocale("tr"); + request.setBuyer(new Buyer("John", "Doe", "bad-email")); + + List errors = OrderRequestValidator.validate(request); + assertFalse(errors.isEmpty()); + assertTrue(errors.stream().anyMatch(e -> e.contains("email"))); + } + + @Test + void testValidateOrThrow_InvalidThrows() { + OrderCreateRequest request = new OrderCreateRequest(); + // Missing all required fields + assertThrows(ValidationException.class, () -> OrderRequestValidator.validateOrThrow(request)); + } +} diff --git a/src/test/java/org/apache/hc/client5/http/impl/classic/CloseableHttpResponseAdapter.java b/src/test/java/org/apache/hc/client5/http/impl/classic/CloseableHttpResponseAdapter.java new file mode 100644 index 0000000..bec25a1 --- /dev/null +++ b/src/test/java/org/apache/hc/client5/http/impl/classic/CloseableHttpResponseAdapter.java @@ -0,0 +1,12 @@ +package org.apache.hc.client5.http.impl.classic; + +import org.apache.hc.core5.http.ClassicHttpResponse; + +/** + * Adapter to access the package-private CloseableHttpResponse.adapt method. + */ +public class CloseableHttpResponseAdapter { + public static CloseableHttpResponse adapt(ClassicHttpResponse response) { + return CloseableHttpResponse.adapt(response); + } +}