# coding=utf-8 import datetime import base64 import json import logging import requests from mongoengine import DoesNotExist from typing import TYPE_CHECKING, Optional from apps.web.core.bridge.wechat.v3api import WechatApiProxy from apps.web.core.exceptions import MerchantError from apps.web.core.models import WechatServiceProvider, JDAggrePayApp, AliApp from apps.web.core.utils import async_operation_no_catch from apps.web.dealer.models import Dealer from apps.web.merchant.exceptions import JdOpenParamsError from apps.web.merchant.constant import ProductStatus, MerchantStatus, JdOpenMerchantType, JdOpenAccountType, JdOpenAuditStatus, JdOpenProductType, AuthStatus, ALI_PAY_QR_CODE from apps.web.merchant.models import MerchantSourceInfo, JDOpenApplyInfo, MerchantAgent from library.jdopen.constants import OPEN_SECRET_KEY, OPEN_ACCESS_KEY from library.jdopen.exceptions import JdOpenException from library.jdopen.client import JdOpenMerchantClient from library.jdpsi.client import JdPsiMerchantClient from library.jdpsi.exceptions import JdPsiException if TYPE_CHECKING: from apps.web.agent.models import Agent from apps.web.merchant.models import Attach logger = logging.getLogger(__name__) # 信号触发函数 def upload_merchant_to_jd(sender, merchantId, **kwargs): # type: (Optional[MerchantSourceInfo, JDOpenApplyInfo], str, dict) -> None # 先查找到商户 logger.info("[upload_merchant_to_jd] start to upload data to jd merchant, merchantId = {}".format(merchantId)) try: merchant = sender.objects.get(id=merchantId) except DoesNotExist: logger.error("[upload_merchant_to_jd] find merchant error not exist!, merchantId = {}".format(merchantId)) return proxy = MerchantApplyProxy(merchant) async_operation_no_catch(proxy.submit_data) def upload_merchant_to_auth(sender, merchantId, **kwargs): # type: (Optional[MerchantSourceInfo, JDOpenApplyInfo], str, dict) -> None """ 上传商户的实名确认信息 包括支付宝的和微信的 """ logger.info("[upload_merchant_to_auth] start to upload data to wechat, merchantId = {}".format(merchantId)) try: merchant = sender.objects.get(id=merchantId) except DoesNotExist: logger.error("[upload_merchant_to_auth] find merchant error not exist!, merchantId = {}".format(merchantId)) return # 分别提交支付宝以及微信的实名认证资料 proxy = MerchantApplyProxy(merchant) async_operation_no_catch(proxy.submit_wechat) async_operation_no_catch(proxy.submit_ali) def create_psi_product(sender, merchantId, **kwargs): logger.info("[create_psi_product] start to create psi merchant product, merchantId = {}".format(merchantId)) try: merchant = sender.objects.get(id=merchantId) except DoesNotExist: logger.error("[create_psi_product] find merchant error not exist!, merchantId = {}".format(merchantId)) return applier = JdPsiMerchantApplier(merchant, get_psi_client()) async_operation_no_catch(applier.create_product) def create_settle(sender, merchantId, **kwargs): # type: (Optional[MerchantSourceInfo, JDOpenApplyInfo], str, dict) -> None """ 京东 open 创建商户 """ logger.info("[create_settle] start to create open merchant settle account, merchantId = {}".format(merchantId)) try: merchant = sender.objects.get(id=merchantId) except DoesNotExist: logger.error("[create_settle] find merchant error not exist!, merchantId = {}".format(merchantId)) return applier = JdOpenMerchantApplier(merchant, get_open_client()) async_operation_no_catch(applier.create_settle) def create_shop(sender, merchantId, **kwargs): # type: (Optional[MerchantSourceInfo, JDOpenApplyInfo], str, dict) -> None """ 京东 open 创建商店 """ logger.info("[create_shop] start to create open shop, merchantId = {}".format(merchantId)) try: merchant = sender.objects.get(id=merchantId) except DoesNotExist: logger.error("[create_shop] find merchant error not exist!, merchantId = {}".format(merchantId)) return applier = JdOpenMerchantApplier(merchant, get_open_client()) async_operation_no_catch(applier.create_shop) def upload_attaches(sender, merchantId, **kwargs): # type: (Optional[MerchantSourceInfo, JDOpenApplyInfo], str, dict) -> None """ 京东 open 上传附件 """ logger.info("[upload_attaches] start to upload open merchant attaches, merchantId = {}".format(merchantId)) try: merchant = sender.objects.get(id=merchantId) except DoesNotExist: logger.error("[upload_attaches] find merchant error not exist!, merchantId = {}".format(merchantId)) return applier = JdOpenMerchantApplier(merchant, get_open_client()) async_operation_no_catch(applier.upload_attaches) def complete_customer(sender, merchantId, **kwargs): # type: (Optional[MerchantSourceInfo, JDOpenApplyInfo], str, dict) -> None """ 京东 open 完成报单 """ logger.info("[complete_customer] start to complete open merchant, merchantId = {}".format(merchantId)) try: merchant = sender.objects.get(id=merchantId) except DoesNotExist: logger.error("[complete_customer] find merchant error not exist!, merchantId = {}".format(merchantId)) return applier = JdOpenMerchantApplier(merchant, get_open_client()) async_operation_no_catch(applier.complete) def confirm_customer(sender, merchantId, **kwargs): # type: (Optional[MerchantSourceInfo, JDOpenApplyInfo], str, dict) -> None """ 京东 open 报单确认 """ logger.info("[confirm_customer] start to confirm open merchant, merchantId = {}".format(merchantId)) try: merchant = sender.objects.get(id=merchantId) except DoesNotExist: logger.error("[confirm_customer] find merchant error not exist!, merchantId = {}".format(merchantId)) return applier = JdOpenMerchantApplier(merchant, get_open_client()) async_operation_no_catch(applier.confirm) # 功能辅助函数 def get_file(url): res = requests.get(url) return res.content def get_location_by_area(province, city, district, addr, webKey="109f7b4b81698f345f24aa3dc6684924"): """ 根据地址获取经纬度 """ logger.info("[get_location_by_area] province = {}, city = {}, district = {}, addr = {}".format(province, city, district, addr)) url = "https://restapi.amap.com/v3/geocode/geo?address={}{}{}{}&key={}".format(province, city, district, addr, webKey) try: result = requests.get(url).json() except Exception as e: logger.error("[get_location_by_area] error = {}, province = {}, city = {}, district = {}, addr = {}".format(e, province, city, district, addr)) return "0.000000", "0.000000" if "status" not in result or result["status"] != "1": return "0.000000", "0.000000" geocode = result["geocodes"][0] lng, lat = geocode["location"].split(",") return lng, lat def get_wechat_proxy(): provider = WechatServiceProvider.objects.get(mchid="398254625") # type: WechatServiceProvider return WechatApiProxy(provider) # type: WechatApiProxy def get_open_client(): openClient = JdOpenMerchantClient(OPEN_ACCESS_KEY, OPEN_SECRET_KEY) return openClient def get_psi_client(): psiClient = JdPsiMerchantClient() return psiClient def get_ali_client(): app = AliApp.objects.get(appid="2021001191645419") # type: AliApp return app.client def query_merchant_settle(merchantOwner, st, et): # type: (Dealer, datetime.datetime, datetime.datetime) -> dict """ 查询商户的结算信息 只查询1天的 (商户拥有者可能是代理商、经销商) """ merchant = MerchantSourceInfo.get_source_record(merchantOwner) # type: MerchantSourceInfo if not merchant.merchantNo: app = merchantOwner.jd_env_pay_app() # type: JDAggrePayApp agentNo = MerchantAgent.default_merchant_agent merchantNo = app.merchant_no else: agentNo = merchant.agentNo merchantNo = merchant.merchantNo startTime = datetime.datetime.strftime(st, "%Y-%m-%d") endTime = datetime.datetime.strftime(et, "%Y-%m-%d") psiClient = get_psi_client() result = psiClient.query_settle(agentNo, startTime, endTime, merchantNo=merchantNo) return result def query_sub_merchantId(document, openClient): # type: (Optional[None, JDOpenApplyInfo], JdOpenMerchantClient) -> Optional[None, JDOpenApplyInfo] """ 查询 jdopen 的子商户编号 (微信 支付宝) """ # 首先查询 微信的子商编 data = { "customerNum": document.customerNum, "payProduct": str(JdOpenProductType.WX.value) } try: result = openClient.support.get_product_customer(**data) except JdOpenException as je: logger.error("[query_sub_merchantId] duo_la_bao merchant <{}> query audit result error = {} ".format(document, je)) return # 获取到了微信的子商编号 for item in result["data"]: if item["status"] == "OPEN": subMerchantId = item["subCustomerNum"] break else: subMerchantId = "" logger.info("[query_sub_merchantId] duo_la_bao merchant <{}> query sub merchantId subMerchantId = {} ".format(document, subMerchantId)) data["payProduct"] = str(JdOpenProductType.ALI.value) try: result = openClient.support.get_product_customer(**data) except JdOpenException as je: logger.error("[query_sub_merchantId] duo_la_bao merchant <{}> query audit result error = {} ".format(document, je)) return for item in result["data"]: if item["status"] == "OPEN": subAliMerchantId = item["subCustomerNum"] break else: subAliMerchantId = "" logger.info("[query_sub_merchantId] duo_la_bao merchant <{}> query sub merchantId subAliMerchantId = {} ".format(document, subAliMerchantId)) # 更新商户编号到 文档 然后等待进一步的资料 return document.update_sub_merchant(subMerchantId=subMerchantId, subAliMerchantId=subAliMerchantId) def get_merchant_by_version(owner, version): if version == "v2": return JDOpenApplyInfo.get_merchant_by_owner(owner) else: return MerchantSourceInfo.get_source_record(owner) def update_channels_info(merchant): """ 获取自研商户的子商编 新增获取支付宝的子商户编号 """ logger.info("[update_channels_info] ownerId = {}".format(merchant.ownerId)) # 如果存在就不要去获取了 if merchant.wxSource.subMerchantId and merchant.wxSource.subAliMerchantId: logger.info("[update_channels_info] ownerId = {}, channels has been ready".format( merchant.ownerId, merchant.wxSource.subMerchantId, merchant.wxSource.subAliMerchantId )) return merchant wxApplier = merchant.wxSource # 首先尝试获取微信子商编号 psiClient = get_psi_client() result = psiClient.query_sub_channel(merchant.agentNo, merchant.merchantNo) if "hlbWxSubNoResultInfo" not in result["data"]: logger.info("[update_channels_info] owner = <{}-{}>, not get subMchId and channelId".format(merchant.ownerRole, merchant.ownerId)) merchant.to_fail(u"渠道编号获取错误") return merchant.reload() channelsInfo = json.loads(result["data"]["hlbWxSubNoResultInfo"]) subMchId, channelId = channelsInfo["threePartnerNoData"][0]["threePartnerNo"], channelsInfo["threePartnerNoData"][0]["channelMerchantNo"] # 获取支付宝的子商户编号 openClient = get_open_client() result = openClient.support.get_product_customer(merchant.merchantNo, "ALIPAY") subCustomerNum = merchant.wxSource.subAliMerchantId = result["data"][0]["subCustomerNum"] # 直接更新渠道编号 wxApplier.update_sub_merchant(subMchId=subMchId, channel=channelId, subCustomerNum=subCustomerNum) return merchant.reload() def is_wechat_authorized(merchant): """ 是否已经通过微信的审核 """ proxy = get_wechat_proxy() result = proxy.get_merchant_apply_state(merchant.wxSource.subMerchantId) return result["authorize_state"] == "AUTHORIZE_STATE_AUTHORIZED" def is_alipay_authorized(merchant): """ 是否已经通过支付宝的审核 目前没有办法获取到支付宝的实名状态 一律返回True """ return True def query_audit_result(document, openClient): # type: (Optional[None, JDOpenApplyInfo], JdOpenMerchantClient) -> Optional[None, JDOpenApplyInfo] """ 查询报单的结果 """ logger.info("[query_audit_result] duo_la_bao merchant <{}>".format(document)) if not document: return data = { "agentNum": document.agentNum, "customerNum": document.customerNum } try: result = openClient.audit.get_audit_result(**data) except JdOpenException as je: logger.error("[query_audit_result] duo_la_bao merchant <{}> query audit result error = {} ".format(document, je)) return logger.info("[query_audit_result] duo_la_bao merchant <{}>, result = {}".format(document, result)) declareResult = result["data"]["declareList"][-1] # 根据京东审核的状态 确定不同的 declareStatus = declareResult["declareStatus"] if declareStatus == JdOpenAuditStatus.PASS: logger.info("[query_audit_result] duo_la_bao merchant <{}>, audit pass".format(document)) document.to_success() elif declareStatus == JdOpenAuditStatus.NOT_PASS: logger.info("[query_audit_result] duo_la_bao merchant <{}>, audit no pass".format(document)) auditOpinion = declareResult["auditOpinion"] document.to_fail(auditOpinion) else: logger.info("[query_audit_result] duo_la_bao merchant <{}>, audit doing".format(document)) return document def get_wechat_auth_info(merchant): # type:(Optional[JDOpenApplyInfo, MerchantSourceInfo]) -> dict """ 获取微信的实名信息 """ data = { "channel": "wechat", "status": AuthStatus.AUDIT, "subMerchantId": "", "description": "" } subMerchantId = merchant.wxSource.subMerchantId if not subMerchantId: return data data.update({"subMerchantId": subMerchantId}) if is_wechat_authorized(merchant): data["status"] = AuthStatus.AUTHED return data applymentId = merchant.wxSource.applymentId if not applymentId: return data wechatProxy = get_wechat_proxy() result = wechatProxy.get_merchant_audit(merchant.wxSource.applymentId) if "applyment_state" not in result: return data elif result["applyment_state"] in [ "APPLYMENT_STATE_PASSED", "APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON", "APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT" ]: data["status"] = AuthStatus.PASS data["qrCode"] = "data:image/png;base64,{}".format(result["qrcode_data"]) return data elif result["applyment_state"] in ["APPLYMENT_STATE_REJECTED"]: data["status"] = AuthStatus.NO_PASS data["description"] = u"【审核驳回】{}:{},请联系平台客服处理".format(result["reject_param"], result["reject_reason"]) return data else: return data def get_alipay_auth_info(merchant): """ 获取支付宝的实名信息 支付宝的时候一定要兼容之前的版本 之前从来没有获取过支付宝的子商户编号 """ data = { "channel": "ali", "status": AuthStatus.AUDIT, "subMerchantId": "", "description": "" } subMerchantId = merchant.wxSource.subAliMerchantId if not subMerchantId: merchant = update_channels_info(merchant) subMerchantId = merchant.wxSource.subAliMerchantId if subMerchantId: data["subMerchantId"] = subMerchantId data["status"] = AuthStatus.PASS data["qrCode"] = ALI_PAY_QR_CODE return data class QueryMerchant(object): def __init__(self, merchant): # type:(MerchantSourceInfo) -> None self._mer = merchant def do(self): pass class JdOpenParamsChecker(object): def __init__(self, **kwargs): self.data = {"id": kwargs.pop("id", "")} self.source = kwargs @staticmethod def area_check(area): return "code" in area and "name" in area @staticmethod def date_check(date): if date == "forever": return True try: datetime.datetime.strptime(date, "%Y-%m-%d") except ValueError: return False return True def create(self, owner): # 公共参数的检查 self.common_check() # 公司商户的参数检查以及 商户创建 if self.data["customerType"] == JdOpenMerchantType.COMPANY: self.check_company_merchant() return JDOpenApplyInfo.create_company(owner, **self.data) # 个人商户的参数检查 商户创建 elif self.data["customerType"] == JdOpenMerchantType.PERSON: self.check_person_merchant() return JDOpenApplyInfo.create_personal(owner, **self.data) # 个体工商户的参数检查 商户创建 elif self.data["customerType"] == JdOpenMerchantType.INDIVIDUALBISS: self.check_individualbiss_merchant() return JDOpenApplyInfo.create_individualbiss(owner, **self.data) # 事业单位的参数检查 商户创建 else: self.check_institution_merchant() return JDOpenApplyInfo.create_institution(owner, **self.data) def common_check(self): """ 检测商户的基本信息 并将其赋值到data中 """ customerType = self.source.get("customerType") if customerType not in JdOpenMerchantType.choices(): raise JdOpenParamsError(u"参数错误,商户类型错误") self.data["customerType"] = customerType shortName = self.source.get("shortName") if not shortName: raise JdOpenParamsError(u"参数错误,缺少商户简称") self.data["shortName"] = shortName province = self.source.get("province") city = self.source.get("city") district = self.source.get("district") address = self.source.get("address") if not all([province, city, district]): raise JdOpenParamsError(u"参数错误,缺少商户地区信息") if not self.area_check(province): raise JdOpenParamsError(u"参数错误,商户地区 省 信息错误") if not self.area_check(city): raise JdOpenParamsError(u"参数错误, 商户地区 市 信息错误") if not self.area_check(district): raise JdOpenParamsError(u"参数错误,商户地区 区 信息错误") if not address: raise JdOpenParamsError(u"参数错误,缺少商户详细地址") self.data["province"] = province self.data["city"] = city self.data["district"] = district self.data["address"] = address # 内部补充经纬度 self.data["mapLng"], self.data["mapLat"] = get_location_by_area(province["name"], city["name"], district["name"], address) def check_person_merchant(self): """ 创建一条个人商户的记录 """ # 用户填写的个人界面的信息提取 legalImgFront = self.source.get("legalImgFront") legalImgBack = self.source.get("legalImgBack") legalImgHold = self.source.get("legalImgHold") legalName = self.source.get("legalName") legalCardNo = self.source.get("legalCardNo") legalStart = self.source.get("legalStart") legalEnd = self.source.get("legalEnd") legalForever = self.source.get("legalForever") if not legalImgFront: raise JdOpenParamsError(u"参数错误,请上传收款人证件正面照") if not legalImgBack: raise JdOpenParamsError(u"参数错误,请上传收款人证件反面照") if not legalImgHold: raise JdOpenParamsError(u"参数错误,请上传收款人手持证件照") if not legalName: raise JdOpenParamsError(u"参数错误,缺少收款人姓名") if not legalCardNo: raise JdOpenParamsError(u"参数错误,缺少收款人证件号码") if not self.date_check(legalStart) or not self.date_check(legalEnd): raise JdOpenParamsError(u"参数错误, 收款人证件有效期错误") self.data["legalImgFront"] = legalImgFront self.data["legalImgBack"] = legalImgBack self.data["legalImgHold"] = legalImgHold self.data["legalName"] = legalName self.data["legalCardNo"] = legalCardNo self.data["legalStart"] = legalStart self.data["legalEnd"] = legalEnd if not legalForever else "forever" # 用户填写的结算界面的信息提取 accountType = self.source.get("accountType") bankImg = self.source.get("bankImg") bankCardNo = self.source.get("bankCardNo") bankName = self.source.get("bankName") bankBranchName = self.source.get("bankBranchName") bankProvince = self.source.get("bankProvince") bankCity = self.source.get("bankCity") bankPhone = self.source.get("bankPhone") if not accountType: raise JdOpenParamsError(u"参数错误,请选择账户类型") if not bankImg: raise JdOpenParamsError(u"参数错误,请上传银行卡图片") if not bankCardNo: raise JdOpenParamsError(u"参数错误,缺少银行卡号") if not bankName: raise JdOpenParamsError(u"参数错误,缺少银行名称") if not bankBranchName: raise JdOpenParamsError(u"参数错误,缺少银行支行名称") if not all([bankProvince, bankCity]): raise JdOpenParamsError(u"参数错误,缺少银行地区信息") if not self.area_check(bankProvince) or not self.area_check(bankCity): raise JdOpenParamsError(u"参数错误,银行开户地区选择错误") if not bankPhone: raise JdOpenParamsError(u"参数错误,缺少银行卡预留手机号码") self.data["accountType"] = accountType self.data["bankImg"] = bankImg self.data["bankCardNo"] = bankCardNo self.data["bankName"] = bankName self.data["bankBranchName"] = bankBranchName self.data["bankProvince"] = bankProvince self.data["bankCity"] = bankCity self.data["bankPhone"] = bankPhone # 商店照片的信息的获取 shopImgA = self.source.get("shopImgA") shopImgB = self.source.get("shopImgB") shopImgC = self.source.get("shopImgC") if not all([shopImgA, shopImgB, shopImgC]): raise JdOpenParamsError(u"参数错误,缺少营业照片") self.data["shopImgA"] = shopImgA self.data["shopImgB"] = shopImgB self.data["shopImgC"] = shopImgC # 联系人手机号码获取 这个字段的位置不固定 如果是个人 跟随法人信息确认 其余均在联系人地方 phoneNumber = self.source.get("phoneNumber") if not phoneNumber: raise JdOpenParamsError(u"参数错误,缺少联系人手机号码") self.data["phoneNumber"] = phoneNumber # 非默认参数的补充 self.data["fullName"] = u"个人_{}".format(self.data["legalName"]) def check_individualbiss_merchant(self): """ 个体工商户 (简易版的企业商户 区别在于 个体工商户可以对私) """ # 公司法人的参数校验 legalImgFront = self.source.get("legalImgFront") legalImgBack = self.source.get("legalImgBack") legalName = self.source.get("legalName") legalCardNo = self.source.get("legalCardNo") legalStart = self.source.get("legalStart") legalEnd = self.source.get("legalEnd") legalForever = self.source.get("legalForever") if not legalImgFront: raise JdOpenParamsError(u"参数错误,请上传收款人证件正面照") if not legalImgBack: raise JdOpenParamsError(u"参数错误,请上传收款人证件反面照") if not legalName: raise JdOpenParamsError(u"参数错误,缺少收款人姓名") if not legalCardNo: raise JdOpenParamsError(u"参数错误,缺少收款人证件号码") if not self.date_check(legalStart) or not self.date_check(legalEnd): raise JdOpenParamsError(u"参数错误, 收款人证件有效期错误") self.data["legalImgFront"] = legalImgFront self.data["legalImgBack"] = legalImgBack self.data["legalName"] = legalName self.data["legalCardNo"] = legalCardNo self.data["legalStart"] = legalStart self.data["legalEnd"] = legalEnd if not legalForever else "forever" # 联系人信息的填写 contactImgFront = self.source.get("contactImgFront") contactImgBack = self.source.get("contactImgBack") contactName = self.source.get("contactName") contactCardNo = self.source.get("contactCardNo") contactStart = self.source.get("contactStart") contactEnd = self.source.get("contactEnd") contactForever = self.source.get("contactForever") if not contactImgFront: raise JdOpenParamsError(u"参数错误,请上传联系人证件正面照") if not contactImgBack: raise JdOpenParamsError(u"参数错误,请上传联系人证件反面照") if not contactName: raise JdOpenParamsError(u"参数错误,缺少联系人姓名") if not contactCardNo: raise JdOpenParamsError(u"参数有误,缺少联系人证件号码") if not self.date_check(contactStart) or not self.date_check(contactEnd): raise JdOpenParamsError(u"参数错误, 联系人证件有效期错误") self.data["contactImgFront"] = contactImgFront self.data["contactImgBack"] = contactImgBack self.data["contactName"] = contactName self.data["contactCardNo"] = legalCardNo self.data["contactStart"] = contactCardNo self.data["contactEnd"] = contactEnd if not contactForever else "forever" # 营业执照的参数校验 organizationImg = self.source.get("organizationImg") organizationName = self.source.get("organizationName") organizationNo = self.source.get("organizationNo") organizationStart = self.source.get("organizationStart") organizationEnd = self.source.get("organizationEnd") organizationProvince = self.source.get("organizationProvince") organizationCity = self.source.get("organizationCity") organizationDistrict = self.source.get("organizationDistrict") organizationAddress = self.source.get("organizationAddress") organizationForever = self.source.get("organizationForever") if not organizationImg: raise JdOpenParamsError(u"参数错误,请上传营业执照") if not organizationName: raise JdOpenParamsError(u"参数错误,缺少公司名称") if not organizationNo: raise JdOpenParamsError(u"参数错误,缺少统一信用码") if not self.date_check(organizationStart) or not self.date_check(organizationEnd): raise JdOpenParamsError(u"参数错误, 营业执照有效期填写错误") if not self.area_check(organizationProvince): raise JdOpenParamsError(u"参数错误,营业执照 省 信息错误") if not self.area_check(organizationCity): raise JdOpenParamsError(u"参数错误,营业执照 市 信息错误") if not self.area_check(organizationDistrict): raise JdOpenParamsError(u"参数错误,营业执照 区 信息错误") if not organizationAddress: raise JdOpenParamsError(u"参数错误,缺少营业执照详细地址") self.data["organizationImg"] = organizationImg self.data["organizationName"] = organizationName self.data["organizationNo"] = organizationNo self.data["organizationStart"] = organizationStart self.data["organizationEnd"] = organizationEnd if not organizationForever else "forever" self.data["organizationProvince"] = organizationProvince self.data["organizationCity"] = organizationCity self.data["organizationDistrict"] = organizationDistrict self.data["organizationAddress"] = organizationAddress # 用户填写的结算界面的信息提取 accountType = self.source.get("accountType") bankImg = self.source.get("bankImg") bankCardNo = self.source.get("bankCardNo") bankName = self.source.get("bankName") bankBranchName = self.source.get("bankBranchName") bankProvince = self.source.get("bankProvince") bankCity = self.source.get("bankCity") bankPhone = self.source.get("bankPhone") if not accountType: raise JdOpenParamsError(u"参数错误,请选择账户类型") if not bankImg: raise JdOpenParamsError(u"参数错误,请上传开户许可证图片") if not bankCardNo: raise JdOpenParamsError(u"参数错误,缺少结算账号") if not bankName: raise JdOpenParamsError(u"参数错误,缺少结算银行名称") if not bankBranchName: raise JdOpenParamsError(u"参数错误,缺少结算银行支行名称") if not all([bankProvince, bankCity]): raise JdOpenParamsError(u"参数错误,缺少结算银行地区信息") if not self.area_check(bankProvince) or not self.area_check(bankCity): raise JdOpenParamsError(u"参数错误,结算银行开户地区选择错误") if not bankPhone: raise JdOpenParamsError(u"参数错误,缺少银行卡预留手机号码") self.data["accountType"] = accountType self.data["bankImg"] = bankImg self.data["bankCardNo"] = bankCardNo self.data["bankName"] = bankName self.data["bankBranchName"] = bankBranchName self.data["bankProvince"] = bankProvince self.data["bankCity"] = bankCity self.data["bankPhone"] = bankPhone # 商店照片的信息的获取 shopImgA = self.source.get("shopImgA") shopImgB = self.source.get("shopImgB") shopImgC = self.source.get("shopImgC") if not all([shopImgA, shopImgB, shopImgC]): raise JdOpenParamsError(u"参数错误,缺少营业照片") self.data["shopImgA"] = shopImgA self.data["shopImgB"] = shopImgB self.data["shopImgC"] = shopImgC # 联系人手机号码获取 这个字段的位置不固定 如果是个人 跟随法人信息确认 其余均在联系人地方 phoneNumber = self.source.get("phoneNumber") if not phoneNumber: raise JdOpenParamsError(u"参数错误,缺少联系人手机号码") self.data["phoneNumber"] = phoneNumber # 个体工商户的 商户全程为 营业执照名称 self.data["fullName"] = u"{}".format(self.data["organizationName"]) # 个体工商户的 组织机构代码 税务登记证 都是营业执照 self.data["organizationcode"] = self.data["organizationImg"] self.data["taxregistration"] = self.data["organizationImg"] # 补充一下经办人的函件 if contactName != legalName or contactCardNo != legalCardNo: businessAuthorizationLetter = self.source.get("businessAuthorizationLetter") if not businessAuthorizationLetter: raise JdOpenParamsError(u"参数错误,缺少业务办理授权函") else: self.data["businessAuthorizationLetter"] = businessAuthorizationLetter else: self.data["businessAuthorizationLetter"] = "" def check_company_merchant(self): """ 创建一条公司商户记录 """ # 公司法人的参数校验 legalImgFront = self.source.get("legalImgFront") legalImgBack = self.source.get("legalImgBack") legalName = self.source.get("legalName") legalCardNo = self.source.get("legalCardNo") legalStart = self.source.get("legalStart") legalEnd = self.source.get("legalEnd") legalForever = self.source.get("legalForever") legalProvince = self.source.get("legalProvince") legalCity = self.source.get("legalCity") legalDistrict = self.source.get("legalDistrict") legalAddress = self.source.get("legalAddress") if not legalImgFront: raise JdOpenParamsError(u"参数错误,请上传法人证件正面照") if not legalImgBack: raise JdOpenParamsError(u"参数错误,请上传法人证件反面照") if not legalName: raise JdOpenParamsError(u"参数错误,缺少法人姓名") if not legalCardNo: raise JdOpenParamsError(u"参数错误,缺少法人证件号码") if not self.date_check(legalStart) or not self.date_check(legalEnd): raise JdOpenParamsError(u"参数错误, 法人证件有效期错误") if not all([legalProvince, legalCity, legalDistrict]): raise JdOpenParamsError(u"参数错误,缺少法人地区信息") if not self.area_check(legalProvince): raise JdOpenParamsError(u"参数错误,法人地区 省 信息错误") if not self.area_check(legalCity): raise JdOpenParamsError(u"参数错误, 法人地区 市 信息错误") if not self.area_check(legalDistrict): raise JdOpenParamsError(u"参数错误,法人地区 区 信息错误") if not legalAddress: raise JdOpenParamsError(u"参数错误,缺少商户详细地址") self.data["legalImgFront"] = legalImgFront self.data["legalImgBack"] = legalImgBack self.data["legalName"] = legalName self.data["legalCardNo"] = legalCardNo self.data["legalStart"] = legalStart self.data["legalEnd"] = legalEnd if not legalForever else "forever" self.data["legalProvince"] = legalProvince self.data["legalCity"] = legalCity self.data["legalDistrict"] = legalDistrict self.data["legalAddress"] = legalAddress # 联系人信息的填写 contactImgFront = self.source.get("contactImgFront") contactImgBack = self.source.get("contactImgBack") contactName = self.source.get("contactName") contactCardNo = self.source.get("contactCardNo") contactStart = self.source.get("contactStart") contactEnd = self.source.get("contactEnd") contactForever = self.source.get("contactForever") if not contactImgFront: raise JdOpenParamsError(u"参数错误,请上传联系人证件正面照") if not contactImgBack: raise JdOpenParamsError(u"参数错误,请上传联系人证件反面照") if not contactName: raise JdOpenParamsError(u"参数错误,缺少联系人姓名") if not contactCardNo: raise JdOpenParamsError(u"参数有误,缺少联系人证件号码") if not self.date_check(contactStart) or not self.date_check(contactEnd): raise JdOpenParamsError(u"参数错误, 联系人证件有效期错误") self.data["contactImgFront"] = contactImgFront self.data["contactImgBack"] = contactImgBack self.data["contactName"] = contactName self.data["contactCardNo"] = legalCardNo self.data["contactStart"] = contactCardNo self.data["contactEnd"] = contactEnd if not contactForever else "forever" # 营业执照的参数校验 organizationImg = self.source.get("organizationImg") organizationName = self.source.get("organizationName") organizationNo = self.source.get("organizationNo") organizationStart = self.source.get("organizationStart") organizationEnd = self.source.get("organizationEnd") organizationProvince = self.source.get("organizationProvince") organizationCity = self.source.get("organizationCity") organizationDistrict = self.source.get("organizationDistrict") organizationAddress = self.source.get("organizationAddress") organizationForever = self.source.get("organizationForever") if not organizationImg: raise JdOpenParamsError(u"参数错误,请上传营业执照") if not organizationName: raise JdOpenParamsError(u"参数错误,缺少公司名称") if not organizationNo: raise JdOpenParamsError(u"参数错误,缺少统一信用码") if not self.date_check(organizationStart) or not self.date_check(organizationEnd): raise JdOpenParamsError(u"参数错误, 营业执照有效期填写错误") if not self.area_check(organizationProvince): raise JdOpenParamsError(u"参数错误,营业执照 省 信息错误") if not self.area_check(organizationCity): raise JdOpenParamsError(u"参数错误,营业执照 市 信息错误") if not self.area_check(organizationDistrict): raise JdOpenParamsError(u"参数错误,营业执照 区 信息错误") if not organizationAddress: raise JdOpenParamsError(u"参数错误,缺少营业执照详细地址") self.data["organizationImg"] = organizationImg self.data["organizationName"] = organizationName self.data["organizationNo"] = organizationNo self.data["organizationStart"] = organizationStart self.data["organizationEnd"] = organizationEnd if not organizationForever else "forever" self.data["organizationProvince"] = organizationProvince self.data["organizationCity"] = organizationCity self.data["organizationDistrict"] = organizationDistrict self.data["organizationAddress"] = organizationAddress # 用户填写的结算界面的信息提取 accountType = self.source.get("accountType") bankImg = self.source.get("bankImg") bankCardNo = self.source.get("bankCardNo") bankName = self.source.get("bankName") bankBranchName = self.source.get("bankBranchName") bankProvince = self.source.get("bankProvince") bankCity = self.source.get("bankCity") bankPhone = self.source.get("bankPhone") if not accountType: raise JdOpenParamsError(u"参数错误,请选择账户类型") if not bankImg: raise JdOpenParamsError(u"参数错误,请上传开户许可证图片") if not bankCardNo: raise JdOpenParamsError(u"参数错误,缺少结算账号") if not bankName: raise JdOpenParamsError(u"参数错误,缺少结算银行名称") if not bankBranchName: raise JdOpenParamsError(u"参数错误,缺少结算银行支行名称") if not all([bankProvince, bankCity]): raise JdOpenParamsError(u"参数错误,缺少结算银行地区信息") if not self.area_check(bankProvince) or not self.area_check(bankCity): raise JdOpenParamsError(u"参数错误,结算银行开户地区选择错误") if not bankPhone: raise JdOpenParamsError(u"参数错误,缺少银行卡预留手机号码") self.data["accountType"] = accountType self.data["bankImg"] = bankImg self.data["bankCardNo"] = bankCardNo self.data["bankName"] = bankName self.data["bankBranchName"] = bankBranchName self.data["bankProvince"] = bankProvince self.data["bankCity"] = bankCity self.data["bankPhone"] = bankPhone # 商店照片的信息的获取 shopImgA = self.source.get("shopImgA") shopImgB = self.source.get("shopImgB") shopImgC = self.source.get("shopImgC") if not all([shopImgA, shopImgB, shopImgC]): raise JdOpenParamsError(u"参数错误,缺少营业照片") self.data["shopImgA"] = shopImgA self.data["shopImgB"] = shopImgB self.data["shopImgC"] = shopImgC # 联系人手机号码获取 这个字段的位置不固定 如果是个人 跟随法人信息确认 其余均在联系人地方 phoneNumber = self.source.get("phoneNumber") if not phoneNumber: raise JdOpenParamsError(u"参数错误,缺少联系人手机号码") self.data["phoneNumber"] = phoneNumber # 企业商户的商户全称 为公司名称 self.data["fullName"] = u"{}".format(self.data["organizationName"]) # 企业商户的 组织机构代码 税务登记证 统一社会信用代码 都是营业执照 self.data["organizationcode"] = self.data["organizationImg"] self.data["taxregistration"] = self.data["organizationImg"] self.data["unifiedsocialcreditcode"] = self.data["organizationImg"] # 补充一下经办人的函件 if contactName != legalName or contactCardNo != legalCardNo: businessAuthorizationLetter = self.source.get("businessAuthorizationLetter") if not businessAuthorizationLetter: raise JdOpenParamsError(u"参数错误,缺少业务办理授权函") else: self.data["businessAuthorizationLetter"] = businessAuthorizationLetter else: self.data["businessAuthorizationLetter"] = "" def check_institution_merchant(self): """""" legalImgFront = self.source.get("legalImgFront") legalImgBack = self.source.get("legalImgBack") legalName = self.source.get("legalName") legalCardNo = self.source.get("legalCardNo") legalStart = self.source.get("legalStart") legalEnd = self.source.get("legalEnd") legalForever = self.source.get("legalForever") if not legalImgFront: raise JdOpenParamsError(u"参数错误,请上传法人证件正面照") if not legalImgBack: raise JdOpenParamsError(u"参数错误,请上传法人证件反面照") if not legalName: raise JdOpenParamsError(u"参数错误,缺少法人姓名") if not legalCardNo: raise JdOpenParamsError(u"参数错误,缺少法人证件号码") if not self.date_check(legalStart) or not self.date_check(legalEnd): raise JdOpenParamsError(u"参数错误, 法人证件有效期错误") self.data["legalImgFront"] = legalImgFront self.data["legalImgBack"] = legalImgBack self.data["legalName"] = legalName self.data["legalCardNo"] = legalCardNo self.data["legalStart"] = legalStart self.data["legalEnd"] = legalEnd if not legalForever else "forever" # 联系人信息的填写 contactImgFront = self.source.get("contactImgFront") contactImgBack = self.source.get("contactImgBack") contactName = self.source.get("contactName") contactCardNo = self.source.get("contactCardNo") contactStart = self.source.get("contactStart") contactEnd = self.source.get("contactEnd") contactForever = self.source.get("contactForever") if not contactImgFront: raise JdOpenParamsError(u"参数错误,请上传联系人证件正面照") if not contactImgBack: raise JdOpenParamsError(u"参数错误,请上传联系人证件反面照") if not contactName: raise JdOpenParamsError(u"参数错误,缺少联系人姓名") if not contactCardNo: raise JdOpenParamsError(u"参数有误,缺少联系人证件号码") if not self.date_check(contactStart) or not self.date_check(contactEnd): raise JdOpenParamsError(u"参数错误, 联系人证件有效期错误") self.data["contactImgFront"] = contactImgFront self.data["contactImgBack"] = contactImgBack self.data["contactName"] = contactName self.data["contactCardNo"] = legalCardNo self.data["contactStart"] = contactCardNo self.data["contactEnd"] = contactEnd if not contactForever else "forever" # 营业执照的参数校验 certType = self.source.get("certType") certImg = self.source.get("certImg") certName = self.source.get("certName") certNo = self.source.get("certNo") certStart = self.source.get("certStart") certEnd = self.source.get("certEnd") certProvince = self.source.get("certProvince") certCity = self.source.get("certCity") certDistrict = self.source.get("certDistrict") certAddress = self.source.get("certAddress") certForever = self.source.get("certForever") if not certType: raise JdOpenParamsError(u"参数错误") if not certImg: raise JdOpenParamsError(u"参数错误,请上传证书照片") if not certName: raise JdOpenParamsError(u"参数错误,缺少组织机构名称") if not certNo: raise JdOpenParamsError(u"参数错误,缺少组织机构码") if not self.date_check(certStart) or not self.date_check(certEnd): raise JdOpenParamsError(u"参数错误, 证书有效期填写错误") if not self.area_check(certProvince): raise JdOpenParamsError(u"参数错误,证书地区 省 信息错误") if not self.area_check(certCity): raise JdOpenParamsError(u"参数错误,证书地区 市 信息错误") if not self.area_check(certDistrict): raise JdOpenParamsError(u"参数错误,证书地区 区 信息错误") if not certAddress: raise JdOpenParamsError(u"参数错误,缺少证书详细地址") self.data["certType"] = certType self.data["certImg"] = certImg self.data["certName"] = certName self.data["certNo"] = certNo self.data["certStart"] = certStart self.data["certEnd"] = certEnd if not certForever else "forever" self.data["certProvince"] = certProvince self.data["certCity"] = certCity self.data["certDistrict"] = certDistrict self.data["certAddress"] = certAddress # 用户填写的结算界面的信息提取 accountType = self.source.get("accountType") bankImg = self.source.get("bankImg") bankCardNo = self.source.get("bankCardNo") bankName = self.source.get("bankName") bankBranchName = self.source.get("bankBranchName") bankProvince = self.source.get("bankProvince") bankCity = self.source.get("bankCity") bankPhone = self.source.get("bankPhone") if not accountType: raise JdOpenParamsError(u"参数错误,请选择账户类型") if not bankImg: raise JdOpenParamsError(u"参数错误,请上传开户许可证图片") if not bankCardNo: raise JdOpenParamsError(u"参数错误,缺少结算账号") if not bankName: raise JdOpenParamsError(u"参数错误,缺少结算银行名称") if not bankBranchName: raise JdOpenParamsError(u"参数错误,缺少结算银行支行名称") if not all([bankProvince, bankCity]): raise JdOpenParamsError(u"参数错误,缺少结算银行地区信息") if not self.area_check(bankProvince) or not self.area_check(bankCity): raise JdOpenParamsError(u"参数错误,结算银行开户地区选择错误") if not bankPhone: raise JdOpenParamsError(u"参数错误,缺少银行卡预留手机号码") self.data["accountType"] = accountType self.data["bankImg"] = bankImg self.data["bankCardNo"] = bankCardNo self.data["bankName"] = bankName self.data["bankBranchName"] = bankBranchName self.data["bankProvince"] = bankProvince self.data["bankCity"] = bankCity self.data["bankPhone"] = bankPhone # 商店照片的信息的获取 shopImgA = self.source.get("shopImgA") shopImgB = self.source.get("shopImgB") shopImgC = self.source.get("shopImgC") if not all([shopImgA, shopImgB, shopImgC]): raise JdOpenParamsError(u"参数错误,缺少营业照片") self.data["shopImgA"] = shopImgA self.data["shopImgB"] = shopImgB self.data["shopImgC"] = shopImgC # 联系人手机号码获取 这个字段的位置不固定 如果是个人 跟随法人信息确认 其余均在联系人地方 phoneNumber = self.source.get("phoneNumber") if not phoneNumber: raise JdOpenParamsError(u"参数错误,缺少联系人手机号码") self.data["phoneNumber"] = phoneNumber # 资质信息检查 certificateFile = self.source.get("certificateFile") specialQualification = self.source.get("specialQualification") if not certificateFile: raise JdOpenParamsError(u"参数错误,请上传单位证明函") if not specialQualification: raise JdOpenParamsError(u"参数错误,请上传特殊资质证书") self.data["certificateFile"] = certificateFile self.data["specialQualification"] = specialQualification # 非默认参数的补充 self.data["fullName"] = u"{}".format(self.data["certName"]) # 事业单位的 组织机构代码、税务登记证、统一社会信用代码 就是营业执照(证书) self.data["organizationcode"] = self.data["certImg"] self.data["taxregistration"] = self.data["certImg"] self.data["unifiedsocialcreditcode"] = self.data["certImg"] # 补充一下经办人的函件 if contactName != legalName or contactCardNo != legalCardNo: businessAuthorizationLetter = self.source.get("businessAuthorizationLetter") if not businessAuthorizationLetter: raise JdOpenParamsError(u"参数错误,缺少业务办理授权函") else: self.data["businessAuthorizationLetter"] = businessAuthorizationLetter else: self.data["businessAuthorizationLetter"] = "" class MerchantApplier(object): """ 商户申请 负责维持状态到商户申请完成 包含递交商户资料 对商户申请状态轮询 不负责实名 的任何任务 将实名与商户进行解耦 各自商户申请完成各自实现函数 """ def __init__(self, merchant, client): # type:(Optional[JDOpenApplyInfo, MerchantSourceInfo], Optional[JdPsiMerchantClient, JdOpenMerchantClient]) -> None self._merchant = merchant self._client = client def submit(self): pass def query_audit_result(self): pass class JdPsiMerchantApplier(MerchantApplier): def submit(self): """ 创建商户 """ logger.info("[create_customer] psi merchant <{}>".format(self._merchant)) if not self._merchant: return data = {"agentNo": self._merchant.agentNo} data.update(self._merchant.load_enter_image_info()) data.update(self._merchant.load_enter_entity_info()) try: result = self._client.create_customer(**data) except JdPsiException as je: self._merchant.to_fail(je.errMsg) return merchantNo = result.get("merchantNo") serialNo = result["data"]["serialNo"] self._merchant.enter_success(merchantNo, serialNo) def query_audit_result(self): """ 查询产品的开通状态 产品开通成功的情况下 进行秘钥查询 """ logger.info("[query_audit_result] query ownerId = {}".format(self._merchant.ownerId)) if self._merchant.merchantStatus != int(MerchantStatus.WAITING): return # 将产品码和产品建立关系 方便后续处理 productMap = { self._merchant.products[_name].productId: self._merchant.products[_name] for _name in self._merchant.products } # 发送查询的申请 try: queryInfo = self._merchant.load_query_info() result = self._client.query_product(self._merchant.agentNo, **queryInfo) except JdPsiException as je: # 此处不需要切换失败的状态 等待下一次的轮询即可 logger.error("query error!, record is <{}>, code = {}, error = {}".format(self._merchant.id, je.errCode, je.errMsg)) return # 解析查询的结果 products = result["dataList"] errorMsg = "" # 对每一个返回的产品信息进行轮询 for _item in products: _productId = _item["productNo"] _product = productMap[_productId] status = _item.get("status") if int(status) == ProductStatus.FAIL: logger.error("product fail, record is <{}>, product is <{}>".format(self._merchant.id, _product.productId)) errorMsg = _item.get("resultMsg", "") _product.to_fail() elif int(status) == ProductStatus.SUCCESS or int(status) == ProductStatus.CONFIRM: logger.info("product success, record is <{}>, product is <{}>".format(self._merchant.id, _product.productId)) _product.to_success() else: logger.info("product waiting, record is <{}>, product is <{}>".format(self._merchant.id, _product.productId)) # 商户重载一次 获取真实的产品开通状态 merchant = self._merchant.reload() if merchant.is_product_fail(): return merchant.to_fail(errorMsg) # 如果产品没有完全开通成功 直接退出 等待下一次的轮询 if not merchant.is_product_success(): return desKey, mdKey = self.query_secret() merchant.to_confirm(desKey=desKey, mdKey=mdKey) def query_secret(self): """ 查询秘钥 """ try: queryInfo = self._merchant.load_query_info() result = self._client.query_secret_key(self._merchant.agentNo, **queryInfo) except JdPsiException as je: logger.error("[query_secret] query secret error = {}, code = {}, record = {}".format(je.errMsg, je.errCode, self._merchant.id)) return "", "" desKey, mdKey = result["data"]["desKey"], result["data"]["mdKey"] return desKey, mdKey def create_product(self): if not self._merchant.support_apply(): logger.error("can not find merchant source info!") self._merchant.to_fail(u"不支持开通产品 请联系工作人员协查") return for _name in self._merchant.products: _product = self._merchant.products[_name] # 不符合开通产品条件的产品直接跳过 if not _product.support_apply(): continue # 先将产品的状态切换为等待状态 _product.to_wait() _productInfo = self._merchant.load_product_info(_product) try: self._client.create_product(**_productInfo) except MerchantError as e: # 失败的情况下 切换产品状态为失败 切换商户状态为失败 用户重新提交资料 重新建立初始化状态的产品 _product.to_fail() self._merchant.to_fail(e.message) class JdOpenMerchantApplier(MerchantApplier): def submit(self): """ 新增商户 有可能是新增 或者是修改 """ logger.info("[create_customer] duo_la_bao merchant <{}>".format(self._merchant)) if not self._merchant: return # 抽取公共信息 data = { "agentNum": self._merchant.agentNum, "fullName": self._merchant.fullName, "shortName": self._merchant.shortName, "industry": self._merchant.industry, "province": self._merchant.province, "city": self._merchant.city, "district": self._merchant.district, "customerType": self._merchant.customerType, "certificateType": self._merchant.certificateType, "certificateCode": self._merchant.legalCardNo, "certificateName": self._merchant.legalName, "certificateStartDate": self._merchant.legalStart, "certificateEndDate": self._merchant.legalEnd if self._merchant.legalEnd != "forever" else "", } # 根据商户类型的不同 填充不同的信息 if self._merchant.is_personal: data["linkMan"] = self._merchant.legalName data["linkPhone"] = self._merchant.phoneNumber data["contactPhoneNum"] = self._merchant.phoneNumber data["linkManId"] = self._merchant.legalCardNo elif self._merchant.is_company: data["linkMan"] = self._merchant.contactName data["linkPhone"] = self._merchant.phoneNumber data["contactPhoneNum"] = self._merchant.phoneNumber data["linkManId"] = self._merchant.contactCardNo data["postalAddress"] = self._merchant.organizationAddr elif self._merchant.is_institution: data["linkMan"] = self._merchant.contactName data["linkPhone"] = self._merchant.phoneNumber data["contactPhoneNum"] = self._merchant.phoneNumber data["linkManId"] = self._merchant.contactCardNo data["certType"] = self._merchant.certType data["certNum"] = self._merchant.certNo data["postalAddress"] = self._merchant.certAddr else: data["linkMan"] = self._merchant.contactName data["linkPhone"] = self._merchant.phoneNumber data["contactPhoneNum"] = self._merchant.phoneNumber data["linkManId"] = self._merchant.contactCardNo data["postalAddress"] = self._merchant.organizationAddr # 根据是否已经有商户编号 决定是新增还是修改 try: if not self._merchant.customerNum: result = self._client.customer.create_customer(**data) else: result = self._client.customer.modify_customer(customerNum=self._merchant.customerNum, **data) except JdOpenException as je: logger.error("[create_customer] duo_la_bao merchant <{}> create customer error = {}".format(self._merchant, je)) self._merchant.to_fail(je.message) return logger.info("[create_customer] duo_la_bao merchant <{}> create customer success,result = {}".format(self._merchant, result)) customerNum = result["data"]["customerNum"] return self._merchant.to_customer(customerNum) def query_audit_result(self): pass def create_settle(self): """ 创建结算信息 """ logger.info("[create_settle] duo_la_bao merchant <{}>".format(self._merchant)) if not self._merchant: return data = { "customerNum": self._merchant.customerNum, "bankAccountName": self._merchant.legalName, "bankAccountNum": self._merchant.bankCardNo, "province": self._merchant.bankProvince, "city": self._merchant.bankCity, "bankName": self._merchant.bankName, "bankBranchName": self._merchant.bankBranchName, "settleAmount": self._merchant.settleAmount, "payBankList": [pay.to_dict() for pay in self._merchant.payBankList], "accountType": self._merchant.accountType, "phone": self._merchant.bankPhone } if self._merchant.is_personal: data["accountType"] = self._merchant.accountType data["privateType"] = "PERSON" data["settlerCertificateCode"] = self._merchant.legalCardNo data["settlerCertificateStartDate"] = self._merchant.legalStart data["settlerCertificateEndDate"] = self._merchant.legalEnd if self._merchant.legalEnd != "forever" else "" elif self._merchant.is_company: data["accountType"] = self._merchant.accountType elif self._merchant.is_institution: data["accountType"] = self._merchant.accountType else: data["accountType"] = self._merchant.accountType if self._merchant.accountType == JdOpenAccountType.PRIVATE: data["privateType"] = "INDIVIDUAL" data["settlerCertificateCode"] = self._merchant.legalCardNo data["settlerCertificateStartDate"] = self._merchant.legalStart data["settlerCertificateEndDate"] = self._merchant.legalEnd if self._merchant.legalEnd != "forever" else "" try: if not self._merchant.settleNum: result = self._client.settle.create_account(**data) else: result = self._client.settle.modify_account(settleNum=self._merchant.settleNum, **data) except JdOpenException as je: logger.error("[create_settle] duo_la_bao merchant <{}> create settle error = {}".format(self._merchant, je)) self._merchant.to_fail(je.message) return logger.info("[create_settle] duo_la_bao merchant <{}> create settle success, result = {}".format(self._merchant, result)) settleNum = result["data"]["settleNum"] return self._merchant.to_settle(settleNum) def create_shop(self): logger.info("[create_shop] duo_la_bao merchant <{}>".format(self._merchant)) if not self._merchant: return data = { "agentNum": self._merchant.agentNum, "customerNum": self._merchant.customerNum, "shopName": self._merchant.shortName, "address": self._merchant.merchantAddr, "oneIndustry": self._merchant.industry, "twoIndustry": self._merchant.subIndustry, "mobilePhone": self._merchant.phoneNumber, "mapLng": self._merchant.mapLng, "mapLat": self._merchant.mapLat } # 个人商户的类型暂时定死 if self._merchant.is_personal: data["microBizType"] = "MICRO_TYPE_STORE" try: if not self._merchant.shopNum: result = self._client.shop.create_shop(**data) else: result = self._client.shop.modify_shop(shopNum=self._merchant.shopNum, **data) except JdOpenException as je: logger.error("[create_shop] duo_la_bao merchant <{}> create shop error = {}".format(self._merchant, je)) self._merchant.to_fail(je.message) return logger.info("[create_shop] duo_la_bao merchant <{}> create shop success, result = {}".format(self._merchant, result)) shopNum = result["data"]["shopNum"] return self._merchant.to_shop(shopNum) def upload_attaches(self): logger.info("[update_attach] duo_la_bao merchant <{}>".format(self._merchant)) if not self._merchant: return # 组件公共组件 attaches = { "CASHIERDESK": self._merchant.shopImgA, "SHOP": self._merchant.shopImgB, "IDENTITYDOOR": self._merchant.shopImgC, "IDENTITYFRONT": self._merchant.legalImgFront, "IDENTITYOPPOSITE": self._merchant.legalImgBack } if self._merchant.is_personal: attaches["IDENTIFYHANDHOLD"] = self._merchant.identifyhandhold attaches["BANKFRONT"] = self._merchant.bankImg elif self._merchant.is_company: attaches["PERMIT"] = self._merchant.bankImg attaches["LICENCE"] = self._merchant.organizationImg attaches["ORGANIZATIONCODE"] = self._merchant.organizationcode attaches["TAXREGISTRATION"] = self._merchant.taxregistration attaches["UNIFIEDSOCIALCREDITCODE"] = self._merchant.unifiedsocialcreditcode elif self._merchant.is_institution: attaches["PERMIT"] = self._merchant.bankImg attaches["LICENCE"] = self._merchant.certImg attaches["TAXREGISTRATION"] = self._merchant.taxregistration attaches["ORGANIZATIONCODE"] = self._merchant.organizationcode attaches["UNIFIEDSOCIALCREDITCODE"] = self._merchant.unifiedsocialcreditcode attaches["CERTIFICATE_FILE"] = self._merchant.certificateFile attaches["SPECIAL_QUALIFICATION"] = self._merchant.specialQualification else: if self._merchant.accountType == JdOpenAccountType.PUBLIC: attaches["PERMIT"] = self._merchant.bankImg else: attaches["BANKFRONT"] = self._merchant.bankImg attaches["LICENCE"] = self._merchant.organizationImg attaches["ORGANIZATIONCODE"] = self._merchant.organizationcode attaches["TAXREGISTRATION"] = self._merchant.taxregistration for attachType, img in attaches.items(): # type:(str, Attach) data = { "customerNum": self._merchant.customerNum, "attachType": attachType, "content": base64.b64encode(img.content) } try: if not img.attachNum: result = self._client.attach.upload_attach(**data) else: result = self._client.attach.modify_attach(attachNum=img.attachNum, **data) attachNum = result["data"]["attachNum"] img.upload_success(attachNum) except JdOpenException as je: logger.error("[update_attach] duo_la_bao merchant <{}> update attach <{}> error = {} ".format(self._merchant, attachType, je)) self._merchant.to_fail(je.message) return logger.info("[update_attach] duo_la_bao merchant <{}> update attach <{}> success".format(self._merchant, attachType)) else: return self._merchant.to_attach() def complete(self): logger.info("[complete_merchant] duo_la_bao merchant <{}>".format(self._merchant)) if not self._merchant: return if self._merchant.is_personal: data = { "customerNum": self._merchant.customerNum } elif self._merchant.is_company: data = { "customerNum": self._merchant.customerNum, "licenseId": self._merchant.organizationNo, "licenseStartTime": self._merchant.organizationStart, "licenseEndTime": self._merchant.organizationEnd, } elif self._merchant.is_institution: data = { "customerNum": self._merchant.customerNum, "licenseId": self._merchant.certNo, "licenseStartTime": self._merchant.certStart, "licenseEndTime": self._merchant.certEnd, } else: data = { "customerNum": self._merchant.customerNum, "licenseId": self._merchant.organizationNo, "licenseStartTime": self._merchant.organizationStart, "licenseEndTime": self._merchant.organizationEnd, } try: result = self._client.complete.complete_customer(**data) except JdOpenException as je: logger.error("[complete_merchant] duo_la_bao merchant <{}> complete merchant result error = {} ".format(self._merchant, je)) self._merchant.to_fail(je.message) return logger.info("[complete_merchant] duo_la_bao merchant <{}> complete merchant success ".format(self._merchant)) return self._merchant.to_complete() def confirm(self): logger.info("[confirm_merchant] duo_la_bao merchant <{}>".format(self._merchant)) if not self._merchant: return data = { "agentNum": self._merchant.agentNum, "customerNum": self._merchant.customerNum } try: result = self._client.complete.confirm_customer(**data) except JdOpenException as je: logger.error("[confirm_merchant] duo_la_bao merchant <{}> confirm merchant result error = {} ".format(self._merchant, je)) self._merchant.to_fail(je.message) return logger.info("[confirm_merchant] duo_la_bao merchant <{}> confirm merchant success ".format(self._merchant)) return self._merchant.to_confirm() class MerchantApplyProxy(object): def __init__(self, merchant): # type:(Optional[MerchantSourceInfo, JDOpenApplyInfo]) -> None self.merchant = merchant def submit_data(self): """ 将数据提供到商户方供给审核 """ merchant = self.merchant.reload() # type: Optional[MerchantSourceInfo, JDOpenApplyInfo] if not merchant.support_enter(): logger.error("[MerchantApplyProxy submit_data] not support enter merchant, merchantId = {}".format(self.merchant.id)) return if isinstance(merchant, MerchantSourceInfo): applier = JdPsiMerchantApplier(merchant=merchant, client=get_psi_client()) elif isinstance(merchant, JDOpenApplyInfo): applier = JdOpenMerchantApplier(merchant=merchant, client=get_open_client()) else: logger.error("[MerchantApplyProxy submit_data] not support merchant type, merchantId = {}".format(self.merchant.id)) return return applier.submit() def query_merchant_audit(self): """ 查询商户的审核状态 """ merchant = self.merchant.reload() # type: Optional[MerchantSourceInfo, JDOpenApplyInfo] if not merchant.support_query_audit(): logger.error("[MerchantApplyProxy query_merchant_audit] not support query audit, merchantId = {}".format(self.merchant.id)) return if isinstance(merchant, MerchantSourceInfo): applier = JdPsiMerchantApplier(merchant=merchant, client=get_psi_client()) elif isinstance(merchant, JDOpenApplyInfo): applier = JdOpenMerchantApplier(merchant=merchant, client=get_open_client()) else: logger.error("[MerchantApplyProxy submit_data] not support merchant type, merchantId = {}".format(self.merchant.id)) return # 查询商户的审核状态 如果审核成功 触发 下一步的行为 () return applier.query_audit_result() def submit_auth(self): """ 提交 实名信息 分别向支付宝和微信提交 """ merchant = self.merchant.reload() # type: Optional[MerchantSourceInfo, JDOpenApplyInfo] if not merchant.support_jdaggre(): logger.error("[MerchantApplyProxy submit_auth] not support submit auth, merchantId = {}".format(self.merchant.id)) return # 微信没有申请的 if not merchant.is_wechat_submit: self.submit_wechat() # 支付宝没有提交申请资料的 if not merchant.is_ali_submit: self.submit_ali() # 如果提交都成功了 切换状态 merchant = self.merchant.reload() if all([merchant.is_wechat_submit, merchant.is_ali_submit]): merchant.to_auth_wait() def query_auth_audit(self): """ 查询实名审核的状态 """ wechatResult = self.query_wechat_audit() aliResult = self.query_ali_audit() if all([wechatResult, aliResult]): self.merchant.to_auth_apply_success() def submit_wechat(self): """ 提交微信审核资料 """ # 重载一次 防止状态变更失败 merchant = self.merchant.reload() # type: Optional[MerchantSourceInfo, JDOpenApplyInfo] if isinstance(merchant, MerchantSourceInfo): merchant = update_channels_info(merchant) elif isinstance(merchant, JDOpenApplyInfo): openClient = get_open_client() merchant = query_sub_merchantId(merchant, openClient) else: return wechatProxy = get_wechat_proxy() wxApplier = merchant.wxSource if not wxApplier.subMerchantId: logger.error("[submit_wechat] ownerId = {} no subMerchantId!".format(merchant.ownerId)) return try: result = wechatProxy.submit_merchant(wxApplier) except MerchantError: logger.error("[submit_wechat] ownerId = {} submit error!".format(merchant.ownerId)) return if "applyment_id" in result: applymentId = result["applyment_id"] merchant.to_wx_waiting(applymentId=applymentId) else: merchant.to_fail(result["message"]) def query_wechat_audit(self): """ 查询微信 的审核 """ # 重载一次 防止状态变更失败 merchant = self.merchant.reload() logger.info("[query_wechat_audit] ownerId = {}".format(merchant.ownerId)) # 获取微信服务商 wechatProxy = get_wechat_proxy() wxApplier = merchant.wxSource if not wxApplier.applymentId: logger.error("[query_wechat_audit] ownerId = {} not found applymentId".format(merchant.ownerId)) return try: result = wechatProxy.get_merchant_audit(wxApplier.applymentId) except MerchantError: logger.error("[query_wechat_audit] ownerId = {} query error!".format(merchant.ownerId)) return if "applyment_state" not in result: return False # 审核通过的 if result["applyment_state"] in [ "APPLYMENT_STATE_PASSED", "APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON", "APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT" ]: return True # 审核驳回的 if result["applyment_state"] in ["APPLYMENT_STATE_REJECTED"]: merchant.to_fail(u"【审核驳回】 {}:{}".format(result["reject_param"], result["reject_reason"])) return False def submit_ali(self): """ 提交支付宝的审核资料 """ pass def query_ali_audit(self): """ 阿里暂时全返回为True """ return True