InAppPurchaseController.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. # @Author : Rocky
  2. # @File : InAppPurchaseController.py
  3. # @Time : 2024/6/21 9:10
  4. import logging
  5. import time
  6. import json
  7. import threading
  8. import requests
  9. from appstoreserverlibrary.api_client import AppStoreServerAPIClient, GetTransactionHistoryVersion
  10. from appstoreserverlibrary.models.AccountTenure import AccountTenure
  11. from appstoreserverlibrary.models.ConsumptionRequest import ConsumptionRequest
  12. from appstoreserverlibrary.models.ConsumptionStatus import ConsumptionStatus
  13. from appstoreserverlibrary.models.DeliveryStatus import DeliveryStatus
  14. from appstoreserverlibrary.models.Environment import Environment
  15. from appstoreserverlibrary.models.LifetimeDollarsPurchased import LifetimeDollarsPurchased
  16. from appstoreserverlibrary.models.LifetimeDollarsRefunded import LifetimeDollarsRefunded
  17. from appstoreserverlibrary.models.Platform import Platform
  18. from appstoreserverlibrary.models.PlayTime import PlayTime
  19. from appstoreserverlibrary.models.RefundPreference import RefundPreference
  20. from appstoreserverlibrary.models.UserStatus import UserStatus
  21. from appstoreserverlibrary.receipt_utility import ReceiptUtility
  22. from appstoreserverlibrary.models.HistoryResponse import HistoryResponse
  23. from appstoreserverlibrary.models.TransactionHistoryRequest import TransactionHistoryRequest, ProductType, Order
  24. from appstoreserverlibrary.signed_data_verifier import SignedDataVerifier
  25. from cryptography.hazmat.backends import default_backend
  26. from cryptography.hazmat.primitives.serialization import load_pem_private_key
  27. from django.db.models import Q
  28. from django.views import View
  29. from django.http import HttpResponse
  30. from Ansjer.config import LOGGER, CONFIG_INFO, CONFIG_TEST, PAY_TYPE_IN_APP_PURCHASE, BASE_DIR, CONFIG_US
  31. from Controller.CheckUserData import DataValid
  32. from Model.models import Order_Model, Store_Meal, Device_Info, UID_Bucket, Unused_Uid_Meal, AiService, Device_User, \
  33. SysMsgModel, OrderPayLog, InAppRefund
  34. from Object.AWS.S3Email import S3Email
  35. from Object.AliSmsObject import AliSmsObject
  36. from Object.AppleInAppPurchaseSubscriptionObject import InAppPurchase
  37. from Object.RedisObject import RedisObject
  38. from Service.CommonService import CommonService
  39. ENV = Environment.SANDBOX if CONFIG_INFO == CONFIG_TEST else Environment.PRODUCTION
  40. logger = logging.getLogger('apple_pay')
  41. class InAppPurchaseView(View):
  42. def get(self, request, *args, **kwargs):
  43. request.encoding = 'utf-8'
  44. operation = kwargs.get('operation')
  45. return self.validation(request.GET, request, operation)
  46. def post(self, request, *args, **kwargs):
  47. request.encoding = 'utf-8'
  48. operation = kwargs.get('operation')
  49. return self.validation(request.POST, request, operation)
  50. def validation(self, request_dict, request, operation):
  51. if operation == 'AppStoreServerNotifications': # App Store服务器通知
  52. return self.app_store_server_notifications(request)
  53. elif operation == 'putRefundOrder': # App Store服务器通知
  54. return self.put_refund_order()
  55. token_code, user_id, response = CommonService.verify_token_get_user_id(request_dict, request)
  56. if token_code != 0:
  57. return response.json(token_code)
  58. if operation == 'verifyTransaction': # 认证交易
  59. return self.verify_transaction(user_id, request_dict, response)
  60. @classmethod
  61. def verify_transaction(cls, user_id, request_dict, response):
  62. """
  63. 认证交易
  64. @param user_id: 用户id
  65. @param request_dict: 请求参数
  66. @request_dict receipt: 收据
  67. @param response: 响应对象
  68. @return: response
  69. """
  70. receipt = request_dict.get('receipt', None)
  71. order_id = request_dict.get('orderID', None)
  72. uid = request_dict.get('uid', None)
  73. lang = request_dict.get('lang', 'en')
  74. channel = request_dict.get('channel', None)
  75. logger.info(f"receipt: {receipt}, 订单orderId: {order_id}, uid: {uid}")
  76. if not all([receipt, uid, channel, order_id]):
  77. return response.json(444)
  78. # redis加锁,防止订单重复
  79. redis_obj = RedisObject()
  80. redis_key = order_id + 'in_app_purchase'
  81. is_lock = redis_obj.CONN.setnx(redis_key, 1)
  82. if not is_lock:
  83. return response.json(5)
  84. redis_obj.CONN.expire(redis_key, 60)
  85. try:
  86. order_qs = Order_Model.objects.filter(orderID=order_id, UID=uid).values("rank_id", "transaction_id")
  87. if not order_qs.exists():
  88. return response.json(173, "订单不存在")
  89. if order_qs[0]["transaction_id"]:
  90. return response.json(0)
  91. if UID_Bucket.objects.filter(orderId=order_id).exists():
  92. return response.json(0)
  93. if Unused_Uid_Meal.objects.filter(order_id=order_id).exists():
  94. return response.json(0)
  95. # 从交易信息中获取product_id
  96. key_path = '{}/Ansjer/file/in_app_purchase/SubscriptionKey_N42WMFCV6A.p8'.format(BASE_DIR)
  97. with open(key_path, 'rb') as file:
  98. # 读取文件内容
  99. private_key = file.read()
  100. key_id = 'N42WMFCV6A'
  101. issuer_id = '69a6de8c-789b-47e3-e053-5b8c7c11a4d1'
  102. bundle_id = 'com.ansjer.zccloud'
  103. environment = ENV
  104. client = AppStoreServerAPIClient(private_key, key_id, issuer_id, bundle_id, environment)
  105. receipt_util = ReceiptUtility()
  106. transaction_id = receipt_util.extract_transaction_id_from_app_receipt(receipt)
  107. if transaction_id is None:
  108. pay_result_url = CommonService.get_payment_status_url(lang, 'fail')
  109. return response.json(0, {'url': pay_result_url})
  110. logger.info(f"苹果内购认证交易订单orderID:{order_id}, transaction_id:{transaction_id}, 时间戳: {int(time.time())}")
  111. OrderPayLog.objects.create(order_id=order_id, order_no=transaction_id,
  112. business_name=f"内购验单",
  113. created_time=int(time.time()), updated_time=int(time.time()),
  114. access_result="SUCCESS")
  115. transaction_info = ""
  116. # 查询交易信息
  117. attempts = 0
  118. while attempts < 6:
  119. try:
  120. transaction_info = client.get_transaction_info(transaction_id)
  121. break
  122. except ConnectionError as err:
  123. attempts += 1
  124. if attempts == 5:
  125. OrderPayLog.objects.create(order_id=order_id, order_no=transaction_id,
  126. business_name=f"{order_id}获取transactionInfo超时",
  127. created_time=int(time.time()), updated_time=int(time.time()),
  128. access_result="ERROR")
  129. return response.json(5)
  130. logger.info(f"订单orderId:{order_id}, transaction_id:{transaction_id}, 第{attempts}次获取支付信息超时")
  131. logger.info(f"订单orderId:{order_id}, transaction_id:{transaction_id}, 成功获取支付信息, 时间戳: {int(time.time())}")
  132. signed_transaction_info = transaction_info.signedTransactionInfo
  133. root_certificates = []
  134. for cert_name in [
  135. 'AppleIncRootCertificate.cer', 'AppleComputerRootCertificate.cer',
  136. 'AppleRootCA-G2.cer', 'AppleRootCA-G3.cer'
  137. ]:
  138. cert_path = '{}/Ansjer/file/in_app_purchase/{}'.format(BASE_DIR, cert_name)
  139. with open(cert_path, 'rb') as file:
  140. # 读取文件内容
  141. root_certificates.append(file.read())
  142. enable_online_checks = True
  143. app_apple_id = 1355964934 # 生产环境必需
  144. signed_data_verifier = SignedDataVerifier(
  145. root_certificates, enable_online_checks, environment, bundle_id, app_apple_id)
  146. payload = signed_data_verifier.verify_and_decode_signed_transaction(signed_transaction_info)
  147. product_id = None
  148. if payload and payload.productId:
  149. product_id = payload.productId
  150. if not product_id:
  151. logger.info(f"苹果内购认证交易订单orderID:{order_id}, product_id获取失败")
  152. pay_result_url = CommonService.get_payment_status_url(lang, 'fail')
  153. return response.json(0, {'url': pay_result_url})
  154. now_time = int(time.time())
  155. store_qs = Store_Meal.objects.filter(id=order_qs[0]['rank_id']).values(
  156. 'id', 'currency', 'price', 'lang__content', 'day', 'commodity_type', 'lang__title', 'expire',
  157. 'commodity_code', 'discount_price', 'bucket_id', 'bucket__mold', 'cycle_config_id', 'is_ai')
  158. if not store_qs.exists():
  159. return response.json(173, "套餐不存在")
  160. bucket_id = store_qs[0]['bucket_id']
  161. is_ai = store_qs[0]['is_ai']
  162. expire = store_qs[0]['expire']
  163. end_time = CommonService.calcMonthLater(expire)
  164. # 查询设备是否已开过云存
  165. use_flag = True
  166. uid_bucket_qs = UID_Bucket.objects.filter(uid=uid). \
  167. values('id', 'bucket_id', 'bucket__region', 'endTime', 'use_status')
  168. if uid_bucket_qs.exists():
  169. uid_bucket = uid_bucket_qs.first()
  170. uid_bucket_id = uid_bucket['id']
  171. # 叠加相同套餐的过期时间
  172. if uid_bucket['use_status'] == 1 and uid_bucket['endTime'] > now_time:
  173. Unused_Uid_Meal.objects.create(
  174. uid=uid, channel=channel, addTime=now_time, order_id=order_id, expire=expire, is_ai=is_ai,
  175. bucket_id=bucket_id)
  176. UID_Bucket.objects.filter(id=uid_bucket_id).update(has_unused=1)
  177. use_flag = False
  178. # 更新套餐的过期时间
  179. else:
  180. UID_Bucket.objects.filter(id=uid_bucket_id).update(
  181. channel=channel, bucket_id=bucket_id, endTime=end_time, updateTime=now_time, use_status=1,
  182. orderId=order_id)
  183. else:
  184. uid_bucket = UID_Bucket.objects.create(
  185. uid=uid, channel=channel, bucket_id=bucket_id, endTime=end_time, use_status=1, orderId=order_id,
  186. addTime=now_time, updateTime=now_time)
  187. uid_bucket_id = uid_bucket.id
  188. # 开通AI服务
  189. if is_ai and use_flag:
  190. ai_service = AiService.objects.filter(uid=uid, channel=channel)
  191. # 有正在使用的套餐,叠加套餐时间,否则创建
  192. if ai_service.exists():
  193. ai_service.update(updTime=now_time, use_status=1, orders_id=order_id, endTime=end_time)
  194. else:
  195. AiService.objects.create(
  196. uid=uid, channel=channel, detect_status=1, use_status=1, orders_id=order_id,
  197. addTime=now_time, updTime=now_time, endTime=end_time)
  198. order_qs.update(status=1, uid_bucket_id=uid_bucket_id, transaction_id=transaction_id, create_vod=1,
  199. payTime=int(time.time()), updTime=int(time.time()))
  200. # 构建云存套餐消息
  201. sys_msg_text_list = cls.cloud_storage_message(uid)
  202. # 发送云存套餐购买消息
  203. asy = threading.Thread(target=cls.do_vod_msg_notice,
  204. args=(uid, user_id, lang, sys_msg_text_list))
  205. asy.start()
  206. redis_obj.del_data(redis_key)
  207. pay_result_url = CommonService.get_payment_status_url(lang, 'success')
  208. OrderPayLog.objects.create(order_id=order_id, order_no=transaction_id,
  209. business_name=f"内购充值成功",
  210. created_time=int(time.time()), updated_time=int(time.time()),
  211. access_result="SUCCESS")
  212. return response.json(0, {'url': pay_result_url})
  213. except Exception as e:
  214. redis_obj.del_data(redis_key)
  215. logger.info('苹果内购认证交易接口异常:{}'.
  216. format('error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e))))
  217. OrderPayLog.objects.create(order_id=order_id, business_name=f"内购验单异常",
  218. created_time=int(time.time()), updated_time=int(time.time()), access_result="ERROR")
  219. pay_result_url = CommonService.get_payment_status_url(lang, 'fail')
  220. return response.json(0, {'url': pay_result_url})
  221. @classmethod
  222. def cloud_storage_message(cls, uid):
  223. # 发送云存开通信息
  224. date_time = time.strftime("%Y-%m-%d", time.localtime())
  225. # 如果存在序列号,消息提示用序列号
  226. device_info_qs = Device_Info.objects.filter(UID=uid).values('serial_number', 'Type')
  227. serial_number = device_info_qs[0]['serial_number']
  228. device_type = device_info_qs[0]['Type']
  229. if serial_number:
  230. device_name = CommonService.get_full_serial_number(uid, serial_number, device_type)
  231. else:
  232. device_name = uid
  233. sys_msg_text_list = [
  234. '温馨提示:尊敬的客户,您的{}设备在{}已成功购买云存套餐'.format(device_name, date_time),
  235. 'Dear customer,you already subscribed the cloud storage package successfully for device {} on '.
  236. format(device_name, time.strftime('%b %dth,%Y', time.localtime()))]
  237. return sys_msg_text_list
  238. @classmethod
  239. def do_vod_msg_notice(cls, uid, user_id, lang, sys_msg_text_list):
  240. """
  241. 发送云存开通信息
  242. @param uid: uid
  243. @param user_id: 用户id
  244. @param lang: 语言
  245. @param sys_msg_text_list: 消息列表
  246. @return: response
  247. """
  248. if lang == 'cn':
  249. sys_msg_text = sys_msg_text_list[0]
  250. else:
  251. sys_msg_text = sys_msg_text_list[1]
  252. now_time = int(time.time())
  253. create_data = {
  254. 'userID_id': user_id,
  255. 'msg': sys_msg_text,
  256. 'addTime': now_time,
  257. 'updTime': now_time,
  258. 'uid': uid,
  259. 'eventType': 0
  260. }
  261. SysMsgModel.objects.create(**create_data)
  262. # 不接收邮件用户
  263. if user_id == '167015836969813800138000':
  264. return
  265. user_qs = Device_User.objects.filter(userID=user_id)
  266. if user_qs.exists():
  267. user = user_qs.first()
  268. username = user.username
  269. data_valid = DataValid()
  270. if data_valid.email_validate(username):
  271. S3Email().faEmail(sys_msg_text, username)
  272. elif data_valid.mobile_validate(username):
  273. # 如果存在序列号,消息提示用序列号
  274. device_info_qs = Device_Info.objects.filter(UID=uid).values('serial_number', 'Type')
  275. if device_info_qs.exists():
  276. serial_number = device_info_qs[0]['serial_number']
  277. device_type = device_info_qs[0]['Type']
  278. if serial_number:
  279. device_name = CommonService.get_full_serial_number(uid, serial_number, device_type)
  280. else:
  281. device_name = uid
  282. params = '{"devname":"%s","submittime":"%s"}' % (
  283. device_name, time.strftime("%Y-%m-%d", time.localtime()))
  284. cls.send_message(username, params, 'SMS_219738485')
  285. @staticmethod
  286. def send_message(phone, params, temp_msg):
  287. """
  288. 发送手机消息
  289. @param phone: 用户名
  290. @param params: 消息参数
  291. @param temp_msg: sms码
  292. """
  293. sign_ms = '周视'
  294. ali_sms = AliSmsObject()
  295. ali_sms.send_code_sms_cloud(phone=phone, params=params, sign_name=sign_ms, temp_msg=temp_msg)
  296. @classmethod
  297. def app_store_server_notifications(cls, request):
  298. logger.info('App Store服务器通知请求类型:{}'.format(request.method))
  299. logger.info('App Store服务器通知参数:{}'.format(request.POST))
  300. logger.info('App Store服务器通知请求body:{}'.format(request.body))
  301. payload = json.loads(request.body.decode('utf-8'))
  302. logger.info('App Store服务器通知payload:{}'.format(payload))
  303. # 获取 signedPayload
  304. signed_payload = payload.get('signedPayload')
  305. if not signed_payload:
  306. return HttpResponse(status=400)
  307. bundle_id = 'com.ansjer.zccloud'
  308. environment = ENV
  309. root_certificates = []
  310. for cert_name in [
  311. 'AppleIncRootCertificate.cer', 'AppleComputerRootCertificate.cer',
  312. 'AppleRootCA-G2.cer', 'AppleRootCA-G3.cer'
  313. ]:
  314. cert_path = '{}/Ansjer/file/in_app_purchase/{}'.format(BASE_DIR, cert_name)
  315. with open(cert_path, 'rb') as file:
  316. # 读取文件内容
  317. root_certificates.append(file.read())
  318. enable_online_checks = True
  319. app_apple_id = 1355964934 # 生产环境必需
  320. # 验证签名并解码 payload
  321. verifier = SignedDataVerifier(
  322. root_certificates, enable_online_checks, environment, bundle_id, app_apple_id)
  323. decoded_payload = verifier.verify_and_decode_notification(signed_payload)
  324. logger.info('App Store服务器通知decoded_payload: {}'.format(decoded_payload))
  325. status_code = 200
  326. if str(decoded_payload.rawNotificationType) == "REFUND":
  327. # 一种通知类型,表示 App Store 成功退还了消耗性应用内购买、非消耗性应用内购买、自动续订或不可续订的交易。
  328. # revocationDate 包含退款交易的时间戳。originalTransactionId 和 productId 用于标识原始交易和产品。revocationReason 包含原因。
  329. # 要请求客户所有退款交易的列表,请参阅 App Store 服务器 API 中的获取退款历史记录。
  330. # 1. 找套餐 使用 transaction_id 找orders
  331. decoded_transaction_information = verifier.verify_and_decode_signed_transaction(
  332. decoded_payload.data.signedTransactionInfo)
  333. transaction_id = decoded_transaction_information.transactionId
  334. logger.info('App Store服务器通知退款, transaction_id:{}'.format(transaction_id))
  335. orders_qs = Order_Model.objects.filter(transaction_id=transaction_id)
  336. # 2. 查找云存套餐使用表 和 云存套餐
  337. if orders_qs.exists():
  338. orders_qs.update(status=5, updTime=int(time.time()))
  339. orderID = orders_qs[0].orderID
  340. uid = orders_qs[0].UID
  341. uid_bucket_qs = UID_Bucket.objects.filter(uid=uid, orderId=orderID, use_status=1,
  342. endTime__gt=int(time.time()))
  343. unused_uid_meal_qs = Unused_Uid_Meal.objects.filter(order_id=orderID)
  344. ai_service_qs = AiService.objects.filter(uid=uid, orders=orderID, use_status=1,
  345. endTime__gt=int(time.time()))
  346. if unused_uid_meal_qs.exists():
  347. unused_uid_meal_qs.delete()
  348. if uid_bucket_qs.exists():
  349. uid_bucket_qs.update(status=0, use_status=2, endTime=int(time.time()),
  350. updateTime=int(time.time()))
  351. if ai_service_qs.exists():
  352. ai_service_qs.update(detect_status=0, use_status=2, endTime=int(time.time()),
  353. updTime=int(time.time()))
  354. # 关闭ai
  355. msg = {'commandType': 'AIDisable'}
  356. thing_name = CommonService.query_serial_with_uid(uid) # 存在序列号则为使用序列号作为物品名
  357. topic_name = 'ansjer/generic/{}'.format(thing_name)
  358. req_success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
  359. logger.info(f'App Store服务器通知用户退款, 关闭AI:{req_success}')
  360. InAppRefund.objects.filter(transaction_id=transaction_id).update(updated_time=int(time.time()),
  361. refund_progress=2)
  362. elif CONFIG_INFO == CONFIG_US:
  363. url = "https://api.zositeche.com/inAppPurchase/AppStoreServerNotifications"
  364. eur_response = requests.post(url=url, json=json.loads(request.body))
  365. status_code = eur_response.status_code
  366. elif str(decoded_payload.rawNotificationType) == "CONSUMPTION_REQUEST":
  367. decoded_transaction_information = verifier.verify_and_decode_signed_transaction(
  368. decoded_payload.data.signedTransactionInfo)
  369. transaction_id = decoded_transaction_information.transactionId
  370. app_account_token = decoded_transaction_information.appAccountToken
  371. if app_account_token is None:
  372. app_account_token = ""
  373. orders_qs = Order_Model.objects.filter(transaction_id=transaction_id)
  374. if orders_qs.exists():
  375. orderID = orders_qs[0].orderID
  376. uid = orders_qs[0].UID
  377. app_type = orders_qs[0].app_type
  378. now_time = int(time.time())
  379. put_time = int(now_time + 11.5 * 60 * 60)
  380. in_app_refund_qs = InAppRefund.objects.filter(transaction_id=transaction_id)
  381. if in_app_refund_qs.exists():
  382. in_app_refund_qs.update(refund_progress=0, updated_time=now_time, app_account_token=app_account_token)
  383. else:
  384. InAppRefund.objects.create(transaction_id=transaction_id, orderID=orderID,
  385. uid=uid, app_type=app_type, created_time=now_time,
  386. updated_time=now_time, put_time=put_time,
  387. app_account_token=app_account_token)
  388. elif CONFIG_INFO == CONFIG_US:
  389. url = "https://api.zositeche.com/inAppPurchase/AppStoreServerNotifications"
  390. eur_response = requests.post(url=url, json=json.loads(request.body))
  391. status_code = eur_response.status_code
  392. elif str(decoded_payload.rawNotificationType) == "REFUND_DECLINED":
  393. decoded_transaction_information = verifier.verify_and_decode_signed_transaction(
  394. decoded_payload.data.signedTransactionInfo)
  395. transaction_id = decoded_transaction_information.transactionId
  396. orders_qs = Order_Model.objects.filter(transaction_id=transaction_id)
  397. if orders_qs.exists():
  398. InAppRefund.objects.filter(transaction_id=transaction_id).update(refund_progress=3,
  399. updated_time=int(time.time()))
  400. elif CONFIG_INFO == CONFIG_US:
  401. url = "https://api.zositeche.com/inAppPurchase/AppStoreServerNotifications"
  402. eur_response = requests.post(url=url, json=json.loads(request.body))
  403. status_code = eur_response.status_code
  404. return HttpResponse(status=status_code)
  405. @staticmethod
  406. def put_refund_order():
  407. put_time = int(time.time())
  408. in_app_refund_qs = InAppRefund.objects.filter(refund_progress=0, put_time__lt=put_time)
  409. for in_app_refund in in_app_refund_qs:
  410. transaction_id = in_app_refund.transaction_id
  411. app_type = in_app_refund.app_type
  412. if app_type == 1:
  413. bundle_id = "com.ansjer.zccloud"
  414. elif app_type == 2:
  415. bundle_id = "com.cloudlife.commissionf"
  416. else:
  417. return HttpResponse(status=200)
  418. in_app_purchase_obj = InAppPurchase(bundle_id=bundle_id)
  419. # AppStoreServerAPIClient 用于查询交易信息
  420. client = in_app_purchase_obj.client
  421. orderID = in_app_refund.orderID
  422. app_account_token = in_app_refund.app_account_token
  423. unused_uid_meal_qs = Unused_Uid_Meal.objects.filter(order_id=orderID)
  424. uid_bucket_qs = UID_Bucket.objects.filter(orderId=orderID, endTime__gt=int(time.time()))
  425. if unused_uid_meal_qs.exists():
  426. consumptionStatus = ConsumptionStatus.NOT_CONSUMED
  427. deliveryStatus = DeliveryStatus.DELIVERED_AND_WORKING_PROPERLY
  428. elif uid_bucket_qs.exists():
  429. consumptionStatus = ConsumptionStatus.PARTIALLY_CONSUMED
  430. deliveryStatus = DeliveryStatus.DELIVERED_AND_WORKING_PROPERLY
  431. elif UID_Bucket.objects.filter(orderId=orderID, endTime__lt=int(time.time())):
  432. consumptionStatus = ConsumptionStatus.FULLY_CONSUMED
  433. deliveryStatus = DeliveryStatus.DELIVERED_AND_WORKING_PROPERLY
  434. else:
  435. consumptionStatus = ConsumptionStatus.UNDECLARED
  436. deliveryStatus = DeliveryStatus.DID_NOT_DELIVER_FOR_OTHER_REASON
  437. if in_app_refund.refund_preference == 1:
  438. refundPreference = RefundPreference.PREFER_GRANT
  439. else:
  440. refundPreference = RefundPreference.PREFER_DECLINE
  441. consumption_request = ConsumptionRequest(
  442. customerConsented=True,
  443. consumptionStatus=consumptionStatus,
  444. platform=Platform.UNDECLARED,
  445. sampleContentProvided=True,
  446. deliveryStatus=deliveryStatus,
  447. appAccountToken=app_account_token,
  448. accountTenure=AccountTenure.UNDECLARED,
  449. playTime=PlayTime.UNDECLARED,
  450. lifetimeDollarsRefunded=LifetimeDollarsRefunded.UNDECLARED,
  451. lifetimeDollarsPurchased=LifetimeDollarsPurchased.UNDECLARED,
  452. userStatus=UserStatus.ACTIVE,
  453. refundPreference=refundPreference,
  454. )
  455. client.send_consumption_data(transaction_id, consumption_request)
  456. logger.info(f'内购退款消费数据提交, 订单orderID:{orderID}, transaction_id:{transaction_id}')
  457. in_app_refund.refund_progress = 1
  458. in_app_refund.updated_time = int(time.time())
  459. in_app_refund.put_time = int(time.time())
  460. in_app_refund.save()
  461. return HttpResponse(status=200)