diff --git a/pom.xml b/pom.xml index 166d20fcd..d85aa06be 100644 --- a/pom.xml +++ b/pom.xml @@ -237,6 +237,12 @@ spring-boot-starter-webflux + + commons-codec + commons-codec + 1.12 + + diff --git a/src/main/java/au/com/royalpay/payment/manage/PaymentManageApplication.java b/src/main/java/au/com/royalpay/payment/manage/PaymentManageApplication.java index 8afe9e5fb..c8f42a529 100644 --- a/src/main/java/au/com/royalpay/payment/manage/PaymentManageApplication.java +++ b/src/main/java/au/com/royalpay/payment/manage/PaymentManageApplication.java @@ -15,6 +15,7 @@ import org.springframework.boot.autoconfigure.mongo.MongoClientSettingsBuilderCu import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.core.io.Resource; +import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; import java.io.File; @@ -31,6 +32,7 @@ import java.util.concurrent.TimeUnit; @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) @EnableScheduling @EnableCaching(proxyTargetClass = true) +@EnableAsync public class PaymentManageApplication { public static void main(String[] args) { diff --git a/src/main/java/au/com/royalpay/payment/manage/citypartner/core/impls/CityPartnerPrizeServiceImpl.java b/src/main/java/au/com/royalpay/payment/manage/citypartner/core/impls/CityPartnerPrizeServiceImpl.java index a1abe55b4..a239ef6d7 100644 --- a/src/main/java/au/com/royalpay/payment/manage/citypartner/core/impls/CityPartnerPrizeServiceImpl.java +++ b/src/main/java/au/com/royalpay/payment/manage/citypartner/core/impls/CityPartnerPrizeServiceImpl.java @@ -511,7 +511,7 @@ public class CityPartnerPrizeServiceImpl implements CityPartnerPrizeService { PayChannel payChannel = PayChannel.fromChannelCode(channel); if (payChannel == PayChannel.ALIPAY_APS_IN_STORE || payChannel == PayChannel.ALIPAY_APS_CASHIER) { - Map> groupByPayType = oneChannel.getValue().stream().collect(Collectors.groupingBy(e -> e.getString("pay_type").equals("alipay_cn"))); + Map> groupByPayType = oneChannel.getValue().stream().collect(Collectors.groupingBy(e -> "alipay_cn".equalsIgnoreCase(e.getString("pay_type")))); for (Map.Entry> payType : groupByPayType.entrySet()) { BigDecimal totalAps = BigDecimal.ZERO; BigDecimal total_surageAps = BigDecimal.ZERO; @@ -525,7 +525,7 @@ public class CityPartnerPrizeServiceImpl implements CityPartnerPrizeService { BigDecimal channelRate = null; if (payChannel == PayChannel.ALIPAY_APS_IN_STORE) { if ("alipay_cn".equalsIgnoreCase(params.getString("pay_type"))) { - channelRate = params.get("org_rate") != null ? params.getBigDecimal("org_rate") : (orgInfo.getBigDecimal("aliapy_rate_value").divide(CommonConsts.HUNDRED, 4, RoundingMode.DOWN)); + channelRate = params.get("org_rate") != null ? params.getBigDecimal("org_rate") : (orgInfo.getBigDecimal("alipay_rate_value").divide(CommonConsts.HUNDRED, 4, RoundingMode.DOWN)); } else { channelRate = params.get("org_rate") != null ? params.getBigDecimal("org_rate") : ((orgInfo.getBigDecimal("retail_interchange_fee_value").add(orgInfo.getBigDecimal("retail_service_fee_value"))).divide(CommonConsts.HUNDRED, 4, RoundingMode.DOWN)); } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/application/ShopifyMerchantAuthApplication.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/application/ShopifyMerchantAuthApplication.java index 2731087dd..779b20d90 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/application/ShopifyMerchantAuthApplication.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/application/ShopifyMerchantAuthApplication.java @@ -26,7 +26,7 @@ import java.util.Date; @Component public class ShopifyMerchantAuthApplication { - @Value("${shopify.version:2021-10}") + @Value("${shopify.version:2022-01}") private String apiVersion; @Value("${shopify.auth.apiKey}") @@ -53,34 +53,59 @@ public class ShopifyMerchantAuthApplication { private PaymentsAppConfigureClient paymentsAppConfigureClient; /** - * 获取shopify店铺授权URL + * 获取shopify店铺授权url + * @param shopifyStoreHost + * @return + */ + public ShopifyPermissionURL getShopifyPermissionUrl(String shopifyStoreHost) { + ShopifyPermissionURL shopifyPermissionURL = shopifyAuthService.shopifyPermission(shopifyStoreHost); + return shopifyPermissionURL; + } + + /** + * 绑定安装shopify店铺 * * @param request 店铺信息 * @return */ - public ShopifyPermissionURL shopifyPermission(ShopifyPermissionRequest request) { + public ShopifyAccessToken install(ShopifyPermissionRequest request) { LoginInfo loginInfo = new LoginInfo(); loginInfo.setLoginId(request.getLoginId()); loginInfo.setPassword(request.getPassword()); - signInStatusManager.partnerSignIn(loginInfo); - SimpleMerchantAccount simpleMerchantAccount = merchantAccountService.getByUsername(request.getLoginId()); + String shop = request.getShop(); + SimpleMerchantAccount simpleMerchantAccount = merchantAccountService.getByUsername(request.getLoginId()); SimpleMerchant simpleMerchant = merchantService.getByClientId(simpleMerchantAccount.getClientId()); - ShopifyStore shopifyShop = shopifyStoreService.getByShopifyShop(request.getShop()); + ShopifyStore shopifyShop = shopifyStoreService.getByShopifyShop(shop); + ShopifyAccessToken accessToken = shopifyAuthService.getAccessToken(shop, request.getCode()); if (shopifyShop == null) { - shopifyStoreService.createShopifyStore(ShopifyStore.instanceOf(simpleMerchantAccount, simpleMerchant, request.getShop())); - return shopifyAuthService.shopifyPermission(request); + shopifyStoreService.createShopifyStore(ShopifyStore.instanceOf(simpleMerchantAccount, simpleMerchant, shop, accessToken)); + return getShopifyPaymentAppConfigUrl(shop, accessToken); } shopifyStoreService.modifyShopifyStore(shopifyShop .setClientId(simpleMerchantAccount.getClientId()) .setClientMoniker(simpleMerchant.getClientMoniker()) .setModifyTime(new Date()) - .setModifier(request.getShop())); + .setAccessToken(accessToken.getAccess_token()) + .setScope(accessToken.getScope()) + .setModifier(shop)); + + return getShopifyPaymentAppConfigUrl(shop, accessToken); + } + + private ShopifyAccessToken getShopifyPaymentAppConfigUrl(String shop, ShopifyAccessToken accessToken) { + try { + paymentsAppConfigureClient.paymentsAppConfigure(shop, true, apiVersion); + } catch (IOException e) { + log.error(String.format("Shopify store [%s] payment app setting error: %s", shop, e.getMessage())); + throw new BadRequestException("Payment app setting error"); + } - return shopifyAuthService.shopifyPermission(request); + String redirectUrl = String.format(PAYMENT_SETTING_URL, shop, apiKey); + return accessToken.setRedirectUrl(redirectUrl); } /** @@ -90,6 +115,7 @@ public class ShopifyMerchantAuthApplication { * @param code 授权code * @return */ + @Deprecated public ShopifyAccessToken merchantOnboard(String shop, String code) { ShopifyAccessToken accessToken = shopifyAuthService.getAccessToken(shop, code); ShopifyStore shopifyStore = shopifyStoreService.getByShopifyShop(shop); @@ -98,14 +124,8 @@ public class ShopifyMerchantAuthApplication { } shopifyStoreService.modifyShopifyStore(shopifyStore.setAccessToken(accessToken.getAccess_token()).setScope(accessToken.getScope())); - try { - paymentsAppConfigureClient.paymentsAppConfigure(shop, true, apiVersion); - } catch (IOException e) { - log.error(String.format("Shopify store [%s] payment app setting error: %s", shop, e.getMessage())); - throw new BadRequestException("Payment app setting error"); - } - - String redirectUrl = String.format(PAYMENT_SETTING_URL, shop, apiKey); - return accessToken.setRedirectUrl(redirectUrl); + return getShopifyPaymentAppConfigUrl(shop, accessToken); } + + } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/entity/ShopifyCommonParameter.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/entity/ShopifyCommonParameter.java new file mode 100644 index 000000000..c5f56f2d0 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/entity/ShopifyCommonParameter.java @@ -0,0 +1,20 @@ +package au.com.royalpay.payment.manage.shopify.auth.domain.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ShopifyCommonParameter { + private String shop; + private String code; + private String state; + private String hmac; + private String host; + private String timestamp; + +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/exception/ShopifyRequestVerifyException.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/exception/ShopifyRequestVerifyException.java new file mode 100644 index 000000000..6aa717dcb --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/exception/ShopifyRequestVerifyException.java @@ -0,0 +1,11 @@ +package au.com.royalpay.payment.manage.shopify.auth.domain.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.UNAUTHORIZED) +public class ShopifyRequestVerifyException extends RuntimeException{ + public ShopifyRequestVerifyException(String message) { + super(message); + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java index 1f88d2384..56bfbbfb3 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java @@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClientException; @@ -38,9 +39,17 @@ public class ShopifyAuthService { @Qualifier("shopifyRestTemplate") private RestTemplate restTemplate; - public ShopifyPermissionURL shopifyPermission(ShopifyPermissionRequest request) { + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public ShopifyPermissionURL shopifyPermission(String shopifyStoreHost) { String redirectUri = PlatformEnvironment.getEnv().concatUrl("/shopify/auth/back"); - String permissionUrl = String.format(PERMISSION_URL, request.getShop(), clientId, scope, redirectUri, String.valueOf(new Date().getTime()).substring(0,10)); + + String state = String.valueOf(new Date().getTime()).substring(0,10); + + stringRedisTemplate.boundValueOps("shopifyAuthState:"+shopifyStoreHost).set(state); + + String permissionUrl = String.format(PERMISSION_URL, shopifyStoreHost, clientId, scope, redirectUri, state); return ShopifyPermissionURL.builder().url(permissionUrl).build(); } @@ -57,4 +66,5 @@ public class ShopifyAuthService { log.info(String.format("Shopify merchant [%s] access token: %s", shop, shopifyAccessToken)); return shopifyAccessToken; } + } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java new file mode 100644 index 000000000..cf90d7473 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java @@ -0,0 +1,34 @@ +package au.com.royalpay.payment.manage.shopify.auth.domain.service; + +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter; +import au.com.royalpay.payment.manage.shopify.support.HmacVerificationUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ShopifyRequestValidator { + + @Value("${shopify.auth.apiSecretKey}") + private String clientSecret; + + public Boolean valid(ShopifyCommonParameter parameter) { + StringBuilder message =new StringBuilder(); + message.append("code=").append(parameter.getCode()) + .append("&host=").append(parameter.getHost()) + .append("&shop=").append(parameter.getShop()) + .append("&state=").append(parameter.getState()) + .append("×tamp=").append(parameter.getTimestamp()); + return HmacVerificationUtil.hmacSHA256(message.toString(),clientSecret,parameter.getHmac()); + } + + public boolean verifyPermission(String shopifyStoreHost, String hmac, String timestamp) { + StringBuilder message =new StringBuilder(); + message.append("shop=").append(shopifyStoreHost) + .append("×tamp=").append(timestamp); + return HmacVerificationUtil.hmacSHA256(message.toString(),clientSecret,hmac); + } + + public boolean verify(String message, String hmac) { + return HmacVerificationUtil.hmacSHA256(message,clientSecret,hmac); + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java index 6599ccb05..745dff1f6 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java @@ -2,11 +2,12 @@ package au.com.royalpay.payment.manage.shopify.auth.web; import au.com.royalpay.payment.manage.shopify.auth.domain.application.ShopifyMerchantAuthApplication; import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyAccessToken; -import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyPermissionURL; import au.com.royalpay.payment.manage.shopify.auth.web.command.ShopifyPermissionRequest; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; @@ -26,28 +27,9 @@ public class ShopifyAuthController { * @param request 店铺信息 * @return */ - @PostMapping("/permission") - public ShopifyPermissionURL shopifyPermission(@RequestBody @Valid ShopifyPermissionRequest request) { - ShopifyPermissionURL shopifyPermissionURL = shopifyMerchantAuthApplication.shopifyPermission(request); - return shopifyPermissionURL; + @PostMapping("/install") + public ShopifyAccessToken shopifyStoreInstall(@RequestBody @Valid ShopifyPermissionRequest request) { + ShopifyAccessToken shopifyAccessToken = shopifyMerchantAuthApplication.install(request); + return shopifyAccessToken; } - - /** - * shopify授权回调接口 - * - * @return - */ - @GetMapping("/back") - public ModelAndView shopifyAuthBack(@RequestParam(value = "code") String code, - @RequestParam(name = "hmac", required = false) String hmac, - @RequestParam(name = "host", required = false) String host, - @RequestParam("shop") String shop, - @RequestParam(name = "state", required = false) String state, - @RequestParam(name = "timestamp", required = false) String timestamp) { - ShopifyAccessToken accessToken = shopifyMerchantAuthApplication.merchantOnboard(shop, code); - ModelAndView view = new ModelAndView("shopify/auth_back"); - view.addObject("accessToken",accessToken); - return view; - } - } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java new file mode 100644 index 000000000..f4443d1ce --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java @@ -0,0 +1,104 @@ +package au.com.royalpay.payment.manage.shopify.auth.web; + +import au.com.royalpay.payment.manage.shopify.auth.domain.application.ShopifyMerchantAuthApplication; +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter; +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyPermissionURL; +import au.com.royalpay.payment.manage.shopify.auth.domain.exception.ShopifyRequestVerifyException; +import au.com.royalpay.payment.manage.shopify.auth.domain.service.ShopifyRequestValidator; +import au.com.royalpay.payment.tools.env.PlatformEnvironment; +import au.com.royalpay.payment.tools.exceptions.BadRequestException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; +import java.util.regex.Pattern; + +@Controller +@RequestMapping(value = "/shopify") +public class ShopifyAuthTemplateController { + + @Autowired + private ShopifyMerchantAuthApplication shopifyMerchantAuthApplication; + + @Autowired + private ShopifyRequestValidator shopifyRequestValidator; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + /** + * shopify店铺安装入口 + * + * @param shop + * @param hmac + * @param timestamp + * @return + */ + @GetMapping("/auth") + public String shopifyStorePermission(@RequestParam("shop") String shop, + @RequestParam("hmac") String hmac, + @RequestParam("timestamp") String timestamp, + HttpServletResponse response) { + if (!Pattern.matches("^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", shop)) { + throw new BadRequestException("Parameter shop is invalid."); + } + if (!shopifyRequestValidator.verifyPermission(shop, hmac, timestamp)) { + throw new ShopifyRequestVerifyException("This request parameters is invalid"); + } + ShopifyPermissionURL shopifyPermissionURL = shopifyMerchantAuthApplication.getShopifyPermissionUrl(shop); + response.setHeader("content-security-policy", "frame-ancestors https://" + shop + ".myshopify.com https://admin.shopify.com"); + return "redirect:" + shopifyPermissionURL.getUrl(); + } + + /** + * shopify店铺授权后回调URL + * + * @param code + * @param hmac + * @param host + * @param state + * @param shop + * @param timestamp + * @return + */ + @GetMapping("/auth/back") + public RedirectView shopifyStoreAuthRedirect(@RequestParam("code") String code, + @RequestParam("hmac") String hmac, + @RequestParam("host") String host, + @RequestParam("state") String state, + @RequestParam("shop") String shop, + @RequestParam("timestamp") String timestamp, + HttpServletResponse response) { + + if (!Pattern.matches("^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", shop)) { + throw new ShopifyRequestVerifyException("Parameter shop is invalid."); + } + + String preState = stringRedisTemplate.boundValueOps("shopifyAuthState:" + shop).get(); + if (!state.equals(preState)) { + throw new ShopifyRequestVerifyException("This request parameters is invalid"); + } + stringRedisTemplate.delete("shopifyAuthState:" + shop); + ShopifyCommonParameter shopifyCommonParameter = ShopifyCommonParameter.builder() + .code(code) + .hmac(hmac) + .host(host) + .state(state) + .shop(shop) + .timestamp(timestamp) + .build(); + if (!shopifyRequestValidator.valid(shopifyCommonParameter)) { + throw new ShopifyRequestVerifyException("This request parameters is invalid"); + } + + String redirectUri = PlatformEnvironment.getEnv().concatUrl("/auth.html#/shopify/login?code=" + code + "&hmac=" + hmac + "&host=" + host + "&state=" + state + "&shop=" + shop + "×tamp=" + timestamp); + response.setHeader("content-security-policy", "frame-ancestors https://" + shop + ".myshopify.com https://admin.shopify.com"); + return new RedirectView(redirectUri); + } + +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java index aaeb585a2..ef2526d07 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; @Data @Builder @@ -14,20 +15,26 @@ import javax.validation.constraints.NotBlank; @AllArgsConstructor public class ShopifyPermissionRequest { - @NotBlank(message = "Shop can not blank") - private String shop; - @NotBlank(message = "Login Id can not blank") private String loginId; @NotBlank(message = "Password can not blank") private String password; + @NotBlank(message = "Code can not blank") + private String code; + + @NotBlank(message = "Shop can not blank") + @Pattern(regexp = "^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", message = "Shop hostname is invalid") + private String shop; + public static ShopifyPermissionRequest instanceOf(CreateShopifyMerchantCommand command) { return ShopifyPermissionRequest.builder() .loginId(command.getPaymentAccount().getLoginId()) .password(command.getPaymentAccount().getPassword()) + .code(command.getCode()) .shop(command.getShopifyShop()) .build(); } + } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java new file mode 100644 index 000000000..fc7a8fb02 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java @@ -0,0 +1,29 @@ +package au.com.royalpay.payment.manage.shopify.auth.web.command; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +@Data +public class ShopifyVerifyRequest { + + @NotBlank(message = "Code can not blank") + private String code; + + @NotBlank(message = "hmac can not blank") + private String hmac; + + @NotBlank(message = "host can not blank") + private String host; + + @NotBlank(message = "Shop can not blank") + @Pattern(regexp = "^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", message = "Shop hostname is invalid") + private String shop; + + @NotBlank(message = "state can not blank") + private String state; + + @NotBlank(message = "timestamp can not blank") + private String timestamp; +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/ShopifyWebhooksController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/ShopifyWebhooksController.java new file mode 100644 index 000000000..0b620a206 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/ShopifyWebhooksController.java @@ -0,0 +1,75 @@ +package au.com.royalpay.payment.manage.shopify.hooks; + +import au.com.royalpay.payment.manage.shopify.auth.domain.exception.ShopifyRequestVerifyException; +import au.com.royalpay.payment.manage.shopify.auth.domain.service.ShopifyRequestValidator; +import au.com.royalpay.payment.manage.shopify.hooks.command.ShopifyCustomerRedactCommand; +import au.com.royalpay.payment.manage.shopify.hooks.command.ShopifyCustomerRequestCommand; +import au.com.royalpay.payment.manage.shopify.hooks.command.ShopifyShopRedactCommand; +import au.com.royalpay.payment.manage.shopify.store.domain.entity.ShopifyStore; +import au.com.royalpay.payment.manage.shopify.store.domain.service.ShopifyStoreService; +import au.com.royalpay.payment.manage.shopify.support.ShopifyHttpUtils; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; + +@Slf4j +@RestController +@RequestMapping(value = "/shopify") +public class ShopifyWebhooksController { + + @Autowired + private ShopifyStoreService shopifyStoreService; + + @Autowired + private ShopifyRequestValidator shopifyRequestValidator; + + /** + * 推送顾客信息查询请求 + * + */ + @PostMapping("/customer/request") + public void customerRequest(@RequestHeader("X-Shopify-Hmac-SHA256") String hmac, + HttpServletRequest request) { + String requestBody = ShopifyHttpUtils.getRequestBody(request); + if (!shopifyRequestValidator.verify(requestBody, hmac)) { + throw new ShopifyRequestVerifyException("Unauthorized"); + } + ShopifyCustomerRequestCommand shopifyCustomerRequestCommand = JSONObject.parseObject(requestBody, ShopifyCustomerRequestCommand.class); + } + + /** + * 擦除顾客信息消息通知 + * + */ + @PostMapping("/customer/erasure") + public void customerRedact(@RequestHeader("X-Shopify-Hmac-SHA256") String hmac, + HttpServletRequest request) { + String requestBody = ShopifyHttpUtils.getRequestBody(request); + if (!shopifyRequestValidator.verify(requestBody, hmac)) { + throw new ShopifyRequestVerifyException("Unauthorized"); + } + ShopifyCustomerRedactCommand shopifyCustomerRedactCommand = JSONObject.parseObject(requestBody, ShopifyCustomerRedactCommand.class); + } + + /** + * shopify店铺卸载payment app事件 + * + */ + @PostMapping("/shop/erasure") + public void shopRedact(@RequestHeader("X-Shopify-Hmac-SHA256") String hmac, + HttpServletRequest request) { + String requestBody = ShopifyHttpUtils.getRequestBody(request); + if (!shopifyRequestValidator.verify(requestBody, hmac)) { + throw new ShopifyRequestVerifyException("Unauthorized"); + } + ShopifyShopRedactCommand shopifyShopRedactCommand = JSONObject.parseObject(requestBody, ShopifyShopRedactCommand.class); + ShopifyStore shopifyShop = shopifyStoreService.getByShopifyShop(shopifyShopRedactCommand.getShop_domain()); + if (shopifyShop == null) { + return; + } + shopifyStoreService.modifyShopifyStore(shopifyShop.setStatus(0)); + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyCustomer.java b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyCustomer.java new file mode 100644 index 000000000..5ad3d045b --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyCustomer.java @@ -0,0 +1,10 @@ +package au.com.royalpay.payment.manage.shopify.hooks.command; + +import lombok.Data; + +@Data +public class ShopifyCustomer { + private String id; + private String email; + private String phone; +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyCustomerRedactCommand.java b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyCustomerRedactCommand.java new file mode 100644 index 000000000..8cea05276 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyCustomerRedactCommand.java @@ -0,0 +1,13 @@ +package au.com.royalpay.payment.manage.shopify.hooks.command; + +import lombok.Data; + +import java.util.List; + +@Data +public class ShopifyCustomerRedactCommand { + private String shop_id; + private String shop_domain; + private ShopifyCustomer customer; + private List orders_to_redact; +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyCustomerRequestCommand.java b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyCustomerRequestCommand.java new file mode 100644 index 000000000..37ae86c1c --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyCustomerRequestCommand.java @@ -0,0 +1,19 @@ +package au.com.royalpay.payment.manage.shopify.hooks.command; + +import lombok.Data; + +import java.util.List; + +@Data +public class ShopifyCustomerRequestCommand { + private String shop_id; + private String shop_domain; + private List orders_requested; + private ShopifyCustomer customer; + private DataRequest data_request; + + @Data + public class DataRequest{ + private String id; + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyShopRedactCommand.java b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyShopRedactCommand.java new file mode 100644 index 000000000..a8e551094 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/command/ShopifyShopRedactCommand.java @@ -0,0 +1,9 @@ +package au.com.royalpay.payment.manage.shopify.hooks.command; + +import lombok.Data; + +@Data +public class ShopifyShopRedactCommand { + private String shop_id; + private String shop_domain; +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplication.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplication.java index 0b4efc35b..29a063e1a 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplication.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplication.java @@ -1,21 +1,24 @@ package au.com.royalpay.payment.manage.shopify.store.domain.application; import au.com.royalpay.payment.manage.shopify.auth.domain.application.ShopifyMerchantAuthApplication; -import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyPermissionURL; +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyAccessToken; import au.com.royalpay.payment.manage.shopify.auth.web.command.ShopifyPermissionRequest; import au.com.royalpay.payment.manage.shopify.store.domain.context.MerchantCreateContext; import au.com.royalpay.payment.manage.shopify.store.domain.entity.MerchantAccountRequest; import au.com.royalpay.payment.manage.shopify.store.domain.entity.SimpleMerchant; +import au.com.royalpay.payment.manage.shopify.store.domain.event.ShopifyStoreCreatedEvent; import au.com.royalpay.payment.manage.shopify.store.domain.service.MerchantAccountService; import au.com.royalpay.payment.manage.shopify.store.domain.service.MerchantService; import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand; import au.com.royalpay.payment.manage.shopify.support.PlatformMerchantProvider; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service -public class ShopifyStoreApplication { +public class ShopifyStoreApplication implements ApplicationEventPublisherAware { @Autowired private MerchantService merchantservice; @@ -29,6 +32,13 @@ public class ShopifyStoreApplication { @Autowired private ShopifyMerchantAuthApplication shopifyMerchantAuthApplication; + private ApplicationEventPublisher eventPublisher; + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.eventPublisher = applicationEventPublisher; + } + /** * 检查partnerCode的商户是否存在 * @@ -46,7 +56,7 @@ public class ShopifyStoreApplication { * @return 授权链接 */ @Transactional - public ShopifyPermissionURL register(CreateShopifyMerchantCommand command) { + public ShopifyAccessToken register(CreateShopifyMerchantCommand command) { MerchantCreateContext merchantCreateContext = new MerchantCreateContext(platformMerchantProvider, command); SimpleMerchant simpleMerchant = merchantservice.createMerchant(merchantCreateContext); @@ -54,6 +64,12 @@ public class ShopifyStoreApplication { MerchantAccountRequest accountRequest = MerchantAccountRequest.instanceOf(command, simpleMerchant); merchantAccountService.createAccount(accountRequest); - return shopifyMerchantAuthApplication.shopifyPermission(ShopifyPermissionRequest.instanceOf(command)); + ShopifyAccessToken shopifyAccessToken = shopifyMerchantAuthApplication.install(ShopifyPermissionRequest.instanceOf(command)); + + this.eventPublisher.publishEvent(new ShopifyStoreCreatedEvent(this, simpleMerchant, command, accountRequest)); + + return shopifyAccessToken; } + + } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/ShopifyMerchantApplyInfo.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/ShopifyMerchantApplyInfo.java new file mode 100644 index 000000000..965202243 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/ShopifyMerchantApplyInfo.java @@ -0,0 +1,37 @@ +package au.com.royalpay.payment.manage.shopify.store.domain.entity; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class ShopifyMerchantApplyInfo { + + private int clientId; + + private String clientMoniker; + + private String shopifyShop; + + private String contactPerson; + + private String contactPhone; + + private String contactEmail; + + private String displayName; + + private String companyName; + + private String address; + + private String suburb; + + private String postcode; + + private String state; + + private String country; + + +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/ShopifyStore.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/ShopifyStore.java index 871e725e6..154730cfe 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/ShopifyStore.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/ShopifyStore.java @@ -1,5 +1,6 @@ package au.com.royalpay.payment.manage.shopify.store.domain.entity; +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyAccessToken; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -36,7 +37,9 @@ public class ShopifyStore { private String scope; - public static ShopifyStore instanceOf(SimpleMerchantAccount merchantAccount, SimpleMerchant simpleMerchant, String shop) { + private int status; + + public static ShopifyStore instanceOf(SimpleMerchantAccount merchantAccount, SimpleMerchant simpleMerchant, String shop, ShopifyAccessToken accessToken) { return ShopifyStore.builder() .id(UUID.randomUUID().toString()) .clientId(merchantAccount.getClientId()) @@ -44,6 +47,8 @@ public class ShopifyStore { .shopifyShop(shop) .createTime(new Date()) .creator("shopify store") + .accessToken(accessToken.getAccess_token()) + .scope(accessToken.getScope()) .modifyTime(new Date()).build(); } } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/SimpleMerchant.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/SimpleMerchant.java index 0e943d543..8c6c4b101 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/SimpleMerchant.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/entity/SimpleMerchant.java @@ -1,12 +1,14 @@ package au.com.royalpay.payment.manage.shopify.store.domain.entity; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor +@Builder public class SimpleMerchant { private Integer clientId; private String clientMoniker; diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/event/ShopifyStoreCreatedEvent.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/event/ShopifyStoreCreatedEvent.java new file mode 100644 index 000000000..e3d83a12e --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/event/ShopifyStoreCreatedEvent.java @@ -0,0 +1,35 @@ +package au.com.royalpay.payment.manage.shopify.store.domain.event; + +import au.com.royalpay.payment.manage.shopify.store.domain.application.ShopifyStoreApplication; +import au.com.royalpay.payment.manage.shopify.store.domain.entity.MerchantAccountRequest; +import au.com.royalpay.payment.manage.shopify.store.domain.entity.SimpleMerchant; +import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand; +import org.springframework.context.ApplicationEvent; + +public class ShopifyStoreCreatedEvent extends ApplicationEvent { + + private SimpleMerchant simpleMerchant; + + private CreateShopifyMerchantCommand command; + + private MerchantAccountRequest accountRequest; + + public ShopifyStoreCreatedEvent(ShopifyStoreApplication source, SimpleMerchant simpleMerchant, CreateShopifyMerchantCommand command, MerchantAccountRequest accountRequest) { + super(source); + this.simpleMerchant = simpleMerchant; + this.command = command; + this.accountRequest = accountRequest; + } + + public SimpleMerchant getSimpleMerchant() { + return simpleMerchant; + } + + public CreateShopifyMerchantCommand getCommand() { + return command; + } + + public MerchantAccountRequest getAccountRequest() { + return accountRequest; + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/listener/ShopifyStoreCreatedListener.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/listener/ShopifyStoreCreatedListener.java new file mode 100644 index 000000000..2e978cbc0 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/domain/listener/ShopifyStoreCreatedListener.java @@ -0,0 +1,63 @@ +package au.com.royalpay.payment.manage.shopify.store.domain.listener; + +import au.com.royalpay.payment.manage.notice.core.MailService; +import au.com.royalpay.payment.manage.shopify.store.domain.entity.ShopifyMerchantApplyInfo; +import au.com.royalpay.payment.manage.shopify.store.domain.event.ShopifyStoreCreatedEvent; +import au.com.royalpay.payment.manage.shopify.store.web.command.PaymentMerchantCommand; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.thymeleaf.context.Context; +import org.thymeleaf.spring5.SpringTemplateEngine; + +import javax.annotation.Resource; +import java.io.IOException; +import java.net.URISyntaxException; + +@Slf4j +@Component +public class ShopifyStoreCreatedListener { + + @Resource + private MailService mailService; + + @Resource + private SpringTemplateEngine thymeleaf; + + private static final String consignee = "info@royalpay.com.au"; + + @Async + @EventListener + public void onShopifyStoreCreated(ShopifyStoreCreatedEvent event) { + PaymentMerchantCommand paymentMerchant = event.getCommand().getPaymentMerchant(); + ShopifyMerchantApplyInfo applyInfo = ShopifyMerchantApplyInfo.builder() + .clientId(event.getSimpleMerchant().getClientId()) + .clientMoniker(event.getSimpleMerchant().getClientMoniker()) + .contactEmail(event.getAccountRequest().getContactEmail()) + .contactPhone(event.getAccountRequest().getContactPhone()) + .contactPerson(paymentMerchant.getContactPerson()) + .address(paymentMerchant.getAddress()) + .shopifyShop(event.getCommand().getShopifyShop()) + .displayName(event.getAccountRequest().getDisplayName()) + .companyName(paymentMerchant.getCompanyName()) + .suburb(paymentMerchant.getSuburb()) + .state(paymentMerchant.getState()) + .country(paymentMerchant.getCountry()) + .postcode(paymentMerchant.getPostcode()) + .build(); + Context ctx = new Context(); + ctx.setVariable("applyInfo", applyInfo); + + final String content = thymeleaf.process("mail/shopify_merchant_application.html", ctx); + try { + mailService.sendEmail("Shopify merchant application", consignee, "", content); + } catch (URISyntaxException e) { + log.error(e.getMessage()); + e.printStackTrace(); + } catch (IOException e) { + log.error(e.getMessage()); + e.printStackTrace(); + } + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/ShopifyStoreController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/ShopifyStoreController.java index 22bbb1bc4..9cb987e35 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/ShopifyStoreController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/ShopifyStoreController.java @@ -1,5 +1,6 @@ package au.com.royalpay.payment.manage.shopify.store.web; +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyAccessToken; import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyPermissionURL; import au.com.royalpay.payment.manage.shopify.store.domain.application.ShopifyStoreApplication; import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand; @@ -23,6 +24,7 @@ public class ShopifyStoreController { * * @param partnerCode 商户标识 */ + @Deprecated @GetMapping("/exist") public Boolean validPaymentAppMerchant(@RequestParam("partnerCode") String partnerCode) { return shopifyStoreApplication.existMerchant(partnerCode); @@ -35,7 +37,7 @@ public class ShopifyStoreController { * @Return 店铺授权链接 */ @PostMapping("/register") - public ShopifyPermissionURL createMerchantWithShopify(@RequestBody @Valid CreateShopifyMerchantCommand command) { + public ShopifyAccessToken createMerchantWithShopify(@RequestBody @Valid CreateShopifyMerchantCommand command) { return shopifyStoreApplication.register(command); } } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java index c4311a72d..8bad7393b 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java @@ -4,6 +4,7 @@ import lombok.Data; import lombok.experimental.Accessors; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; @Data @Accessors(chain = true) @@ -13,6 +14,11 @@ public class CreateShopifyMerchantCommand { private PaymentAccountCommand paymentAccount; + @NotBlank(message = "Auth code can not blank") + private String code; + @NotBlank(message = "Shop can not blank") + @Pattern(regexp = "^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", message = "Shop hostname is invalid") private String shopifyShop; + } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/support/HmacVerificationUtil.java b/src/main/java/au/com/royalpay/payment/manage/shopify/support/HmacVerificationUtil.java new file mode 100644 index 000000000..5ba85aac0 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/support/HmacVerificationUtil.java @@ -0,0 +1,58 @@ +package au.com.royalpay.payment.manage.shopify.support; + +import org.apache.commons.codec.digest.HmacAlgorithms; +import org.apache.commons.codec.digest.HmacUtils; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.crypto.RuntimeCryptoException; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import javax.xml.bind.annotation.adapters.HexBinaryAdapter; +import java.nio.charset.StandardCharsets; +import java.security.Security; +import java.util.Locale; + +public class HmacVerificationUtil { + + public static boolean checkParameters(String message, String secret, String hmac) { + try { + Security.addProvider(new BouncyCastleProvider()); + SecretKey secretKey = new SecretKeySpec(secret.getBytes("UTF8"), "HmacSHA256"); + Mac mac = Mac.getInstance(secretKey.getAlgorithm()); + mac.init(secretKey); + byte[] digest = mac.doFinal(message.getBytes("UTF-8")); + String marshal = new HexBinaryAdapter().marshal(digest).toLowerCase(Locale.ROOT); + return StringUtils.equals(marshal, hmac); + } catch (Exception e) { + throw new RuntimeCryptoException("加密异常"); + } + } + + public static boolean hmacSHA256(String input, String key, String hmac) { + String encode = encode(input, key, HmacAlgorithms.HMAC_SHA_256); + return StringUtils.equals(encode, hmac); + } + + private static String encode(String input, String key, HmacAlgorithms algorithm) { + Mac mac = HmacUtils.getInitializedMac(algorithm, key.getBytes(StandardCharsets.UTF_8)); + byte[] content = input.getBytes(StandardCharsets.UTF_8); + byte[] signResult = mac.doFinal(content); + return bytesToHex(signResult); + } + + private static String bytesToHex(byte[] hash) { + StringBuilder hexString = new StringBuilder(); + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } + + +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/support/ShopifyHttpUtils.java b/src/main/java/au/com/royalpay/payment/manage/shopify/support/ShopifyHttpUtils.java new file mode 100644 index 000000000..6e82a1643 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/support/ShopifyHttpUtils.java @@ -0,0 +1,33 @@ +package au.com.royalpay.payment.manage.shopify.support; + +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; + +public class ShopifyHttpUtils { + + public static String getRequestBody(HttpServletRequest request) { + BufferedReader br = null; + StringBuilder sb = new StringBuilder(""); + try { + br = request.getReader(); + String str; + while ((str = br.readLine()) != null) { + sb.append(str); + } + br.close(); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (null != br) { + try { + br.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return sb.toString(); + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/tradelog/refund/impls/RefundServiceImpl.java b/src/main/java/au/com/royalpay/payment/manage/tradelog/refund/impls/RefundServiceImpl.java index 41cdf081d..cd4e70265 100644 --- a/src/main/java/au/com/royalpay/payment/manage/tradelog/refund/impls/RefundServiceImpl.java +++ b/src/main/java/au/com/royalpay/payment/manage/tradelog/refund/impls/RefundServiceImpl.java @@ -35,6 +35,7 @@ import org.springframework.util.Assert; import javax.annotation.Resource; import java.math.BigDecimal; +import java.text.MessageFormat; import java.util.Date; import java.util.List; diff --git a/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientRateMapper.xml b/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientRateMapper.xml index 4c713885d..cff095259 100644 --- a/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientRateMapper.xml +++ b/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientRateMapper.xml @@ -151,17 +151,15 @@ +
- +
-
- -

Example: geek-test-shop.myshopify.com

-
- +

{{resError}}

+
+ + Not a RoyalPay merchant yet, please register + diff --git a/src/main/ui/static/shopify/auth/templates/shopify_register.html b/src/main/ui/static/shopify/auth/templates/shopify_register.html index 8fcb9bd8d..5d73c2931 100644 --- a/src/main/ui/static/shopify/auth/templates/shopify_register.html +++ b/src/main/ui/static/shopify/auth/templates/shopify_register.html @@ -53,7 +53,7 @@ -
@@ -62,7 +62,7 @@ ng-if="partnerForm.shopifyShop.$dirty">

Required Field

- + -->
diff --git a/src/test/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidatorTest.java b/src/test/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidatorTest.java new file mode 100644 index 000000000..ceb8c17f0 --- /dev/null +++ b/src/test/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidatorTest.java @@ -0,0 +1,46 @@ +package au.com.royalpay.payment.manage.shopify.auth.domain.service; + +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.regex.Pattern; + +@Slf4j +@RunWith(SpringRunner.class) +@SpringBootTest +@ActiveProfiles({"dev", "alipay", "bestpay", "jd", "wechat", "rpay", "yeepay", "rppaysvc", "common", "alipayplusaps"}) +class ShopifyRequestValidatorTest { + + @Autowired + private ShopifyRequestValidator shopifyRequestValidator; + + @Test + public void shopifyRequestValidatorTest() { + ShopifyCommonParameter parameter = ShopifyCommonParameter.builder() + .code("4618ddc9da54cee7be06b35f49c72349") + .host("Z2Vlay10ZXN0LXNob3AubXlzaG9waWZ5LmNvbS9hZG1pbg") + .shop("geek-test-shop.myshopify.com") + .timestamp("1643097047") + .state("1643097021") + .hmac("e7884f623057afd700b27ba8a5b7529a3f2a2943d2931d73fb82c57f2cf0baaa") + .build(); + Boolean valid = shopifyRequestValidator.valid(parameter); + log.warn(String.format("---------------------result: [%s]-------------",valid)); + } + + @Test + public void testShopifyDomain() { + String shop = "exampleshop.myshopify.com"; + + boolean matches = Pattern.matches("^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", shop); + + log.warn(String.format("---------------------matches: [%s]-------------",matches)); + } +} \ No newline at end of file diff --git a/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplicationTest.java b/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplicationTest.java index 800559bf8..7751c2fd0 100644 --- a/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplicationTest.java +++ b/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplicationTest.java @@ -1,5 +1,6 @@ package au.com.royalpay.payment.manage.shopify.store.domain.application; +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyAccessToken; import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyPermissionURL; import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand; import au.com.royalpay.payment.manage.shopify.store.web.command.PaymentAccountCommand; @@ -46,7 +47,7 @@ class ShopifyStoreApplicationTest { .setPaymentAccount(accountCommand) .setShopifyShop("demo.myshopify.com"); - ShopifyPermissionURL shopifyPermissionURL = shopifyStoreApplication.register(command); - log.warn(JSON.toJSONString(shopifyPermissionURL)); + ShopifyAccessToken shopifyAccessToken = shopifyStoreApplication.register(command); + log.warn(JSON.toJSONString(shopifyAccessToken)); } } \ No newline at end of file diff --git a/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/listener/ShopifyStoreCreatedListenerTest.java b/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/listener/ShopifyStoreCreatedListenerTest.java new file mode 100644 index 000000000..268063fb6 --- /dev/null +++ b/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/listener/ShopifyStoreCreatedListenerTest.java @@ -0,0 +1,51 @@ +package au.com.royalpay.payment.manage.shopify.store.domain.listener; + +import au.com.royalpay.payment.manage.shopify.store.domain.application.ShopifyStoreApplication; +import au.com.royalpay.payment.manage.shopify.store.domain.entity.MerchantAccountRequest; +import au.com.royalpay.payment.manage.shopify.store.domain.entity.SimpleMerchant; +import au.com.royalpay.payment.manage.shopify.store.domain.event.ShopifyStoreCreatedEvent; +import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand; +import au.com.royalpay.payment.manage.shopify.store.web.command.PaymentAccountCommand; +import au.com.royalpay.payment.manage.shopify.store.web.command.PaymentMerchantCommand; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +@Slf4j +@RunWith(SpringRunner.class) +@SpringBootTest +@ActiveProfiles({"dev", "alipay", "bestpay", "jd", "wechat", "rpay", "yeepay", "rppaysvc", "common", "alipayplusaps"}) +class ShopifyStoreCreatedListenerTest { + + @Autowired + private ShopifyStoreCreatedListener shopifyStoreCreatedListener; + + @Test + public void shopifyStoreRegisterTest() { + + SimpleMerchant simpleMerchant = SimpleMerchant.builder().clientId(00001).clientMoniker("test").build(); + PaymentMerchantCommand paymentMerchantCommand = new PaymentMerchantCommand() + .setCompanyName("test company ltd") + .setAddress("test address") + .setSuburb("test suburb") + .setState("test state") + .setCountry("test country") + .setContactPerson("test contact person") + .setContactPhone("test contact phone") + .setContactEmail("test contact email"); + + PaymentAccountCommand paymentAccountCommand = new PaymentAccountCommand() + .setLoginId("test login id") + .setPassword("test password") + .setConfirmPassword("test confirm password"); + + CreateShopifyMerchantCommand command = new CreateShopifyMerchantCommand().setShopifyShop("test.myshop.com").setPaymentMerchant(paymentMerchantCommand).setPaymentAccount(paymentAccountCommand); + ShopifyStoreCreatedEvent event = new ShopifyStoreCreatedEvent(new ShopifyStoreApplication(), simpleMerchant, command, MerchantAccountRequest.instanceOf(command, simpleMerchant)); + + shopifyStoreCreatedListener.onShopifyStoreCreated(event); + } +} \ No newline at end of file