jdopen.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import simplejson as json
  6. from django.conf import settings
  7. from typing import TYPE_CHECKING, Dict
  8. from apps.web.common.transaction.refund import RefundNotifier, RefundPuller
  9. if TYPE_CHECKING:
  10. from django.core.handlers.wsgi import WSGIRequest
  11. from apps.web.core.payment import PaymentGatewayT
  12. from apps.web.common.transaction.pay import RefundRecordT, RechargeRecordT
  13. logger = logging.getLogger(__name__)
  14. class JDOpenRefundNotifier(RefundNotifier):
  15. def parse_request(self, request): # type:(WSGIRequest) -> dict
  16. _head = {
  17. 'accessKey': request.META['HTTP_ACCESSKEY'],
  18. 'version': request.META['HTTP_VERSION'],
  19. 'timestamp': request.META['HTTP_TIMESTAMP'],
  20. 'token': request.META['HTTP_TOKEN']
  21. }
  22. _body = json.loads(request.body) # type: Dict
  23. logger.debug('received jdopen refund notify: body = {}; heads = {}'.format(_body, _head))
  24. return {
  25. 'body': _body,
  26. 'head': _head
  27. }
  28. def verify_payload(self, payload): # type:(dict) -> bool
  29. return True
  30. def handle_refund_order(self, refundOrder, post_pay): # type:(RefundRecordT, callable) -> None
  31. if not self.payload:
  32. refundOrder.fail(errorDesc = u'退款通知参数错误')
  33. return
  34. if self.payload["body"]["refundStatus"] != "SUCCESS":
  35. refundOrder.fail(
  36. errorCode = self.payload["body"].get('failCode', ''),
  37. errorDesc = self.payload["body"].get('failReason', ''))
  38. return
  39. import arrow
  40. refund_finished_time = arrow.get(
  41. self.payload["body"]["refundDate"], 'YYYY-MM-DD HH:mm',
  42. tzinfo = settings.TIME_ZONE).naive # type: datetime.datetime
  43. matched = refundOrder.succeed(
  44. tradeRefundNo = str(self.payload["body"].get('bankRequestNum', '')), finishedTime = refund_finished_time)
  45. if not matched:
  46. return
  47. return post_pay(refundOrder, refund_finished_time)
  48. @property
  49. def refund_order_no(self): # type:() -> str
  50. return self.payload["body"]['refundRequestNum']
  51. @property
  52. def errorResponse(self): # type:() -> str
  53. return "error"
  54. @property
  55. def successResponse(self): # type:() -> str
  56. return "ok"
  57. class JDOpenRefundPuller(RefundPuller):
  58. def pull(self, payGateWay, payOrder, post_pay): # type:(PaymentGatewayT, RechargeRecordT, callable) -> None
  59. try:
  60. result = payGateWay.api_refund_query(requestNum = payOrder.orderNo)
  61. refund_record_list = result['data']['refundRecordList']
  62. for refund_record in refund_record_list:
  63. if refund_record['refundRequestNum'] != self._refundOrder.orderNo:
  64. logger.debug('order<orderNo={}> has another refund record<orderNo={}>'.format(
  65. payOrder.orderNo, self._refundOrder.orderNo))
  66. continue
  67. else:
  68. if refund_record["status"] == "FAIL":
  69. self._refundOrder.fail(errorDesc = refund_record["failReason"])
  70. elif refund_record["status"] == "SUCCESS":
  71. import arrow
  72. completeTime = arrow.get(
  73. refund_record['refundTime'], 'YYYY-MM-DD HH:mm:ss', tzinfo = settings.TIME_ZONE).naive
  74. matched = self._refundOrder.succeed(
  75. tradeRefundNo = refund_record['bankRequestNum'], finishedTime = completeTime)
  76. if not matched:
  77. return
  78. post_pay(self._refundOrder, completeTime)
  79. elif result["payStatus"] == "INIT":
  80. pass
  81. except Exception as e:
  82. logger.exception(e)