| | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.talentcard.server.business.DatabaseRows; |
| | | import com.talentcard.server.business.order.OrderFundBoundaryService; |
| | | import com.talentcard.server.business.payment.HuifuPaymentPayload.TransStatus; |
| | | import com.talentcard.server.business.payment.PaymentSettlementService.ProviderPaymentFact; |
| | | import com.talentcard.server.business.payment.PaymentSettlementService.SettlementOutcome; |
| | | import com.talentcard.server.business.payment.huifu.HuifuPayload; |
| | | import com.talentcard.server.business.payment.huifu.HuifuPayload.TransStatus; |
| | | import com.talentcard.server.business.payment.huifu.HuifuSignatureService; |
| | | import com.talentcard.server.common.BusinessException; |
| | | import com.talentcard.server.common.ErrorCode; |
| | |
| | | throw new BusinessException(ErrorCode.FORBIDDEN, "汇付回调验签失败"); |
| | | } |
| | | Map<String, Object> envelope = parse(responseData); |
| | | Map<String, Object> data = HuifuPaymentPayload.businessData(envelope); |
| | | String requestNo = HuifuPaymentPayload.firstNonBlank(HuifuPaymentPayload.value(data, "req_seq_id"), HuifuPaymentPayload.value(envelope, "req_seq_id")); |
| | | Map<String, Object> data = HuifuPayload.businessData(envelope); |
| | | String requestNo = HuifuPayload.firstNonBlank(HuifuPayload.value(data, "req_seq_id"), HuifuPayload.value(envelope, "req_seq_id")); |
| | | if (requestNo.isBlank()) throw new BusinessException(ErrorCode.BAD_REQUEST, "汇付回调缺少请求流水号"); |
| | | |
| | | String payloadHash = sha256(responseData); |
| | |
| | | return acknowledgement(requestNo); |
| | | } |
| | | |
| | | String transStatus = HuifuPaymentPayload.value(data, "trans_stat", "transStat"); |
| | | if (HuifuPaymentPayload.status(transStatus) == TransStatus.UNKNOWN) { |
| | | String transStatus = HuifuPayload.value(data, "trans_stat", "transStat"); |
| | | if (HuifuPayload.status(transStatus) == TransStatus.UNKNOWN) { |
| | | updateEvent(requestNo, "UNKNOWN_STATUS"); |
| | | return acknowledgement(requestNo); |
| | | } |
| | |
| | | return acknowledgement(requestNo); |
| | | } |
| | | |
| | | if (!HuifuPaymentPayload.paid(transStatus, HuifuPaymentPayload.code(data))) { |
| | | if (!HuifuPayload.paid(transStatus, HuifuPayload.code(data))) { |
| | | // The provider did not confirm money: keep the payment pending for the query path. |
| | | jdbc.update(""" |
| | | update payment_transaction |
| | | set provider_response_code = ?, provider_response_message = ? |
| | | where provider = ? and payment_no = ? and status in ('CREATED', 'CREATE_FAILED', 'PREPAY_CREATED', 'CREATE_UNKNOWN') |
| | | """, HuifuPaymentPayload.code(data), HuifuPaymentPayload.message(data), PROVIDER, requestNo); |
| | | """, HuifuPayload.code(data), HuifuPayload.message(data), PROVIDER, requestNo); |
| | | updateEvent(requestNo, "PENDING_QUERY"); |
| | | return acknowledgement(requestNo); |
| | | } |
| | | |
| | | SettlementOutcome outcome = settlementService.settle(new ProviderPaymentFact( |
| | | requestNo, |
| | | HuifuPaymentPayload.value(data, "huifu_id", "huifuId"), |
| | | HuifuPaymentPayload.amountInCent(HuifuPaymentPayload.value(data, "trans_amt", "transAmt")), |
| | | HuifuPayload.value(data, "huifu_id", "huifuId"), |
| | | HuifuPayload.amountInCent(HuifuPayload.value(data, "trans_amt", "transAmt")), |
| | | providerTransactionNo(data), |
| | | HuifuPaymentPayload.code(data), |
| | | HuifuPaymentPayload.message(data), |
| | | HuifuPayload.code(data), |
| | | HuifuPayload.message(data), |
| | | "CALLBACK")); |
| | | updateEvent(requestNo, eventStatus(outcome)); |
| | | return acknowledgement(requestNo); |
| | |
| | | |
| | | Map<String, Object> refund = refunds.get(0); |
| | | long orderId = ((Number) refund.get("orderId")).longValue(); |
| | | String transStatus = HuifuPaymentPayload.value(data, "trans_stat", "transStat"); |
| | | String code = HuifuPaymentPayload.code(data); |
| | | if (HuifuPaymentPayload.paid(transStatus, code)) { |
| | | String transStatus = HuifuPayload.value(data, "trans_stat", "transStat"); |
| | | String code = HuifuPayload.code(data); |
| | | if (HuifuPayload.paid(transStatus, code)) { |
| | | jdbc.update(""" |
| | | update order_refund |
| | | set refund_status = 2, provider = 'HUIFU', provider_refund_no = ?, |
| | | provider_response_code = ?, provider_response_message = ?, refund_time = coalesce(refund_time, now()) |
| | | where id = ? and refund_status = 1 |
| | | """, providerTransactionNo(data), code, HuifuPaymentPayload.message(data), refund.get("id")); |
| | | """, providerTransactionNo(data), code, HuifuPayload.message(data), refund.get("id")); |
| | | // 通道确认退款成功是最终事实:订单级退款状态无条件收敛为已退款。 |
| | | orderFundBoundary.markRefunded(orderId); |
| | | jdbc.update(""" |
| | |
| | | and o.pay_amount <= (select coalesce(sum(r.refund_amount), 0) from order_refund r where r.order_id = o.id and r.refund_status = 2 and r.deleted = 0) |
| | | """, refund.get("orderId")); |
| | | updateEvent(refundNo, "PROCESSED"); |
| | | } else if (HuifuPaymentPayload.terminalFailure(transStatus, code)) { |
| | | } else if (HuifuPayload.terminalFailure(transStatus, code)) { |
| | | int failed = jdbc.update(""" |
| | | update order_refund |
| | | set provider_response_code = ?, provider_response_message = ?, refund_status = 3 |
| | | where id = ? and refund_status = 1 |
| | | """, code, HuifuPaymentPayload.message(data), refund.get("id")); |
| | | """, code, HuifuPayload.message(data), refund.get("id")); |
| | | // 只有本事务真的把退款置为失败,才把订单退回未退款状态;否则会覆盖并发的退款成功。 |
| | | if (failed == 1) orderFundBoundary.markRefundFailed(orderId); |
| | | updateEvent(refundNo, "REFUND_FAILED"); |
| | |
| | | update order_refund |
| | | set provider_response_code = ?, provider_response_message = ? |
| | | where id = ? and refund_status = 1 |
| | | """, code, HuifuPaymentPayload.message(data), refund.get("id")); |
| | | """, code, HuifuPayload.message(data), refund.get("id")); |
| | | updateEvent(refundNo, "PENDING_QUERY"); |
| | | } |
| | | return true; |
| | |
| | | """, PROVIDER, requestNo); |
| | | if (rows.isEmpty()) return false; |
| | | Map<String, Object> event = rows.get(0); |
| | | return payloadHash.equals(HuifuPaymentPayload.text(event.get("payloadSha256"))) |
| | | && TERMINAL_EVENT_STATUSES.contains(HuifuPaymentPayload.text(event.get("processStatus"))); |
| | | return payloadHash.equals(HuifuPayload.text(event.get("payloadSha256"))) |
| | | && TERMINAL_EVENT_STATUSES.contains(HuifuPayload.text(event.get("processStatus"))); |
| | | } |
| | | |
| | | private void upsertEvent(String requestNo, String payloadHash, String status) { |
| | |
| | | } |
| | | |
| | | private String providerTransactionNo(Map<String, Object> data) { |
| | | return HuifuPaymentPayload.value(data, "hf_seq_id", "bank_order_no", "hfSeqId"); |
| | | return HuifuPayload.value(data, "hf_seq_id", "bank_order_no", "hfSeqId"); |
| | | } |
| | | |
| | | private String acknowledgement(String requestNo) { |