Merge branch 'hotfix-citypartner_rate' into develop

master
Yixian 3 years ago
commit f35a92b7fa

@ -237,6 +237,12 @@
<artifactId>spring-boot-starter-webflux</artifactId> <artifactId>spring-boot-starter-webflux</artifactId>
</dependency> </dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.12</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>

@ -15,6 +15,7 @@ import org.springframework.boot.autoconfigure.mongo.MongoClientSettingsBuilderCu
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import java.io.File; import java.io.File;
@ -31,6 +32,7 @@ import java.util.concurrent.TimeUnit;
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableScheduling @EnableScheduling
@EnableCaching(proxyTargetClass = true) @EnableCaching(proxyTargetClass = true)
@EnableAsync
public class PaymentManageApplication { public class PaymentManageApplication {
public static void main(String[] args) { public static void main(String[] args) {

@ -511,7 +511,7 @@ public class CityPartnerPrizeServiceImpl implements CityPartnerPrizeService {
PayChannel payChannel = PayChannel.fromChannelCode(channel); PayChannel payChannel = PayChannel.fromChannelCode(channel);
if (payChannel == PayChannel.ALIPAY_APS_IN_STORE || payChannel == PayChannel.ALIPAY_APS_CASHIER) { if (payChannel == PayChannel.ALIPAY_APS_IN_STORE || payChannel == PayChannel.ALIPAY_APS_CASHIER) {
Map<Boolean, List<JSONObject>> groupByPayType = oneChannel.getValue().stream().collect(Collectors.groupingBy(e -> e.getString("pay_type").equals("alipay_cn"))); Map<Boolean, List<JSONObject>> groupByPayType = oneChannel.getValue().stream().collect(Collectors.groupingBy(e -> "alipay_cn".equalsIgnoreCase(e.getString("pay_type"))));
for (Map.Entry<Boolean, List<JSONObject>> payType : groupByPayType.entrySet()) { for (Map.Entry<Boolean, List<JSONObject>> payType : groupByPayType.entrySet()) {
BigDecimal totalAps = BigDecimal.ZERO; BigDecimal totalAps = BigDecimal.ZERO;
BigDecimal total_surageAps = BigDecimal.ZERO; BigDecimal total_surageAps = BigDecimal.ZERO;
@ -525,7 +525,7 @@ public class CityPartnerPrizeServiceImpl implements CityPartnerPrizeService {
BigDecimal channelRate = null; BigDecimal channelRate = null;
if (payChannel == PayChannel.ALIPAY_APS_IN_STORE) { if (payChannel == PayChannel.ALIPAY_APS_IN_STORE) {
if ("alipay_cn".equalsIgnoreCase(params.getString("pay_type"))) { 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 { } 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)); 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));
} }

@ -26,7 +26,7 @@ import java.util.Date;
@Component @Component
public class ShopifyMerchantAuthApplication { public class ShopifyMerchantAuthApplication {
@Value("${shopify.version:2021-10}") @Value("${shopify.version:2022-01}")
private String apiVersion; private String apiVersion;
@Value("${shopify.auth.apiKey}") @Value("${shopify.auth.apiKey}")
@ -53,34 +53,59 @@ public class ShopifyMerchantAuthApplication {
private PaymentsAppConfigureClient paymentsAppConfigureClient; private PaymentsAppConfigureClient paymentsAppConfigureClient;
/** /**
* shopifyURL * shopifyurl
* @param shopifyStoreHost
* @return
*/
public ShopifyPermissionURL getShopifyPermissionUrl(String shopifyStoreHost) {
ShopifyPermissionURL shopifyPermissionURL = shopifyAuthService.shopifyPermission(shopifyStoreHost);
return shopifyPermissionURL;
}
/**
* shopify
* *
* @param request * @param request
* @return * @return
*/ */
public ShopifyPermissionURL shopifyPermission(ShopifyPermissionRequest request) { public ShopifyAccessToken install(ShopifyPermissionRequest request) {
LoginInfo loginInfo = new LoginInfo(); LoginInfo loginInfo = new LoginInfo();
loginInfo.setLoginId(request.getLoginId()); loginInfo.setLoginId(request.getLoginId());
loginInfo.setPassword(request.getPassword()); loginInfo.setPassword(request.getPassword());
signInStatusManager.partnerSignIn(loginInfo); 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()); 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) { if (shopifyShop == null) {
shopifyStoreService.createShopifyStore(ShopifyStore.instanceOf(simpleMerchantAccount, simpleMerchant, request.getShop())); shopifyStoreService.createShopifyStore(ShopifyStore.instanceOf(simpleMerchantAccount, simpleMerchant, shop, accessToken));
return shopifyAuthService.shopifyPermission(request); return getShopifyPaymentAppConfigUrl(shop, accessToken);
} }
shopifyStoreService.modifyShopifyStore(shopifyShop shopifyStoreService.modifyShopifyStore(shopifyShop
.setClientId(simpleMerchantAccount.getClientId()) .setClientId(simpleMerchantAccount.getClientId())
.setClientMoniker(simpleMerchant.getClientMoniker()) .setClientMoniker(simpleMerchant.getClientMoniker())
.setModifyTime(new Date()) .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 * @param code code
* @return * @return
*/ */
@Deprecated
public ShopifyAccessToken merchantOnboard(String shop, String code) { public ShopifyAccessToken merchantOnboard(String shop, String code) {
ShopifyAccessToken accessToken = shopifyAuthService.getAccessToken(shop, code); ShopifyAccessToken accessToken = shopifyAuthService.getAccessToken(shop, code);
ShopifyStore shopifyStore = shopifyStoreService.getByShopifyShop(shop); ShopifyStore shopifyStore = shopifyStoreService.getByShopifyShop(shop);
@ -98,14 +124,8 @@ public class ShopifyMerchantAuthApplication {
} }
shopifyStoreService.modifyShopifyStore(shopifyStore.setAccessToken(accessToken.getAccess_token()).setScope(accessToken.getScope())); shopifyStoreService.modifyShopifyStore(shopifyStore.setAccessToken(accessToken.getAccess_token()).setScope(accessToken.getScope()));
try { return getShopifyPaymentAppConfigUrl(shop, accessToken);
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);
}
} }

@ -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;
}

@ -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);
}
}

@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestClientException;
@ -38,9 +39,17 @@ public class ShopifyAuthService {
@Qualifier("shopifyRestTemplate") @Qualifier("shopifyRestTemplate")
private RestTemplate restTemplate; 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 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(); 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)); log.info(String.format("Shopify merchant [%s] access token: %s", shop, shopifyAccessToken));
return shopifyAccessToken; return shopifyAccessToken;
} }
} }

@ -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("&timestamp=").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("&timestamp=").append(timestamp);
return HmacVerificationUtil.hmacSHA256(message.toString(),clientSecret,hmac);
}
public boolean verify(String message, String hmac) {
return HmacVerificationUtil.hmacSHA256(message,clientSecret,hmac);
}
}

@ -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.application.ShopifyMerchantAuthApplication;
import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyAccessToken; 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 au.com.royalpay.payment.manage.shopify.auth.web.command.ShopifyPermissionRequest;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView; 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; import javax.validation.Valid;
@ -26,28 +27,9 @@ public class ShopifyAuthController {
* @param request * @param request
* @return * @return
*/ */
@PostMapping("/permission") @PostMapping("/install")
public ShopifyPermissionURL shopifyPermission(@RequestBody @Valid ShopifyPermissionRequest request) { public ShopifyAccessToken shopifyStoreInstall(@RequestBody @Valid ShopifyPermissionRequest request) {
ShopifyPermissionURL shopifyPermissionURL = shopifyMerchantAuthApplication.shopifyPermission(request); ShopifyAccessToken shopifyAccessToken = shopifyMerchantAuthApplication.install(request);
return shopifyPermissionURL; 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;
}
} }

@ -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();
}
/**
* shopifyURL
*
* @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 + "&timestamp=" + timestamp);
response.setHeader("content-security-policy", "frame-ancestors https://" + shop + ".myshopify.com https://admin.shopify.com");
return new RedirectView(redirectUri);
}
}

@ -7,6 +7,7 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
@Data @Data
@Builder @Builder
@ -14,20 +15,26 @@ import javax.validation.constraints.NotBlank;
@AllArgsConstructor @AllArgsConstructor
public class ShopifyPermissionRequest { public class ShopifyPermissionRequest {
@NotBlank(message = "Shop can not blank")
private String shop;
@NotBlank(message = "Login Id can not blank") @NotBlank(message = "Login Id can not blank")
private String loginId; private String loginId;
@NotBlank(message = "Password can not blank") @NotBlank(message = "Password can not blank")
private String password; 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) { public static ShopifyPermissionRequest instanceOf(CreateShopifyMerchantCommand command) {
return ShopifyPermissionRequest.builder() return ShopifyPermissionRequest.builder()
.loginId(command.getPaymentAccount().getLoginId()) .loginId(command.getPaymentAccount().getLoginId())
.password(command.getPaymentAccount().getPassword()) .password(command.getPaymentAccount().getPassword())
.code(command.getCode())
.shop(command.getShopifyShop()) .shop(command.getShopifyShop())
.build(); .build();
} }
} }

@ -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;
}

@ -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);
}
/**
* shopifypayment 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));
}
}

@ -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;
}

@ -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<Long> orders_to_redact;
}

@ -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<Long> orders_requested;
private ShopifyCustomer customer;
private DataRequest data_request;
@Data
public class DataRequest{
private String id;
}
}

@ -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;
}

@ -1,21 +1,24 @@
package au.com.royalpay.payment.manage.shopify.store.domain.application; 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.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.auth.web.command.ShopifyPermissionRequest;
import au.com.royalpay.payment.manage.shopify.store.domain.context.MerchantCreateContext; 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.MerchantAccountRequest;
import au.com.royalpay.payment.manage.shopify.store.domain.entity.SimpleMerchant; 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.MerchantAccountService;
import au.com.royalpay.payment.manage.shopify.store.domain.service.MerchantService; 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.store.web.command.CreateShopifyMerchantCommand;
import au.com.royalpay.payment.manage.shopify.support.PlatformMerchantProvider; import au.com.royalpay.payment.manage.shopify.support.PlatformMerchantProvider;
import org.springframework.beans.factory.annotation.Autowired; 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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class ShopifyStoreApplication { public class ShopifyStoreApplication implements ApplicationEventPublisherAware {
@Autowired @Autowired
private MerchantService merchantservice; private MerchantService merchantservice;
@ -29,6 +32,13 @@ public class ShopifyStoreApplication {
@Autowired @Autowired
private ShopifyMerchantAuthApplication shopifyMerchantAuthApplication; private ShopifyMerchantAuthApplication shopifyMerchantAuthApplication;
private ApplicationEventPublisher eventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher;
}
/** /**
* partnerCode * partnerCode
* *
@ -46,7 +56,7 @@ public class ShopifyStoreApplication {
* @return * @return
*/ */
@Transactional @Transactional
public ShopifyPermissionURL register(CreateShopifyMerchantCommand command) { public ShopifyAccessToken register(CreateShopifyMerchantCommand command) {
MerchantCreateContext merchantCreateContext = new MerchantCreateContext(platformMerchantProvider, command); MerchantCreateContext merchantCreateContext = new MerchantCreateContext(platformMerchantProvider, command);
SimpleMerchant simpleMerchant = merchantservice.createMerchant(merchantCreateContext); SimpleMerchant simpleMerchant = merchantservice.createMerchant(merchantCreateContext);
@ -54,6 +64,12 @@ public class ShopifyStoreApplication {
MerchantAccountRequest accountRequest = MerchantAccountRequest.instanceOf(command, simpleMerchant); MerchantAccountRequest accountRequest = MerchantAccountRequest.instanceOf(command, simpleMerchant);
merchantAccountService.createAccount(accountRequest); 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;
} }
} }

@ -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;
}

@ -1,5 +1,6 @@
package au.com.royalpay.payment.manage.shopify.store.domain.entity; 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.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@ -36,7 +37,9 @@ public class ShopifyStore {
private String scope; 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() return ShopifyStore.builder()
.id(UUID.randomUUID().toString()) .id(UUID.randomUUID().toString())
.clientId(merchantAccount.getClientId()) .clientId(merchantAccount.getClientId())
@ -44,6 +47,8 @@ public class ShopifyStore {
.shopifyShop(shop) .shopifyShop(shop)
.createTime(new Date()) .createTime(new Date())
.creator("shopify store") .creator("shopify store")
.accessToken(accessToken.getAccess_token())
.scope(accessToken.getScope())
.modifyTime(new Date()).build(); .modifyTime(new Date()).build();
} }
} }

@ -1,12 +1,14 @@
package au.com.royalpay.payment.manage.shopify.store.domain.entity; package au.com.royalpay.payment.manage.shopify.store.domain.entity;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Builder
public class SimpleMerchant { public class SimpleMerchant {
private Integer clientId; private Integer clientId;
private String clientMoniker; private String clientMoniker;

@ -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;
}
}

@ -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();
}
}
}

@ -1,5 +1,6 @@
package au.com.royalpay.payment.manage.shopify.store.web; 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.auth.domain.entity.ShopifyPermissionURL;
import au.com.royalpay.payment.manage.shopify.store.domain.application.ShopifyStoreApplication; import au.com.royalpay.payment.manage.shopify.store.domain.application.ShopifyStoreApplication;
import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand; import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand;
@ -23,6 +24,7 @@ public class ShopifyStoreController {
* *
* @param partnerCode * @param partnerCode
*/ */
@Deprecated
@GetMapping("/exist") @GetMapping("/exist")
public Boolean validPaymentAppMerchant(@RequestParam("partnerCode") String partnerCode) { public Boolean validPaymentAppMerchant(@RequestParam("partnerCode") String partnerCode) {
return shopifyStoreApplication.existMerchant(partnerCode); return shopifyStoreApplication.existMerchant(partnerCode);
@ -35,7 +37,7 @@ public class ShopifyStoreController {
* @Return * @Return
*/ */
@PostMapping("/register") @PostMapping("/register")
public ShopifyPermissionURL createMerchantWithShopify(@RequestBody @Valid CreateShopifyMerchantCommand command) { public ShopifyAccessToken createMerchantWithShopify(@RequestBody @Valid CreateShopifyMerchantCommand command) {
return shopifyStoreApplication.register(command); return shopifyStoreApplication.register(command);
} }
} }

@ -4,6 +4,7 @@ import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
@Data @Data
@Accessors(chain = true) @Accessors(chain = true)
@ -13,6 +14,11 @@ public class CreateShopifyMerchantCommand {
private PaymentAccountCommand paymentAccount; private PaymentAccountCommand paymentAccount;
@NotBlank(message = "Auth code can not blank")
private String code;
@NotBlank(message = "Shop can not blank") @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; private String shopifyShop;
} }

@ -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();
}
}

@ -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();
}
}

@ -35,6 +35,7 @@ import org.springframework.util.Assert;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;

@ -151,7 +151,6 @@
</select> </select>
<update id="postponeMerchantRateByClientId"> <update id="postponeMerchantRateByClientId">
<![CDATA[ <![CDATA[
INSERT sys_client_rates (manager_id, client_id, rate_name, rate_value, transaction_fee, active_time, expiry_time, create_time, update_time, manager_name, clean_days, remark,ext_rates,pay_type) INSERT sys_client_rates (manager_id, client_id, rate_name, rate_value, transaction_fee, active_time, expiry_time, create_time, update_time, manager_name, clean_days, remark,ext_rates,pay_type)
SELECT CONCAT('System-', CURRENT_DATE()),r.client_id,r.rate_name,r.rate_value,r.transaction_fee,DATE_ADD(r.expiry_time, INTERVAL 1 day), SELECT CONCAT('System-', CURRENT_DATE()),r.client_id,r.rate_name,r.rate_value,r.transaction_fee,DATE_ADD(r.expiry_time, INTERVAL 1 day),
IF(DATE_ADD( r.expiry_time, INTERVAL 1 YEAR )<=NOW(),DATE_ADD( r.expiry_time, INTERVAL 2 YEAR ),DATE_ADD( r.expiry_time, INTERVAL 1 YEAR )) expiry_time,NOW(), NOW(), IF(DATE_ADD( r.expiry_time, INTERVAL 1 YEAR )<=NOW(),DATE_ADD( r.expiry_time, INTERVAL 2 YEAR ),DATE_ADD( r.expiry_time, INTERVAL 1 YEAR )) expiry_time,NOW(), NOW(),
@ -161,7 +160,6 @@
and rr.rate_name = #{channel} and rr.rate_name = #{channel}
order by rr.expiry_time desc limit 1) r order by rr.expiry_time desc limit 1) r
where r.expiry_time<= current_date() where r.expiry_time<= current_date()
]]> ]]>
</update> </update>
<select id="latestConfig" resultType="com.alibaba.fastjson.JSONObject"> <select id="latestConfig" resultType="com.alibaba.fastjson.JSONObject">

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="zh">
<div style="margin:0;">Registration application from Shopify store</div>
<blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;">
<div style="margin:0;">Partner Code:<span th:text="${applyInfo.clientMoniker}"></span></div>
<div style="margin:0;">Company Name:<span th:text="${applyInfo.companyName}"></span></div>
<div style="margin:0;">Address:<span th:text="${applyInfo.address}"></span></div>
<div style="margin:0;">Suburb:<span th:text="${applyInfo.suburb}"></span></div>
<div style="margin:0;">State:<span th:text="${applyInfo.state}"></span></div>
<div style="margin:0;">Country:<span th:text="${applyInfo.country}"></span></div>
<div style="margin:0;">Contact Person:<span th:text="${applyInfo.contactPerson}"></span></div>
<div style="margin:0;">Contact Phone:<span th:text="${applyInfo.contactPhone}"></span></div>
<div style="margin:0;">Contact Email:<span th:text="${applyInfo.contactEmail}"></span></div>
<div style="margin:0;">Shopify Store Host:<span th:text="${applyInfo.shopifyShop}"></span></div>
</blockquote>
<div></div>
<div>Please deal with it in time</div>
<blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;">
<div style="margin:0;"><br/></div>
</blockquote>
<div style="margin:0;">&nbsp; &nbsp; &nbsp; &nbsp;</div>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 KiB

After

Width:  |  Height:  |  Size: 895 KiB

@ -1,7 +1,24 @@
define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) {
'use strict'; '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']); 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', { $stateProvider.state('shopify', {
url: '/shopify', url: '/shopify',
templateUrl: '/static/shopify/auth/templates/auth_root.html', templateUrl: '/static/shopify/auth/templates/auth_root.html',
@ -13,19 +30,19 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) {
}).state('shopify.login', { }).state('shopify.login', {
url: '/login', url: '/login',
templateUrl: '/static/shopify/auth/templates/shopify_login.html', templateUrl: '/static/shopify/auth/templates/shopify_login.html',
params: {'userId': null}, params: {'shop': null, 'code': null},
controller: 'ShopifyLoginController' controller: 'ShopifyLoginController'
}).state('shopify.register', { }).state('shopify.register', {
url: '/register', url: '/register',
templateUrl: '/static/shopify/auth/templates/shopify_register.html', 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' controller: 'ShopifyRegisterController'
}); });
}]); }]);
module.controller('ShopifyRootController', ['$scope', '$http', '$state', function ($scope, $http, $state) { module.controller('ShopifyRootController', ['$scope', '$http', '$state', function ($scope, $http, $state) {
if ($state.is('shopify')) { if ($state.is('shopify')) {
$state.go('shopify.auth') $state.go('shopify.login')
} }
}]) }])
@ -48,31 +65,67 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) {
that.authDisable = false 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 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 = { that.model = {
shop: '',
partnerCode: $stateParams.partnerCode,
loginId: '', loginId: '',
password: '' password: '',
code: code,
hmac: hmac,
host:host,
shop: shop,
state: state,
timestamp: timestamp
} }
that.loginDisable = false 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.activeShopifyMerchant = function () {
that.loginDisable = true that.loginDisable = true
$http.post("/shopify/auth/permission", that.model).then(function (res) { $http.post("/shopify/auth/install", that.model).then(function (res) {
console.log("permissionUrl", res.data.url) console.log("redirectUrl", res.data.redirectUrl)
location.href = res.data.url location.href = res.data.redirectUrl
}, function (error) { }, function (error) {
that.resError = error.data.message; that.resError = error.data.message;
that.loginDisable = false 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) { module.controller('ShopifyRegisterController', ['$scope', '$http', '$stateParams', function ($scope, $http, $stateParams) {
@ -223,10 +276,15 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) {
const param = { const param = {
paymentMerchant, paymentMerchant,
paymentAccount, 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) { $http.post('shopify/store/register', param).then(function (resp) {
location.href = resp.data.url location.href = resp.data.redirectUrl
}, function (error) { }, function (error) {
that.resError = error.data.message; that.resError = error.data.message;
that.registerDisable = false that.registerDisable = false

@ -28,22 +28,26 @@
<form> <form>
<div class="form-group form-group-lg"> <div class="form-group form-group-lg">
<input class="form-control input-lg" id="exampleInputEmail" placeholder="Login ID" ng-model="model.loginId"> <input class="form-control input-lg" id="exampleInputEmail" placeholder="Login ID"
ng-model="model.loginId">
</div> </div>
<div class="form-group form-group-lg"> <div class="form-group form-group-lg">
<input type="password" class="form-control" id="exampleInputPassword" placeholder="Password" ng-model="model.password"> <input type="password" class="form-control" id="exampleInputPassword" placeholder="Password"
ng-model="model.password">
</div> </div>
<div class="form-group form-group-lg"> <button class="btn btn-warning btn-lg btn-block m-t-40" ng-disabled="loginDisable"
<input class="form-control input-lg" id="shopifyShop" placeholder="Shop" ng-model="model.shop"> ng-click="activeShopifyMerchant()">Log In
<p class="help-block">Example: geek-test-shop.myshopify.com</p> </button>
</div>
<button class="btn btn-warning btn-lg btn-block m-t-40" ng-disabled="loginDisable" ng-click="activeShopifyMerchant()">Log In</button>
<div> <div>
<p ng-if="resError" style="padding: 6px 12px;font-size: 14px;" <p ng-if="resError" style="padding: 6px 12px;font-size: 14px;"
class="small text-danger">{{resError}}</p> class="small text-danger">{{resError}}</p>
</div> </div>
<div class="m-t-10"></div>
<span style="padding-top: 15px">
Not a RoyalPay merchant yet, <a href="" ng-click="registerMerchant()">please register</a>
</span>
</form> </form>
</div> </div>
</div> </div>

@ -53,7 +53,7 @@
</div> </div>
</div> </div>
<div class="form-group has-feedback" <!--<div class="form-group has-feedback"
ng-class="{'has-error':partnerForm.shopifyShop.$invalid && partnerForm.shopifyShop.$dirty}"> ng-class="{'has-error':partnerForm.shopifyShop.$invalid && partnerForm.shopifyShop.$dirty}">
<input type="text" class="form-control" ng-model="partner.shopifyShop" name="shopifyShop" <input type="text" class="form-control" ng-model="partner.shopifyShop" name="shopifyShop"
placeholder="Shop" required> placeholder="Shop" required>
@ -62,7 +62,7 @@
ng-if="partnerForm.shopifyShop.$dirty"> ng-if="partnerForm.shopifyShop.$dirty">
<p class="small text-danger" ng-message="required">Required Field</p> <p class="small text-danger" ng-message="required">Required Field</p>
</div> </div>
</div> </div>-->
<div class="form-group has-feedback" <div class="form-group has-feedback"
ng-class="{'has-error':partnerForm.companyName.$invalid && partnerForm.companyName.$dirty}"> ng-class="{'has-error':partnerForm.companyName.$invalid && partnerForm.companyName.$dirty}">

@ -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));
}
}

@ -1,5 +1,6 @@
package au.com.royalpay.payment.manage.shopify.store.domain.application; 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.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.CreateShopifyMerchantCommand;
import au.com.royalpay.payment.manage.shopify.store.web.command.PaymentAccountCommand; import au.com.royalpay.payment.manage.shopify.store.web.command.PaymentAccountCommand;
@ -46,7 +47,7 @@ class ShopifyStoreApplicationTest {
.setPaymentAccount(accountCommand) .setPaymentAccount(accountCommand)
.setShopifyShop("demo.myshopify.com"); .setShopifyShop("demo.myshopify.com");
ShopifyPermissionURL shopifyPermissionURL = shopifyStoreApplication.register(command); ShopifyAccessToken shopifyAccessToken = shopifyStoreApplication.register(command);
log.warn(JSON.toJSONString(shopifyPermissionURL)); log.warn(JSON.toJSONString(shopifyAccessToken));
} }
} }

@ -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);
}
}
Loading…
Cancel
Save