Вслед за предыдущей статьей об интерфейсе отмены заказа и интерфейсе запроса заказа, эта статья посвящена процессу подачи заявки на возврат. Эта статья слишком длинная, и я буду публиковать ее в несколько этапов (доступен исходный код проекта, мини-программа и ПК).
Ранее мы обновили начало платежей WeChat, безопасность платежей WeChat и практическую базовую структуру WeChat. Это обновление касается фактической конструкции интерфейса ПК для платежей WeChat. Практическая глава разделена на несколько глав, потому что объем кода действительно велик. немного большой.
В этом проекте используется стек технологий
Серверная часть: SpringBoot3.1.x, Mysql8.0, MybatisPlus.
Интерфейс: Vue3, Vite, ElementPlus.
Мини программы: Uniapp, Uview
Просмотр демо-адреса ВЕБ-сторона Мини программа
Возврат заказа означает, что после покупки товаров или услуг по какой-либо причине потребитель решает отменить заказ или продавец не может предоставить обещанные товары или услуги, что запускает процесс возврата. Возвратный платеж обычно относится к операции продавца по возврату потребителю суммы, ранее уплаченной потребителем. Это может быть решение, достигнутое между потребителями и продавцами из-за дефектных товаров, неудовлетворительного обслуживания, ошибок заказа или других причин, обеспечивающих защиту прав и интересов потребителей.
Подать заявку на возврат Есть много сцен средств,Вот некоторые распространенные ситуации:
Вышеуказанное является профессиональным ответом GPT3.5.
думать Требуется в нашей программеизшагПервоначальное формирование
Мы все знаем, что после успешного платежа WeChat сообщит нам, что платеж прошел успешно, и будет создана запись транзакции. Если мы нажмем на нее, мы увидим номер заказа транзакции.
Хорошо, давайте проверим, будет ли в документе указан этот номер.
Очевидно, мы это получим~ Затем мы сохраним его, когда придет время, и оценим его в комментариях пользователя. Все будет закончено~.
Если возврат средств требуется покупателю или продавцу в течение одного года после совершения транзакции, продавец может вернуть сумму платежа покупателю через интерфейс возврата. WeChat Pay выплатит сумму после получения запроса на возврат и его успешной проверки. Верните его на счет покупателя по первоначальному маршруту.
1. Заказы со временем транзакции более одного года не могут быть предъявлены к возврату.
2. Возврат через WeChat Pay поддерживает несколько возвратов за одну транзакцию (не более 50 раз). Для многократного возврата вам необходимо указать номер заказа продавца исходного платежного поручения и установить разные номера заказов на возврат. Общая сумма, запрошенная для возврата, не может превышать сумму заказа. Если вы отправляете заявку повторно после того, как возврат средств не был выполнен, не меняйте номер заказа на возврат. Используйте исходный номер заказа на возврат, предоставленный продавцом.
3. Ограничение частоты ошибок или недействительных запросов: 6qps, то есть не более 6 ненормальных или ошибочных запросов на возврат средств в секунду.
4. Количество частичных возвратов по каждому платежному поручению не может превышать 50 раз.
5. Если для одного и того же пользователя производится несколько возвратов средств, рекомендуется возвращать их разными пакетами, чтобы избежать одновременных возвратов средств, приводящих к сбоям в возврате средств.
6. Возврат интерфейса заявки на возврат представляет собой только статус принятия бизнеса. Чтобы определить, был ли возврат успешным, вам необходимо получить результат через интерфейс запроса на возврат.
7. Ограничение частоты запросов на возврат средств за заказы, сделанные месяц назад, составляет: 5000/мин.
8. Несколько запросов на возврат средств по одному и тому же заказу должны быть разделены 1 минутой.
Статус возврата меняется следующим образом:
Имя параметра | переменная | Ограничение длины типа | Необходимый | описывать |
---|---|---|---|---|
Номер платежного поручения WeChat | transaction_id | string1, 32 | Выберите один | Номер заказа WeChat, соответствующий исходной платежной транзакции тела. Пример значения: 1217752501201407033233368018. |
Номер заказа продавца | out_trade_no | string6, 32 | Выберите один | Номер заказа продавца, соответствующий исходной платежной транзакции body. Пример значения: 1217752501201407033233368018. |
Номер заказа продавца на возврат средств | out_refund_no | string1, 64 | да | Номер заказа на возврат в основной системе продавца уникален в системе продавца и может состоять только из цифр, заглавных и строчных букв _-|*@. Несколько запросов на один и тот же номер заказа на возврат допускают только один возврат. Пример значения: 1217752501201407033233368018. |
Причина возврата | reason | string1, 64 | нет | Заполнять не обязательно |
Информация о сумме | amount | object | да | bodyЗаказ Информация о сумме |
Сумма возврата | refund | int | да | Сумма возврата в центах может быть только целым числом и не может превышать первоначальную сумму оплаты заказа. Пример значения: 888 |
Исходная сумма заказа | total | int | да | Общая сумма заказа исходной платежной транзакции в центах может быть только целым числом. Пример значения: 888 |
Измените WechatNativeController, чтобы написать интерфейс приложения возврата средств.
/**
* Подать заявку на возврат средств
* @param заказ Нет номера заказа
* @param refundsNo Номер заказа на возврат (Номер транзакции заказа)
* @param reason Причина возврата
*/
@PostMapping("/refunds/{orderNo}/{refundsNo}/{reason}")
public R refunds(@PathVariable String orderNo, @PathVariable String refundsNo, @PathVariable String reason) {
log.info("Подать заявку на возврат средств");
wxPayService.refund(orderNo, reason, refundsNo);
return R.ok();
}
Измените wxPayService, чтобы создать метод возврата.
/**
* Подать заявку на возврат средств
*
* @param orderNo Номер заказа
* @param reason Причина возврата
* @param refundsNo Номер заказа на возврат
*/
@SneakyThrows
public void refund(String orderNo, String reason, String refundsNo) {
// ............
}
Как упоминалось ранее, вам необходимо проверить наличие и статус заказа, чтобы убедиться, что платеж прошел успешно.
log.info("Проверка начинается");
PaymentInfo paymentInfo = paymentInfoService.lambdaQuery().eq(PaymentInfo::getOrderNo, orderNo)
.eq(PaymentInfo::getTradeState, WxTradeState.SUCCESS.getType()).one();
if (null == paymentInfo) {
throw new RuntimeException("Заказ не найден, повторите попытку позже!");
}
При проверке правильности транзакции «Номер заказаданет», введенной клиентом, я буду судить по последним четырем цифрам.
// Собственный приказ судьи Данетды
String transactionNo = paymentInfo.getTransactionId().substring(paymentInfo.getTransactionId().length() - 4);
if (!transactionNo.equals(refundsNo)) {
throw new RuntimeException("Возможно, это не ваш заказ. Пожалуйста, подтвердите транзакцию в уведомлении WeChat после успешной оплаты" заказывайте последние четыре!");
}
После того, как мы это сделали, нам еще нужно сделать еще кое-что.,Разве нам не нужно записать такую важную ссылку на возврат денег?, я просто разделил их и не заработал денег~
Тогда давайте проверим таблицу записей возврата, упомянутую в предыдущей статье.,Некоторые студенты могут растеряться и поехать туда на прямом автобусе.Глава 3. Создание практической базовой основы для платежей WeChat в серии с нулясредиизсоздавать Упомянутая трехслойная структура
CREATE TABLE `t_refund_info` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'идентификатор платежного поручения',
`order_no` varchar(50) DEFAULT NULL COMMENT 'Номер заказа продавца',
`refund_no` varchar(50) DEFAULT NULL COMMENT 'Номер заказа на возврат средств продавцу',
`refund_id` varchar(50) DEFAULT NULL COMMENT 'Номер платежной системы заказа на возврат',`total_fee` int(11) DEFAULT NULL COMMENT 'Исходная сумма заказа(точка)',`refund` int(11) DEFAULT NULL COMMENT 'Сумма возврата(точка)', `reason` varchar(50) DEFAULT NULL COMMENT 'Причина возврата',
`refund_status` varchar(10) DEFAULT NULL COMMENT «Статус возврата»,
`content_return` text COMMENT 'Подать заявку на возврат средства возвращают параметры',
`content_notify` text COMMENT 'Параметры уведомления о результате возврата',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT 'создаватьвремя', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'время обновления',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
Как только это будет сделано, мы создадим запись о заказе на возврат и сохраним ее в базе данных.
Измените returnInfoService, чтобы создать метод createRefundByOrderNo.
log.info("создавать запись заказа на возврат");
//Заказ на возврат средств по номеру создателя заказа
RefundInfo refundsInfo = refundInfoService.createRefundByOrderNo(orderNo, reason);
log.info("Вызов API возврата");
Обработка логики создания заказа на возврат средств
// По номеру заказать Создать заказ на возврат средств
RefundInfo refundInfo = new RefundInfo();
returnInfo.setOrderNo(orderNo);//Номер заказа
returnInfo.setRefundNo(OrderNoUtils.getRefundNo());//номер заказа на возврат
refundInfo.setTotalFee();//Исходная сумма заказа(точка) refundInfo.setRefund();//Сумма возврата(точка) refundInfo.setReason(reason);//Причина возврата
Создайте сущность и введите параметры. Нам все еще не хватает суммы заказа. Мы передали параметр номер заказа Итак, давайте подумаем, где это сделать?
Позвоните в службу заказов, чтобы узнать сумму💰
Служба ввода заказов IOC
/**
* Заказать информационную услугу
*/
private final OrderInfoService orderInfoService;
Инициировать запрос информации о заказе интерфейса
// По номеру заказать Получить информацию о заказе
OrderInfo orderInfo = orderInfoService.lambdaQuery().eq(OrderInfo::getOrderNo, orderNo).one();
Наконец добавлено в базу данных
/**
* создавать Возвращать деньги Заказ По номеру заказа
*
* @param заказ Нет номера заказа
* @param reason Причина возврата
* @return {@link RefundInfo}
*/
public RefundInfo createRefundByOrderNo(String orderNo, String reason) {
// По номеру заказать Получить информацию о заказе
OrderInfo orderInfo = orderInfoService.lambdaQuery().eq(OrderInfo::getOrderNo, orderNo).one();
// По номеру заказать Создать заказ на возврат средств
RefundInfo refundInfo = new RefundInfo();
returnInfo.setOrderNo(orderNo);//Номер заказа
returnInfo.setRefundNo(OrderNoUtils.getRefundNo());//номер заказа на возврат
refundInfo.setTotalFee(orderInfo.getTotalFee());//Исходная сумма заказа(точка) refundInfo.setRefund(orderInfo.getTotalFee());//Сумма возврата(точка) refundInfo.setReason(reason);//Причина возврата
//Сохраняем заказ на возврат
baseMapper.insert(refundInfo);
return refundInfo;
}
URL-адрес запроса:https://api.mch.weixin.qq.com/v3/refund/domestic/refunds
Метод запроса:POST
Параметры запроса:
Имя параметра | переменная | Ограничение длины типа | Необходимый | описывать |
---|---|---|---|---|
Номер платежного поручения WeChat | transaction_id | string1, 32 | Выберите один | Номер заказа WeChat, соответствующий исходной платежной транзакции тела. Пример значения: 1217752501201407033233368018. |
Номер заказа продавца | out_trade_no | string6, 32 | Выберите один | Номер заказа продавца, соответствующий исходной платежной транзакции body. Пример значения: 1217752501201407033233368018. |
Номер заказа продавца на возврат средств | out_refund_no | string1, 64 | да | Номер заказа на возврат в основной системе продавца уникален в системе продавца и может состоять только из цифр, заглавных и строчных букв _-|*@. Несколько запросов на один и тот же номер заказа на возврат допускают только один возврат. Пример значения: 1217752501201407033233368018. |
Причина возврата | reason | string1, 64 | нет | Заполнять не обязательно |
Информация о сумме | amount | object | да | bodyЗаказ Информация о сумме |
Сумма возврата | refund | int | да | Сумма возврата в центах может быть только целым числом и не может превышать первоначальную сумму оплаты заказа. Пример значения: 888 |
Исходная сумма заказа | total | int | да | Общая сумма заказа исходной платежной транзакции в центах может быть только целым числом. Пример значения: 888 |
WxApiType запрашивает перечисление API. Не забывайте о содержании базовой конструкции проекта.
// Вызов API единого заказа
String url = wxPayConfig.getDomain().concat(WxApiType.DOMESTIC_REFUNDS.getType());
HttpPost httpPost = new HttpPost(url);
// Параметры тела запроса
Map<String, Object> paramsMap = new HashMap<>();
paramsMap.put("out_trade_no", orderNo);//номер заказа
paramsMap.put("out_refund_no", refundsInfo.getRefundNo());//номер заказа на возврат
paramsMap.put("reason", reason);//Причина возврата
paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxNotifyType.REFUND_NOTIFY.getType()));//Уведомление о возвратеадрес Map<String, Object> amountMap = new HashMap<>();
amountMap.put("refund", refundsInfo.getRefund());// Сумма возврата
amountMap.put("total", refundsInfo.getTotalFee());// Исходная сумма заказа
amountMap.put("currency", "CNY");// Возврат валюты
paramsMap.put("amount", amountMap);
//Преобразуем параметры в строку json
String jsonParams = JSONUtil.toJsonStr(paramsMap);
log.info("Параметры запроса ===> {}", jsonParams);
StringEntity entity = new StringEntity(jsonParams, "utf-8");
entity.setContentType("application/json");//Устанавливаем формат сообщения запроса
httpPost.setEntity(entity);//Помещаем сообщение запроса в объект запроса
httpPost.setHeader("Accept", "application/json");//Установим формат ответного сообщения
После сборки выполнить запрос
// Завершите подпись и выполните запрос, а также завершите проверку подписи.
try (CloseableHttpResponse response = wxPayClient.execute(httpPost)) {
//Разбираем результаты ответа
JSONObject resultMap = buildBodyParams(response, JSONObject.class);
log.info("Результат возврата возврата ===> {}", resultMap);
// Обновить статус заказа
orderInfoService.lambdaUpdate().eq(OrderInfo::getOrderNo, orderNo).set(OrderInfo::getOrderStatus, OrderStatus.REFUND_PROCESSING.getType()).update();
// Обновить заказ на возврат средств
refundInfoService.updateRefund(resultMap);
}
Исправлять refundInfoService
создавать updateRefund
Способ сохранить важную информацию об этом ответе на возврат средств.
Параметры возврата возврата:
Ответ возвращен для возврата
НетдаВозврат обратного звонка
изпараметры ответаДля начала поговорим о выпуске серийного номера три.
Может Видеть Подать заявку на возврат средствинтерфейс возвращаетизполе статуса ответада
status
Может Видеть
Возврат обратного звонка
интерфейс возвращаетизполе статуса ответадаrefund_status
/**
* Обновить заказ на возврат средств
*
* @param resultMap Результат ответа на возврат
*/
public void updateRefund(JSONObject resultMap) {
// Заказ на возврат по номеру заказа на возврат Исправлять
QueryWrapper<RefundInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("refund_no", resultMap.getStr("out_refund_no"));
// Установите поля, которые вы хотите редактировать
RefundInfo refundInfo = new RefundInfo();
returnInfo.setRefundId(resultMap.getStr("refund_id"));//Номер платежа WeChat заказа на возврат
// Запросить возврат средств и Подать заявку на возврат средствсерединаиз Возвращаемые параметры
if (resultMap.get("status") != null) {
RefundInfo.setRefundStatus(resultMap.getStr("status"));//Статус возврата
returnInfo.setContentReturn(resultMap.toString());//сохраняем все результаты ответа в поле содержимого базы данных
}
// Параметры обратного вызова в обратном вызове возврата
if (resultMap.get("refund_status") != null) {
RefundInfo.setRefundStatus(resultMap.getStr("refund_status"));//Статус возврата
returnInfo.setContentNotify(resultMap.toString());//сохраняем все результаты ответа в поле содержимого базы данных
}
//Обновить заказ на возврат средств
baseMapper.update(refundInfo, queryWrapper);
}
Откройте скорлупу арахиса или другие продукты, чтобы получить заказы на обновление обратного вызова об успешном платеже.
копироватьcodeUrl
параметр Открытькорм https://cli.im/url
Сканируйте QR-код для оплаты!
После успешной оплаты перейдите к уведомлению о платеже WeChat, чтобы проверить номер нашего заказа на транзакцию.
Объяснение интерфейса в спокойном стиле
/api/wx-pay/native/refunds/{orderNo}/{refundsNo}/{reason}
заказ Нет номера заказа
Возврат Нет Номер заказа транзакции. В настоящее время в нашей программе необходимы только последние четыре цифры.
Причина Причина возврата (необязательно)
Это еще не конец ~ Ранее мы упоминали об обратном вызове возврата. На данный момент возврат средств поступил на счет пользователя, а данные заказа, соответствующие нашей собственной базе данных, еще не обновлены.
После изменения статуса возврата WeChat отправит продавцу соответствующие результаты возврата.
В фоновом режиме уведомления взаимодействия,Если ответ, полученный WeChat, не является успешным или истекло время ожидания,WeChat считает, что уведомление не удалось отправить,WeChat будет регулярно повторно инициировать уведомления с помощью определенных стратегий.,Максимизируйте вероятность успеха уведомлений,Однако WeChat не гарантирует, что уведомление в конечном итоге будет успешным.
• Одно и то же уведомление может быть отправлено в торговую систему несколько раз. Торговые системы должны иметь возможность правильно обрабатывать повторяющиеся уведомления. рекомендоватьизупражнятьсяда,Когда торговая система получает уведомление и обрабатывает его,Сначала проверьте статус соответствующих бизнес-данных.,И определить, что уведомление данет обработано. если не обработано,затем обработать еще раз, если он был обработан;,Результат будет возвращен как успех. Перед проверкой статуса и обработкой бизнес-данных,Используйте блокировки данных для управления параллелизмом,Чтобы избежать путаницы данных, вызванной повторным входом функции.
• Если обратный вызов со стороны WeChat не получен после всех частот уведомлений. Продавцам следует вызвать интерфейс запроса заказа, чтобы подтвердить статус заказа.
Специальное напоминание:Пара торговых систем ВВключить уведомления о результатахиз Содержимое должно быть подписано для проверки.,И убедитесь, что информация в уведомлении соответствует информации на стороне продавца.,Предотвратите «фальшивые уведомления» об утечке данных,причинение финансовых потерь.
Метод запроса:POST
URL-адрес запроса:ссылкадапроходить Подать заявку на возврат средств Обозначение интерфейсаизnotify_url,Должен быть протокол https. Если ссылка недоступна,Продавцы не смогут получать уведомления WeChat. URL-адрес уведомления должен быть URL-адресом прямого доступа.,Нет能携带параметр。Пример:“https://pay.weixin.qq.com/wxpay/pay.action”
Исходные слова приведенного выше официального документа просто заключаются в том, что да — это то же самое, что обратный вызов для успешной оплаты.
Исправлять WechatNativeController
НовыйrefundsNotify
метод обратного вызова
⚠️Та же логика, что и уведомление о платеже, только объекты, обрабатываемые да, отличаются. Вы можете наглядно понять, непосредственно введя код.
Студенты начали вводить код
ИсправлятьwxPayService
создавать processRefund
метод Уведомление о возврате Обработка данных заказа на возврат средств
Логика здесь такая же, как и при обратном вызове об успешном платеже. Если вы забыли, пройдите обучение. Глава 5. Игра с серией платежей WeChat с нуля: создание интерфейса обратного вызова WeChat для платежей на стороне ПК
Студенты, пожалуйста, введите код вручную~
Действия такие же, как и в приведенном выше тесте.
⚠️ Если через 3 секунды Возврат обратного звонка Если он не пришел, проверьте настройки.из Возврат обратного звонкаадресданетправильный
Этот вопрос исчерпан. Увидимся в следующий раз👋~. Следуйте за мной, чтобы не потеряться. Если эта статья вам полезна или у вас есть какие-либо вопросы, оставьте сообщение в разделе комментариев, я обычно отвечу. Я вижу это. Пожалуйста, поставьте лайк и поддержите~ 💗
【Идеи выбора темы】
«Технологии приходят из жизни» Зачем писать статью о таком проекте, как WeChat Pay, потому что я увидел, что статьи на рынке не полны, содержат подробности, не на просторечии и не содержат подтверждающих демо-версий!!! Мой опыт игры с WeChat Pay с нуля родился La~ С разными реализациями на ПК и Uniapp.
【Написание плана】
I. Предисловие
А. Выражайте то, что я пишу каждый раз, через Предисловие.
II. Реализация интерфейса возврата заказа.
А. Соберите людей для анализа его логики.
III. Перейдем к делу.
А. Соберите предыдущие теоретические знания для написания функционального кода.
IV. Тестирование.
A. Пошаговое устранение ошибок при написании данета с помощью тестового варианта использования