feat: 实现支付分停车服务API

- 查询车牌服务开通信息API
- 创建停车入场API
- 扣费受理API
- 查询订单API
- 停车入场状态变更通知API
- 订单支付结果通知API
This commit is contained in:
Fang
2022-06-12 22:23:07 +08:00
parent b1b0020524
commit 087cf4ecab
12 changed files with 947 additions and 11 deletions

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2019-2021 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.enumeration;
/**
* 车牌颜色枚举
* @author felord.cn
* @since 1.0.13.RELEASE
*/
public enum PlateColor {
/**
* 蓝色
*/
BLUE,
/**
* 绿色
*/
GREEN,
/**
* 黄色
*/
YELLOW,
/**
* 黑色
*/
BLACK,
/**
* 白色
*/
WHITE,
/**
* 黄绿色
*/
LIMEGREEN
}

View File

@@ -195,7 +195,7 @@ public enum WechatPayV3Type {
*/ */
PAY_SCORE_TERMINATE_PERMISSIONS_OPENID(HttpMethod.POST, "%s/v3/payscore/permissions/openid/{openid}/terminate"), PAY_SCORE_TERMINATE_PERMISSIONS_OPENID(HttpMethod.POST, "%s/v3/payscore/permissions/openid/{openid}/terminate"),
/** /**
* 查询用户授权状态API. * 查询用户授权状态API(旧版接口).
* *
* @since 1.0.2.RELEASE * @since 1.0.2.RELEASE
*/ */
@@ -248,8 +248,30 @@ public enum WechatPayV3Type {
* @since 1.0.13.RELEASE * @since 1.0.13.RELEASE
*/ */
PAY_SCORE_MERCHANT_BILL(HttpMethod.GET, "%s/v3/payscore/merchant-bill"), PAY_SCORE_MERCHANT_BILL(HttpMethod.GET, "%s/v3/payscore/merchant-bill"),
/**
* 查询车牌服务开通信息API
*
* @since 1.0.13.RELEASE
*/
PAY_SCORE_PARKING_FIND(HttpMethod.GET, "%s/v3/vehicle/parking/services/find"),
/**
* 创建停车入场API
*
* @since 1.0.13.RELEASE
*/
PAY_SCORE_PARKING_PARKINGS(HttpMethod.POST, "%s/v3/vehicle/parking/parkings"),
/**
* 扣费受理API
*
* @since 1.0.13.RELEASE
*/
PAY_SCORE_PARKING_TRANSACTIONS_PARKINGS(HttpMethod.POST, "%s/v3/vehicle/transactions/parking"),
/**
* 查询订单API
*
* @since 1.0.13.RELEASE
*/
PAY_SCORE_PARKING_TRANSACTIONS_OUTTRADENO(HttpMethod.GET, "%s/v3/vehicle/transactions/out-trade-no/{out_trade_no}"),
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** /**

View File

@@ -100,6 +100,17 @@ public class WechatApiProvider {
return new WechatPayScoreApi(wechatPayClient, tenantId); return new WechatPayScoreApi(wechatPayClient, tenantId);
} }
/**
* 微信支付分停车服务.
*
* @param tenantId the tenant id
* @return the wechat pay score parking api
* @since 1.0.13.RELEASE
*/
public WechatPayScoreParkingApi payScoreParkingApi(String tenantId) {
return new WechatPayScoreParkingApi(wechatPayClient, tenantId);
}
/** /**
* 微信支付先享卡. * 微信支付先享卡.
* *

View File

@@ -18,7 +18,12 @@
package cn.felord.payment.wechat.v3; package cn.felord.payment.wechat.v3;
import cn.felord.payment.PayException; import cn.felord.payment.PayException;
import cn.felord.payment.wechat.v3.model.*; import cn.felord.payment.wechat.v3.model.CallbackParams;
import cn.felord.payment.wechat.v3.model.CouponConsumeData;
import cn.felord.payment.wechat.v3.model.ProfitSharingConsumeData;
import cn.felord.payment.wechat.v3.model.RefundConsumeData;
import cn.felord.payment.wechat.v3.model.ResponseSignVerifyParams;
import cn.felord.payment.wechat.v3.model.TransactionConsumeData;
import cn.felord.payment.wechat.v3.model.busifavor.BusiFavorReceiveConsumeData; import cn.felord.payment.wechat.v3.model.busifavor.BusiFavorReceiveConsumeData;
import cn.felord.payment.wechat.v3.model.combine.CombineTransactionConsumeData; import cn.felord.payment.wechat.v3.model.combine.CombineTransactionConsumeData;
import cn.felord.payment.wechat.v3.model.discountcard.DiscountCardAcceptedConsumeData; import cn.felord.payment.wechat.v3.model.discountcard.DiscountCardAcceptedConsumeData;
@@ -29,6 +34,8 @@ import cn.felord.payment.wechat.v3.model.payscore.PayScoreConsumer;
import cn.felord.payment.wechat.v3.model.payscore.PayScoreUserConfirmConsumeData; import cn.felord.payment.wechat.v3.model.payscore.PayScoreUserConfirmConsumeData;
import cn.felord.payment.wechat.v3.model.payscore.PayScoreUserPaidConsumeData; import cn.felord.payment.wechat.v3.model.payscore.PayScoreUserPaidConsumeData;
import cn.felord.payment.wechat.v3.model.payscore.PayScoreUserPermissionConsumeData; import cn.felord.payment.wechat.v3.model.payscore.PayScoreUserPermissionConsumeData;
import cn.felord.payment.wechat.v3.model.payscore.parking.ParkingCallback;
import cn.felord.payment.wechat.v3.model.payscore.parking.TransParkingCallback;
import cn.felord.payment.wechat.v3.model.profitsharing.ProfitsharingConsumeData; import cn.felord.payment.wechat.v3.model.profitsharing.ProfitsharingConsumeData;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
@@ -101,7 +108,7 @@ public class WechatPayCallback {
*/ */
@SneakyThrows @SneakyThrows
public Map<String, String> profitSharingCallback(ResponseSignVerifyParams params, Consumer<ProfitSharingConsumeData> consumeDataConsumer) { public Map<String, String> profitSharingCallback(ResponseSignVerifyParams params, Consumer<ProfitSharingConsumeData> consumeDataConsumer) {
String data = this.callback(params, EventType.TRANSACTION); String data = this.callback(params, EventType.TRANSACTION_SUCCESS);
ProfitSharingConsumeData consumeData = MAPPER.readValue(data, ProfitSharingConsumeData.class); ProfitSharingConsumeData consumeData = MAPPER.readValue(data, ProfitSharingConsumeData.class);
consumeDataConsumer.accept(consumeData); consumeDataConsumer.accept(consumeData);
return response(); return response();
@@ -138,7 +145,7 @@ public class WechatPayCallback {
*/ */
@SneakyThrows @SneakyThrows
public Map<String, String> transactionCallback(ResponseSignVerifyParams params, Consumer<TransactionConsumeData> consumeDataConsumer) { public Map<String, String> transactionCallback(ResponseSignVerifyParams params, Consumer<TransactionConsumeData> consumeDataConsumer) {
String data = this.callback(params, EventType.TRANSACTION); String data = this.callback(params, EventType.TRANSACTION_SUCCESS);
TransactionConsumeData consumeData = MAPPER.readValue(data, TransactionConsumeData.class); TransactionConsumeData consumeData = MAPPER.readValue(data, TransactionConsumeData.class);
consumeDataConsumer.accept(consumeData); consumeDataConsumer.accept(consumeData);
return response(); return response();
@@ -156,7 +163,7 @@ public class WechatPayCallback {
*/ */
@SneakyThrows @SneakyThrows
public Map<String, String> combineTransactionCallback(ResponseSignVerifyParams params, Consumer<CombineTransactionConsumeData> consumeDataConsumer) { public Map<String, String> combineTransactionCallback(ResponseSignVerifyParams params, Consumer<CombineTransactionConsumeData> consumeDataConsumer) {
String data = this.callback(params, EventType.TRANSACTION); String data = this.callback(params, EventType.TRANSACTION_SUCCESS);
CombineTransactionConsumeData consumeData = MAPPER.readValue(data, CombineTransactionConsumeData.class); CombineTransactionConsumeData consumeData = MAPPER.readValue(data, CombineTransactionConsumeData.class);
consumeDataConsumer.accept(consumeData); consumeDataConsumer.accept(consumeData);
return response(); return response();
@@ -192,6 +199,73 @@ public class WechatPayCallback {
return response(); return response();
} }
/**
* 支付分停车入场状态变更通知.
* <p>
* 从用户进入开通微信支付分停车服务的停车场(用户入场通知接口),到用户离场期间(扣款接口),
* 这个时间段内如果停车入场状态变为可用或者不可用,微信会把相关状态变更情况(可用/不可用)异步发送给商户,
* 回调url为调用用户入场通知接口时填写的notify_url字段。
* 商户在收到停车入场状态变更通知后,需进行接收处理并返回应答。
*
* @param params the params
* @param parkingCallbackConsumer the parking callback consumer
* @return the map
* @since 1.0.13.RELEASE
*/
@SneakyThrows
public Map<String, String> payscoreParkingCallback(ResponseSignVerifyParams params, Consumer<ParkingCallback> parkingCallbackConsumer) {
CallbackParams callbackParams = resolve(params);
String eventType = callbackParams.getEventType();
if (Objects.equals(eventType, EventType.PAYSCORE_PARKING_ENTRANCE_STATE_CHANGE.event)) {
String data = this.decrypt(callbackParams);
ParkingCallback parkingCallback = MAPPER.readValue(data, ParkingCallback.class);
parkingCallbackConsumer.accept(parkingCallback);
} else {
log.error("wechat pay event type is not matched, callbackParams {}", callbackParams);
throw new PayException(" wechat pay event type is not matched");
}
return response();
}
/**
* 支付分停车订单支付结果通知
* <p>
* 商户请求微信支付分停车服务扣费受理接口,会完成订单受理。
* 订单实际支付完成后,微信支付会把订单支付结果信息发送给商户,商户需要接收处理,并返回应答。
* 同时,如果由于用户余额不足等原因,微信支付会进行垫资,用户对该垫资单进行了还款以后,微信支付会把该笔订单还款信息通知到商户。
* <p>
* 注意:
* <ul>
* <li>同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
* 推荐的做法是,当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。
* 如果未处理,则再进行处理;如果已处理,则直接返回结果成功。
* 在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。</li>
* <li>如果在所有通知频率后没有收到微信侧回调,商户应调用查询订单接口确认订单状态。</li>
* </ul>
* 特别提醒:商户系统对于支付成功通知的内容一定要做签名验证,并校验通知的信息是否与商户侧的信息一致,防止数据泄露导致出现“假通知”,造成资金损失。
* @param params the params
* @param transParkingCallbackConsumer the transParkingCallbackConsumer
* @return the map
* @since 1.0.13.RELEASE
*/
@SneakyThrows
public Map<String, String> payscoreTransParkingCallback(ResponseSignVerifyParams params, Consumer<TransParkingCallback> transParkingCallbackConsumer) {
CallbackParams callbackParams = resolve(params);
String eventType = callbackParams.getEventType();
if (Objects.equals(eventType, EventType.TRANSACTION_SUCCESS.event) ||
Objects.equals(eventType, EventType.TRANSACTION_FAIL.event) ||
Objects.equals(eventType, EventType.TRANSACTION_PAY_BACK.event)
) {
String data = this.decrypt(callbackParams);
TransParkingCallback transParkingCallback = MAPPER.readValue(data, TransParkingCallback.class);
transParkingCallbackConsumer.accept(transParkingCallback);
} else {
log.error("wechat pay event type is not matched, callbackParams {}", callbackParams);
throw new PayException(" wechat pay event type is not matched");
}
return response();
}
/** /**
* 授权/解除授权服务回调通知API. * 授权/解除授权服务回调通知API.
* <p> * <p>
@@ -322,7 +396,7 @@ public class WechatPayCallback {
*/ */
@SneakyThrows @SneakyThrows
public Map<String, String> profitsharingCallback(ResponseSignVerifyParams params, Consumer<ProfitsharingConsumeData> profitsharingConsumeDataConsumer) { public Map<String, String> profitsharingCallback(ResponseSignVerifyParams params, Consumer<ProfitsharingConsumeData> profitsharingConsumeDataConsumer) {
String callback = this.callback(params, EventType.TRANSACTION); String callback = this.callback(params, EventType.TRANSACTION_SUCCESS);
ProfitsharingConsumeData consumeData = MAPPER.readValue(callback, ProfitsharingConsumeData.class); ProfitsharingConsumeData consumeData = MAPPER.readValue(callback, ProfitsharingConsumeData.class);
profitsharingConsumeDataConsumer.accept(consumeData); profitsharingConsumeDataConsumer.accept(consumeData);
return response(); return response();
@@ -426,6 +500,12 @@ public class WechatPayCallback {
* @since 1.0.2.RELEASE * @since 1.0.2.RELEASE
*/ */
PAYSCORE_USER_CLOSE("PAYSCORE.USER_CLOSE_SERVICE"), PAYSCORE_USER_CLOSE("PAYSCORE.USER_CLOSE_SERVICE"),
/**
* 停车入场状态变更通知事件.
*
* @since 1.0.13.RELEASE
*/
PAYSCORE_PARKING_ENTRANCE_STATE_CHANGE("VEHICLE.ENTRANCE_STATE_CHANGE"),
/** /**
* 用户领取微信先享卡事件. * 用户领取微信先享卡事件.
@@ -467,11 +547,19 @@ public class WechatPayCallback {
COUPON_SEND("COUPON.SEND"), COUPON_SEND("COUPON.SEND"),
/** /**
* 支付成功、分账、分账回退事件. * 支付成功、支付分停车支付成功、分账、分账回退事件.
* *
* @since 1.0.0.RELEASE * @since 1.0.0.RELEASE
*/ */
TRANSACTION("TRANSACTION.SUCCESS"), TRANSACTION_SUCCESS("TRANSACTION.SUCCESS"),
/**
* 支付分停车支付失败通知
*/
TRANSACTION_FAIL("TRANSACTION.FAIL"),
/**
* 支付分停车还款通知
*/
TRANSACTION_PAY_BACK("TRANSACTION.PAY_BACK"),
/** /**
* 退款成功事件. * 退款成功事件.

View File

@@ -53,7 +53,7 @@ public class WechatPayScoreApi extends AbstractApi {
} }
/** /**
* 微信支付分-查询用户授权状态API. * 微信支付分-查询用户授权状态API(旧版接口).
* <p> * <p>
* 免确认订单起始接口,【免确认订单模式】是高级接口权限,参见:<a href="https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter2_5.shtml">业务流程说明</a> * 免确认订单起始接口,【免确认订单模式】是高级接口权限,参见:<a href="https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter2_5.shtml">业务流程说明</a>
* <p> * <p>

View File

@@ -0,0 +1,160 @@
/*
* Copyright 2019-2022 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3;
import cn.felord.payment.wechat.WechatPayProperties;
import cn.felord.payment.wechat.enumeration.WeChatServer;
import cn.felord.payment.wechat.enumeration.WechatPayV3Type;
import cn.felord.payment.wechat.v3.model.ResponseSignVerifyParams;
import cn.felord.payment.wechat.v3.model.payscore.parking.ParkingServiceQueryParams;
import cn.felord.payment.wechat.v3.model.payscore.parking.ParkingParams;
import cn.felord.payment.wechat.v3.model.payscore.parking.TransParkingParams;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.util.function.Consumer;
/**
* 微信支付分停车服务API.
* <p>
* 详细文档,参见 <a href="https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter3_7_1.shtml">微信支付分停车服务介绍</a>
*
* @author felord.cn
* @since 1.0.13.RELEASE
*/
public class WechatPayScoreParkingApi extends AbstractApi {
/**
* Instantiates a new Abstract api.
*
* @param wechatPayClient the wechat pay client
* @param tenantId the tenant id
*/
public WechatPayScoreParkingApi(WechatPayClient wechatPayClient, String tenantId) {
super(wechatPayClient, tenantId);
}
/**
* 微信支付分-查询车牌服务开通信息API
* <p>
* 该接口仅支持停车场景,商户首先请求查询车牌服务开通信息接口,确认该车牌,是否被该用户开通车主服务。
*
* @param params the params
* @return wechat response entity
*/
public WechatResponseEntity<ObjectNode> find(ParkingServiceQueryParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.PAY_SCORE_PARKING_FIND, params)
.function((wechatPayV3Type, parkingServiceQueryParams) -> {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
queryParams.add("appid", parkingServiceQueryParams.getAppid());
queryParams.add("plate_number", parkingServiceQueryParams.getPlateNumber());
queryParams.add("plate_color", parkingServiceQueryParams.getPlateColor().name());
queryParams.add("openid", parkingServiceQueryParams.getOpenid());
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.queryParams(queryParams)
.build()
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 微信支付分-创建停车入场API
* <p>
* 车辆入场以后,商户调用该接口,创建停车入场信息,需要处理回调逻辑。
* <p>
* 回调通知 {@link WechatPayCallback#payscoreParkingCallback(ResponseSignVerifyParams, Consumer)}
* @param params the params
* @return wechat response entity
*/
public WechatResponseEntity<ObjectNode> parking(ParkingParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.PAY_SCORE_PARKING_PARKINGS, params)
.function((wechatPayV3Type, parkingParams) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
parkingParams.setNotifyUrl(v3.getDomain().concat(parkingParams.getNotifyUrl()));
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, parkingParams);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 微信支付分-扣费受理API
* <p>
* 商户请求扣费受理接口,会完成订单受理。微信支付进行异步扣款,支付完成后,会将订单支付结果发送给商户。
* <p>
* 注意:
* <ul>
* <li>必须确认扣费受理接口的交易状态返回{@code ACCEPTED}才能放行车辆,若未接收到该状态而放行车辆离场,造成的资金损失由商户侧自行承担</li>
* </ul>
* 回调通知 {@link WechatPayCallback#payscoreTransParkingCallback(ResponseSignVerifyParams, Consumer)}
* @param params the params
* @return wechat response entity
*/
public WechatResponseEntity<ObjectNode> transactionsParking(TransParkingParams params) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.PAY_SCORE_PARKING_TRANSACTIONS_PARKINGS, params)
.function((wechatPayV3Type, transParkingParams) -> {
WechatPayProperties.V3 v3 = this.wechatMetaBean().getV3();
transParkingParams.setNotifyUrl(v3.getDomain().concat(transParkingParams.getNotifyUrl()));
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.toUri();
return Post(uri, transParkingParams);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
/**
* 查询订单API.
*
* @param outTradeNo the out trade no
* @return the wechat response entity
*/
public WechatResponseEntity<ObjectNode> queryTransactionByOutTradeNo(String outTradeNo) {
WechatResponseEntity<ObjectNode> wechatResponseEntity = new WechatResponseEntity<>();
this.client().withType(WechatPayV3Type.PAY_SCORE_PARKING_TRANSACTIONS_OUTTRADENO, outTradeNo)
.function((wechatPayV3Type, tradeNo) -> {
URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA))
.build()
.expand(tradeNo)
.toUri();
return Get(uri);
})
.consumer(wechatResponseEntity::convert)
.request();
return wechatResponseEntity;
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2019-2021 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3.model.payscore.parking;
import cn.felord.payment.wechat.enumeration.PlateColor;
import lombok.Data;
import java.time.OffsetDateTime;
/**
* 创建停车入场API回调结果
*
* @author felord.cn
* @since 1.0.13.RELEASE
*/
@Data
public class ParkingCallback {
/**
* 调用接口提交的商户号
*/
private String spMchid;
/**
* 停车入场id
* <p>
* 微信支付分停车服务为商户分配的入场id商户通过入场通知接口获取入场id
*/
private String parkingId;
/**
* 商户侧入场标识id在同一个商户号下唯一
*/
private String outParkingNo;
/**
* 车牌号
* <p>
* 仅包括省份+车牌不包括特殊字符示例值粤B888888
*/
private String plateNumber;
/**
* 车牌颜色
*/
private PlateColor plateColor;
/**
* 入场时间
* <p>
* 格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE
*/
private OffsetDateTime startTime;
/**
* 停车场名称
*/
private String parkingName;
/**
* 免费时长
* <p>
* 单位:秒
*/
private Integer freeDuration;
/**
* 本次入场车牌的服务状态
* <ul>
* <li>NORMAL正常状态可以使用车主服务</li>
* <li>BLOCKED不可用状态暂时不可以使用车主服务</li>
* </ul>
*/
private String parkingState;
/**
* 不可用服务状态描述,返回车牌状态为{@code BLOCKED},会返回该字段,描述具体的原因
* <p>
* 不可用状态:
* <ul>
* <li>PAUSE已暂停车主服务</li>
* <li>OVERDUE已授权签约但欠费不能提供服务商户提示用户进行还款</li>
* <li>REMOVE用户移除车牌导致车牌不可用。请跳转到授权/开通接口</li>
* </ul>
*/
private String blockedStateDescription;
/**
* 状态变更时间
* <p>
* 格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE
*/
private OffsetDateTime stateUpdateTime;
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2019-2021 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3.model.payscore.parking;
import cn.felord.payment.wechat.enumeration.PlateColor;
import lombok.Data;
import java.time.OffsetDateTime;
/**
* 停车场景信息
*
* @author felord.cn
* @since 1.0.13.RELEASE
*/
@Data
public class ParkingInfo {
/**
* 停车入场id必传
* <p>
* 微信支付分停车服务为商户分配的入场id商户通过入场通知接口获取入场id
*/
private String parkingId;
/**
* 车牌号,必传
* <p>
* 仅包括省份+车牌不包括特殊字符示例值粤B888888
*/
private String plateNumber;
/**
* 车牌颜色,必传
*/
private PlateColor plateColor;
/**
* 入场时间,必传
* <p>
* 格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE
*/
private OffsetDateTime startTime;
/**
* 出场时间,必传
* <p>
* 格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE
*/
private OffsetDateTime endTime;
/**
* 停车场名称,必传
*/
private String parkingName;
/**
* 计费时长,必传
* <p>
* 单位:秒
*/
private Integer chargingDuration;
/**
* 停车场设备id必传
*/
private String deviceId;
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2019-2021 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3.model.payscore.parking;
import cn.felord.payment.wechat.enumeration.PlateColor;
import lombok.Data;
import java.time.OffsetDateTime;
/**
* 创建停车入场API参数
*
* @author felord.cn
* @since 1.0.13.RELEASE
*/
@Data
public class ParkingParams {
/**
* 商户入场id必传
* <p>
* 商户侧入场标识id在同一个商户号下唯一
*/
private String outParkingNo;
/**
* 车牌号,必传
* <p>
* 仅包括省份+车牌不包括特殊字符示例值粤B888888
*/
private String plateNumber;
/**
* 车牌颜色,必传
*/
private PlateColor plateColor;
/**
* 回调通知url必传
* <p>
* 接受入场状态变更回调通知的url注意回调url只接受https
*/
private String notifyUrl;
/**
* 入场时间,必传
* <p>
* 格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE
*/
private OffsetDateTime startTime;
/**
* 停车场名称,必传
*/
private String parkingName;
/**
* 免费时长,必传
* <p>
* 单位:秒
*/
private Integer freeDuration;
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2019-2021 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3.model.payscore.parking;
import cn.felord.payment.wechat.enumeration.PlateColor;
import lombok.Data;
/**
* 查询车牌服务开通信息API参数
*
* @author felord.cn
* @since 1.0.13.RELEASE
*/
@Data
public class ParkingServiceQueryParams {
/**
* 应用ID必传
* <p>
* appid是商户在微信申请公众号或移动应用成功后分配的账号ID登录平台为mp.weixin.qq.com或open.weixin.qq.com
*/
private String appid;
/**
* 车牌号,必传
* <p>
* 仅包括省份+车牌不包括特殊字符示例值粤B888888
*/
private String plateNumber;
/**
* 车牌颜色,必传
*/
private PlateColor plateColor;
/**
* 用户标识,必传
* <p>
* 用户在商户对应{@code appid}下的唯一标识
*/
private String openid;
}

View File

@@ -0,0 +1,212 @@
/*
* Copyright 2019-2021 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3.model.payscore.parking;
import cn.felord.payment.wechat.v3.model.Payer;
import lombok.Data;
import java.time.OffsetDateTime;
/**
* 订单支付结果通知API回调结果
*
* @author felord.cn
* @since 1.0.13.RELEASE
*/
@Data
public class TransParkingCallback {
/**
* 调用接口提交的应用ID
*/
private String appid;
/**
* 调用接口提交的商户号
*/
private String spMchid;
/**
* 调用接口提交的商户服务订单号
*/
private String outTradeNo;
/**
* 微信支付系统生成的订单号。
*/
private String transactionId;
/**
* 商户自定义字段,用户交易账单中对扣费服务的描述。
*/
private String description;
/**
* 订单成功创建时返回
*/
private OffsetDateTime createTime;
/**
* 交易状态
*/
private ParkingTradeState tradeState;
/**
* 交易状态描述
*/
private String tradeStateDescription;
/**
* 支付完成时间
*/
private OffsetDateTime successTime;
/**
* 付款银行类型,参见<a target= "_blank" href= "https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml#part-4">开户银行对照表</a>
*/
private String bankType;
/**
* 附加数据在查询API和支付通知中原样返回可作为自定义参数使用实际情况下只有支付完成状态才会返回该字段。
*/
private String attach;
/**
* 用户是否已还款
* <p>
* 枚举值:
* <ul>
* <li>Y用户已还款</li>
* <li>N用户未还款</li>
* </ul>
* <p>
* 注意使用此字段前需先确认bank_type字段值为BPA以及 trade_state字段值为SUCCESS。
*/
private String userRepaid;
/**
* 交易场景值目前支持PARKING车场停车场景
*/
private String tradeScene;
/**
* trade_scene为PARKING时返回停车场景信息
*/
private ParkingInfo parkingInfo;
/**
* 支付者信息
*/
private Payer payer;
/**
* 订单金额信息
*/
private Amount amount;
/**
* 优惠功能信息
*/
private PromotionDetail promotionDetail;
/**
* 交易状态
*/
public enum ParkingTradeState {
/**
* 支付成功
*/
SUCCESS,
/**
* 已接收,等待扣款
*/
ACCEPT,
/**
* 支付失败(其他原因,如银行返回失败)
*/
PAY_FAIL,
/**
* 转入退款
*/
REFUND
}
/**
* 订单金额信息
*/
@Data
public static class Amount {
/**
* 订单总金额,单位为分,只能为整数
*/
private Integer total;
/**
* 订单折扣
*/
private Integer discountTotal;
/**
* 用户实际支付金额,单位为分,只能为整数
*/
private Integer payerTotal;
/**
* 符合ISO 4217标准的三位字母代码目前只支持人民币CNY
*/
private String currency;
}
/**
* 优惠功能信息
*/
@Data
public static class PromotionDetail {
/**
* 立减优惠id
*/
private String promotionId;
/**
* 优惠券ID
*/
private String couponId;
/**
* 优惠名称
*/
private String name;
/**
* 优惠范围
*/
private String scope;
/**
* 优惠类型
* <p>
* 枚举值:
* <ul>
* <li>CASH充值型代金券</li>
* <li>NOCASH免充值型代金券</li>
* </ul>
*/
private String type;
/**
* 优惠券面额
*/
private Integer amount;
/**
* 活动ID
*/
private String activityId;
/**
* 特指由微信支付商户平台创建的优惠,出资金额等于本项优惠总金额,单位为分。
*/
private Integer wechatpayContribute;
/**
* 特指商户自己创建的优惠,出资金额等于本项优惠总金额,单位为分。
*/
private Integer merchantContribute;
/**
* 其他出资方出资金额,单位为分。
*/
private Integer otherContribute;
/**
* 优惠币种,境内商户号仅支持人民币。
*/
private String currency;
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2019-2021 felord.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* Website:
* https://felord.cn
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.felord.payment.wechat.v3.model.payscore.parking;
import cn.felord.payment.wechat.v3.model.Amount;
import lombok.Data;
/**
* 扣费受理API参数
*
* @author felord.cn
* @since 1.0.13.RELEASE
*/
@Data
public class TransParkingParams {
/**
* 应用ID必传
* <p>
* appid是商户在微信申请公众号或移动应用成功后分配的账号ID登录平台为mp.weixin.qq.com或open.weixin.qq.com
*/
private String appid;
/**
* 服务描述,必传
* <p>
* 商户自定义字段,用于交易账单中对扣费服务的描述。
*/
private String description;
/**
* 附加数据,非必传
* <p>
* 附加数据在查询API和支付通知中原样返回可作为自定义参数使用实际情况下只有支付完成状态才会返回该字段。
*/
private String attach;
/**
* 商户订单号,必传
* <p>
* 商户系统内部订单号,只能是数字、大小写字母,且在同一个商户号下唯一
*/
private String outTradeNo;
/**
* 交易场景,必传
* <p>
* 目前支持 {@code PARKING} 车场停车场景
*/
private String tradeScene;
/**
* 订单优惠标记,非必传
* <p>
* 代金券或立减优惠功能的参数,说明详见 <a href="https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_7&index=3">代金券或立减优惠</a>
*/
private String goodsTag;
/**
* 回调通知url必传
*/
private String notifyUrl;
/**
* 分账标识,非必传,不传则不分账
* <p>
* 枚举值:
* <ul>
* <li>Y需要分账</li>
* <li>N不分账</li>
* </ul>
* <p>
* 字母要求大写,不传默认不分账,分账详细说明见<a href="http://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=26_1">直连分账API</a>、<a href="http://pay.weixin.qq.com/wiki/doc/api/allocation_sl.php?chapter=24_1&index=1">服务商分账API</a>文档
*/
private String profitSharing;
/**
* 订单金额,必传
*/
private Amount amount;
/**
* 停车场景信息,非必传
* <p>
* 当交易场景为{@code PARKING}时,需要在该字段添加停车场景信息
*/
private ParkingInfo parkingInfo;
}