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 @@ diff --git a/src/main/resources/templates/mail/shopify_merchant_application.html b/src/main/resources/templates/mail/shopify_merchant_application.html new file mode 100644 index 000000000..73e96627b --- /dev/null +++ b/src/main/resources/templates/mail/shopify_merchant_application.html @@ -0,0 +1,22 @@ + + +Registration application from Shopify store: + + Partner Code: + Company Name: + Address: + Suburb: + State: + Country: + Contact Person: + Contact Phone: + Contact Email: + Shopify Store Host: + + +Please deal with it in time! + + + + + \ No newline at end of file diff --git a/src/main/ui/static/images/aggretage_aps_board.jpg b/src/main/ui/static/images/aggretage_aps_board.jpg index cbb3499b3..b32cfe33e 100644 Binary files a/src/main/ui/static/images/aggretage_aps_board.jpg and b/src/main/ui/static/images/aggretage_aps_board.jpg differ diff --git a/src/main/ui/static/shopify/auth/shopify.auth.js b/src/main/ui/static/shopify/auth/shopify.auth.js index d3f97904a..6e175b53b 100644 --- a/src/main/ui/static/shopify/auth/shopify.auth.js +++ b/src/main/ui/static/shopify/auth/shopify.auth.js @@ -1,7 +1,24 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { 'use strict'; + + function getQueryVariable(variable) { + var query = window.location.search.substring(1); + var vars = query.split("&"); + for (var i = 0; i < vars.length; i++) { + var pair = vars[i].split("="); + if (pair[0] == variable) { + return pair[1]; + } + } + return null; + } + var module = angular.module('shopify.auth', ['ui.router', 'ui.bootstrap', 'ngMessages']); - module.config(['$stateProvider', function ($stateProvider) { + module.config(['$stateProvider', '$locationProvider', function ($stateProvider, $locationProvider) { + $locationProvider.html5Mode({ + enabled: false, + requireBase: false + }); $stateProvider.state('shopify', { url: '/shopify', templateUrl: '/static/shopify/auth/templates/auth_root.html', @@ -13,19 +30,19 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { }).state('shopify.login', { url: '/login', templateUrl: '/static/shopify/auth/templates/shopify_login.html', - params: {'userId': null}, + params: {'shop': null, 'code': null}, controller: 'ShopifyLoginController' }).state('shopify.register', { url: '/register', templateUrl: '/static/shopify/auth/templates/shopify_register.html', - params: {'userId': null}, + params: {'code': null, 'hmac':null, 'host': null,'shop': null, 'state': null,'timestamp':null}, controller: 'ShopifyRegisterController' }); }]); module.controller('ShopifyRootController', ['$scope', '$http', '$state', function ($scope, $http, $state) { if ($state.is('shopify')) { - $state.go('shopify.auth') + $state.go('shopify.login') } }]) @@ -43,36 +60,72 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { } else { $state.go('shopify.register', {partnerCode: that.store.partnerCode}); } - },function (error) { + }, function (error) { that.resError = error.data.message; that.authDisable = false }) } - - that.registerMerchant = function () { - $state.go('shopify.register'); - } }]); - module.controller('ShopifyLoginController', ['$scope', '$http', '$stateParams', function ($scope, $http, $stateParams) { + module.controller('ShopifyLoginController', ['$scope', '$http', '$state', '$stateParams', '$location', function ($scope, $http, $state, $stateParams, $location) { var that = $scope; + + /*var code = getQueryVariable("code") + var hmac = getQueryVariable("hmac") + var host = getQueryVariable("host") + var shop = getQueryVariable("shop") + var state = getQueryVariable("state") + var timestamp = getQueryVariable("timestamp")*/ + + var code = $location.search().code + var hmac = $location.search().hmac + var host = $location.search().host + var shop = $location.search().shop + var state = $location.search().state + var timestamp = $location.search().timestamp + that.model = { - shop: '', - partnerCode: $stateParams.partnerCode, loginId: '', - password: '' + password: '', + code: code, + hmac: hmac, + host:host, + shop: shop, + state: state, + timestamp: timestamp } that.loginDisable = false + + /*that.verifyRequest = function () { + $http.post("/shopify/auth/verify", that.model).then(function (res) { + }, function (error) { + that.resError = error.data.message; + that.loginDisable = false + }) + } + that.verifyRequest()*/ + that.activeShopifyMerchant = function () { that.loginDisable = true - $http.post("/shopify/auth/permission", that.model).then(function (res) { - console.log("permissionUrl", res.data.url) - location.href = res.data.url - },function (error) { + $http.post("/shopify/auth/install", that.model).then(function (res) { + console.log("redirectUrl", res.data.redirectUrl) + location.href = res.data.redirectUrl + }, function (error) { that.resError = error.data.message; that.loginDisable = false }) } + + that.registerMerchant = function () { + $state.go('shopify.register', { + code: code, + hmac: hmac, + host: host, + shop: shop, + state: state, + timestamp: timestamp + }); + } }]); module.controller('ShopifyRegisterController', ['$scope', '$http', '$stateParams', function ($scope, $http, $stateParams) { @@ -223,10 +276,15 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { const param = { paymentMerchant, paymentAccount, - shopifyShop: that.partner.shopifyShop + code: $stateParams.code, + hmac: $stateParams.hmac, + host: $stateParams.host, + shopifyShop: $stateParams.shop, + state: $stateParams.state, + timestamp: $stateParams.timestamp } $http.post('shopify/store/register', param).then(function (resp) { - location.href = resp.data.url + location.href = resp.data.redirectUrl }, function (error) { that.resError = error.data.message; that.registerDisable = false diff --git a/src/main/ui/static/shopify/auth/templates/shopify_login.html b/src/main/ui/static/shopify/auth/templates/shopify_login.html index aa526c7a4..d8af432d1 100644 --- a/src/main/ui/static/shopify/auth/templates/shopify_login.html +++ b/src/main/ui/static/shopify/auth/templates/shopify_login.html @@ -5,7 +5,7 @@ Title
+ Partner Code: + Company Name: + Address: + Suburb: + State: + Country: + Contact Person: + Contact Phone: + Contact Email: + Shopify Store Host: +
+ +