123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- # coding=utf-8
- import datetime
- import logging
- import typing
- from apilib.monetary import VirtualCoin, RMB, Ratio
- from apps.web.constant import Const, DEALER_CONSUMPTION_AGG_KIND
- from apps.web.core.device_define.kunyuanCar import DEFAULT_VERSION
- from apps.web.device.models import Group, Device
- from apps.web.eventer import EventBuilder
- from apps.web.eventer.base import WorkEvent
- from apps.web.user.models import ConsumeRecord, CardRechargeOrder
- from apps.web.user.models import ServiceProgress, MyUser
- from apps.web.user.transaction_deprecated import refund_money
- if typing.TYPE_CHECKING:
- from apps.web.user.models import Card
- logger = logging.getLogger(__name__)
- class builder(EventBuilder):
- def __getEvent__(self, device_event):
- event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
- if event_data is None or 'cmdCode' not in event_data:
- return None
- if 'ack' in device_event:
- self.deviceAdapter._response_ack(device_event["ack"])
- return ChangYuanCarWorkEventer(self.deviceAdapter, event_data)
- class ChangYuanCarWorkEventer(WorkEvent):
- def do(self, **args):
- cmdCode = self.event_data.get("cmdCode")
- if cmdCode == "A8":
- self.do_finished()
- elif cmdCode == "AE":
- self.do_status()
- elif cmdCode == "B1":
- self.do_start()
- elif cmdCode == "B2":
- self.do_report()
- elif cmdCode == "C1":
- self.do_card()
- else:
- logger.error("error cmdCode".format(cmdCode))
- def do_finished(self):
- """ 结束事件 """
- cardNo = self.event_data["cardNo"]
- port = self.event_data["port"]
- portCache = Device.get_port_control_cache(self.device.devNo, port)
- # 订单版本的
- # if "sequanceNo" in self.event_data and portCache.get("version") > str(DEFAULT_VERSION):
- # return self._do_new_finished()
- if not cardNo:
- self._do_net_pay_finish()
- else:
- self._do_card_pay_finish()
- def do_status(self):
- """ 枪把状态变更 """
- status = self.event_data.get("status")
- port = self.event_data.get("port")
- Device.update_dev_control_cache(self.device.devNo, {port: {"status": status}})
- def do_start(self):
- """ 整体启动后 会上报一次启动信息 """
- logger.info("[KYCAR_do_start] start, dev = {} , event_info = {}".format(self.device.devNo, self.event_data))
- cardNo = self.event_data["cardNo"]
- money = RMB(self.event_data["money"])
- port = self.event_data["port"]
- # 没有卡号的情况 暂时不需要处理
- if not cardNo:
- return
- card = self.update_card_dealer_and_type(cardNo) # type: Card
- if not card:
- return logger.info("[KYCAR_do_start] not find card = {}".format(cardNo))
- # 然后对卡进行扣费使用 创建消费记录
- self.consume_money_for_card(card, money)
- orderNo, cardOrderNo = self.record_consume_for_card(card, money)
- # 创建消费记录 通知用户 扣费
- self.notify_balance_has_consume_for_card(card, money)
- logger.info("[KYCAR_do_start] finished deduct money card = {}, orderNo = {}, cardConsumeOrder = {}".format(cardNo, orderNo, cardOrderNo))
- # 注册服务 个人中心辨别
- ServiceProgress.register_card_service(
- dev=self.device,
- port=int(port),
- card=card
- )
- portCache = {
- "isStart": True,
- "openId": card.openId,
- "startTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- "status": Const.DEV_WORK_STATUS_WORKING,
- "price": int(money),
- "orderNo": orderNo,
- "cardOrderNo": cardOrderNo
- }
- Device.update_dev_control_cache(self.device.devNo, {port: portCache})
- def do_report(self):
- """ 状态上报 """
- port = self.event_data["port"]
- portCache = Device.get_port_control_cache(self.device.devNo, port)
- # 订单版本的
- if "sequanceNo" in self.event_data and portCache.get("version") > str(DEFAULT_VERSION):
- order = ConsumeRecord.objects.filter(sequanceNo=self.event_data["sequanceNo"]).first()
- if not order:
- orderNo, openId = portCache.get("orderNo"), portCache.get("openId")
- order = ConsumeRecord.objects.filter(orderNo=orderNo).first()
- else:
- orderNo, openId = portCache.get("orderNo"), portCache.get("openId")
- order = ConsumeRecord.objects.filter(orderNo=orderNo).first()
- if not order:
- logger.info("[{} do_report not find order, portCache = {}]".format(self.__class__.__name__, portCache))
- return
- leftMoney = RMB(self.event_data.get("leftBalance"))
- usedElec = self.event_data.get("usedElec")
- temperature = self.event_data.get("temperature")
- power = self.event_data.get("power")
- voltage = self.event_data.get("voltage")
- sid = self.event_data.get("sid")
- data = {
- "leftMoney": str(leftMoney),
- "usedElec": usedElec,
- "temperature": temperature,
- "power": power,
- "voltage": voltage,
- "sid": sid
- }
- if "sequanceNo" in self.event_data:
- data["sequanceNo"] = self.event_data["sequanceNo"]
- order.servicedInfo = data
- order.save()
- portCache.update(data)
- Device.update_dev_control_cache(self.device.devNo, {str(order.used_port): portCache})
- def do_card(self):
- """ 查询卡的余额 """
- cardNo = self.event_data["cardNo"]
- card = self.update_card_dealer_and_type(cardNo) # type: Card
- if not card:
- logger.info("card <{}> not refund".format(cardNo))
- return
- # 进行卡的充值
- card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
- self.recharge_id_card(card=card, rechargeType='append', order=card_recharge_order)
- card.reload()
- # 进行余额查询
- self.deviceAdapter._response_card(card)
- def _do_net_pay_finish(self):
- port = self.event_data["port"]
- devCache = Device.get_dev_control_cache(self.device.devNo) or dict()
- portCache = devCache.get(str(port), dict())
- openId = portCache.pop("openId", None)
- vCardId = portCache.get("vCardId")
- leftMoney = self.event_data["leftMoney"]
- payCoins = portCache["coins"]
- payPrice = portCache["price"] # 下发的是price 则退款的时候需要使用price进行一次计算
- # 对于leftMoney 做一次校验保护 主板返回的剩余金额可能是错误的
- leftMoney = min(RMB(leftMoney), RMB(payCoins))
- if not openId:
- logger.info("ChangYuan net pay finish with no openId! {}".format(self.device["devNo"]))
- return
- nowTime = datetime.datetime.now()
- consumeDict = {
- "elec": self.event_data["usedElec"],
- "duration": self.event_data["usedTime"],
- "coin": str(VirtualCoin(payCoins)),
- "spendMoney": str(RMB(RMB(payCoins) - RMB(leftMoney))),
- "reason": self.event_data["reason"],
- "finishedTime": datetime.datetime.strftime(nowTime, "%Y-%m-%d %H:%M:%S")
- }
- user = MyUser.objects.filter(openId=openId, groupId=self.device.groupId).first()
- group = Group.get_group(self.device.groupId)
- logger.info("ChangYuan net pay finish and start to notify user! {}".format(self.device["devNo"]))
- self.notify_user(
- managerialOpenId = user.managerialOpenId if user else "",
- templateName = "service_complete",
- title = u"\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}\\n\\n服务地址:\\t\\t{group}\\n\\n使用时长:\\t\\t{duration}分钟\\n\\n付款金额:\\t\\t{coin}".format(
- reason = self.event_data["reason"],
- logicalCode = self.device.logicalCode,
- group = group.address,
- duration = self.event_data["usedTime"],
- coin = u"{}金币".format(payCoins)
- ),
- service = u"汽车桩充电服务",
- finishTime = datetime.datetime.strftime(nowTime, "%Y-%m-%d %H:%M:%S"),
- remark = u'谢谢您的支持'
- )
- refundMoney = leftMoney
- if refundMoney > RMB(0):
- # 金币支付的并且打开了金币退款的开关
- if not vCardId and self.device.is_auto_refund:
- # 重新计算退币数量 防止coins不等于price
- refundMoney = VirtualCoin(payCoins) * Ratio(refundMoney.amount / RMB(payPrice).amount)
- refund_money(self.device, refundMoney, openId)
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.COIN: (VirtualCoin(payCoins) - refundMoney).mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: refundMoney.mongo_amount
- })
- self.notify_user(
- user.managerialOpenId if user else '',
- 'refund_coins',
- **{
- 'title': u"退款",
- 'backCount': u'%s(金币)' % refundMoney,
- 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- }
- )
- # 剩下的 支付方式有 1.虚拟卡支付 2.金币支付但是没有打开金币支付的开关
- else:
- logger.info("not need to refund pay type! {}".format(self.event_data))
- ServiceProgress.update_progress_and_consume_rcd(
- self.device["ownerId"],
- {
- "open_id": openId,
- "device_imei": self.device["devNo"],
- "port": int(port),
- "isFinished": False
- },
- consumeDict)
- Device.clear_port_control_cache(self.device.devNo, port)
- def _do_card_pay_finish(self):
- logger.info("[KYCar_do_card_pay_finish] dev <{}> card finished, event_info = {}".format(self.device.devNo, self.event_data))
- port = self.event_data["port"]
- cardNo = self.event_data["cardNo"]
- reason = self.event_data["reason"]
- usedElec = self.event_data["usedElec"]
- usedTime = self.event_data["usedTime"]
- leftMoney = self.event_data["leftMoney"]
- card = self.update_card_dealer_and_type(cardNo)
- if not card:
- return logger.info("[KYCar_do_card_pay_finish] dev <{}> card finished, not find card = {}".format(self.device.devNo, cardNo))
- # 获取缓存里面的一些信息
- devCache = Device.get_dev_control_cache(self.device.devNo) or dict()
- portCache = devCache.get(port) or dict()
- price = portCache.get("price", 0)
- if not price:
- return logger.info("[KYCar_do_card_pay_finish] dev <{}> card finished, not find cache = {}".format(self.device.devNo, cardNo))
- cacheLeftMoney = portCache.get("leftMoney", price)
- # 防止主板误报 取最小的一个 然后取大于0的
- leftMoney = max(min(RMB(price), RMB(leftMoney), RMB(cacheLeftMoney)), RMB(0))
- # 对卡进行退费
- self.refund_money_for_card(money=leftMoney, cardId=str(card.id))
- logger.info("[KYCar_do_card_pay_finish] dev <{}> card finished, card = {}, refund = {}".format(self.device.devNo, cardNo, leftMoney))
- # 通知用户
- group = Group.get_group(self.device["groupId"])
- self.notify_user(
- managerialOpenId=card.managerialOpenId,
- templateName="service_complete",
- title=u"\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}\\n\\n服务地址:\\t\\t{group}\\n\\n使用时长:\\t\\t{duration}分钟".format(
- reason=u"充电结束",
- logicalCode=self.device["logicalCode"],
- group=group.get("address", ""),
- duration=self.event_data["usedTime"],
- ),
- service=u"本次充电结束",
- finishTime=datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S"),
- remark=u'谢谢您的支持'
- )
- servicedInfo = {
- "usedElec": usedElec,
- "duration": usedTime,
- "cardNo": cardNo,
- "refundedMoney": leftMoney,
- "reason": reason,
- "finishedTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- }
- ServiceProgress.update_progress_and_consume_rcd(
- self.device["ownerId"],
- {
- "device_imei": self.device["devNo"],
- "cardId": str(card.id),
- "port": int(port),
- "isFinished": False
- },
- servicedInfo
- )
- Device.clear_port_control_cache(self.device.devNo, port)
- def _do_new_finished(self):
- """
- 新版本的结束 通过sequanceNo直接找到订单进行处理
- """
- order = ConsumeRecord.objects.filter(sequanceNo=self.event_data["sequanceNo"]).first() # type: ConsumeRecord
- if not order:
- logger.info("[ChangYuanCarWorkEventer _do_new_finished] not find consume order, sequanceNo = {}".format(self.event_data["sequanceNo"]))
- return
- if order.status == "finished":
- logger.info("[ChangYuanCarWorkEventer _do_new_finished] order status finished, sequanceNo = {}".format(self.event_data["sequanceNo"]))
- return
- leftMoney = self.event_data["leftMoney"]
- refundMoney = min(RMB(leftMoney), RMB(order.money))
- nowTime = datetime.datetime.now()
- user = order.user
- self.notify_user(
- managerialOpenId=user.managerialOpenId if user else "",
- templateName="service_complete",
- title=u"\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}\\n\\n服务地址:\\t\\t{group}\\n\\n使用时长:\\t\\t{duration}分钟".format(
- reason=self.event_data["reason"],
- logicalCode=self.device.logicalCode,
- group=self.device.group.get("address", ""),
- duration=self.event_data["usedTime"],
- ),
- service=u"汽车桩充电服务",
- finishTime=datetime.datetime.strftime(nowTime, "%Y-%m-%d %H:%M:%S"),
- remark=u'谢谢您的支持'
- )
- consumeDict = {"elec": self.event_data["usedElec"], "duration": self.event_data["usedTime"], "coin": str(VirtualCoin(order.coin)),
- "spendMoney": str(RMB(RMB(order.money) - RMB(leftMoney))), "reason": self.event_data["reason"],
- "finishedTime": datetime.datetime.strftime(nowTime, "%Y-%m-%d %H:%M:%S"), "sequanceNo": self.event_data["sequanceNo"]}
- if self.device.is_auto_refund and RMB(leftMoney) > RMB(0):
- refundMoney = VirtualCoin(order.coin) * Ratio(refundMoney.amount / RMB(order.money).amount)
- cardNo = self.event_data["cardNo"]
- if not cardNo:
- refund_money(self.device, refundMoney, user.openId)
- else:
- card = self.update_card_dealer_and_type(cardNo)
- self.refund_money_for_card(money=leftMoney, cardId=str(card.id))
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.COIN: (VirtualCoin(order.money) - refundMoney).mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: refundMoney.mongo_amount
- })
- self.notify_user(
- user.managerialOpenId if user else '',
- 'refund_coins',
- **{
- 'title': u"退款",
- 'backCount': u'%s(金币)' % refundMoney,
- 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- }
- )
- ServiceProgress.update_progress_and_consume_rcd(
- self.device.ownerId,
- {
- "open_id": user.openId,
- "device_imei": self.device.devNo,
- "port": order.used_port,
- "isFinished": False
- },
- consumeDict
- )
- Device.clear_port_control_cache(self.device.devNo, order.used_port)
- order.status = "finished"
- order.save()
|