# -*- coding: utf-8 -*- #!/usr/bin/env python import requests from typing import TYPE_CHECKING, Optional import datetime import logging import os import random from django.conf import settings from mongoengine import StringField, EmbeddedDocument, EmbeddedDocumentField, DateTimeField, IntField, MapField, \ BooleanField, LazyReferenceField, EmbeddedDocumentListField from apilib.monetary import JDMerchantPermillage from apps.web.core import ROLE from apps.web.core.db import Searchable, JDMerchantPermillageField from apps.web.core.file import AliOssFileUploader from apps.web.core.models import JDOpenPayApp, CustomerPayRelation, JDAggrePayApp from apps.web.merchant.constant import COMPANY_TYPE, PRIATE_OR_PUBLIC, MerchantStatus, ProductType, ProductStatus, \ ProductRateType, DEFAULT_TRADE_FEE, WechatSubjectType, IdentificationType, CertType, MicroBizType, MERCHANT_OWNER_ROLE, MerchantVersion, MerchantLogAction, ContactType, \ JdOpenMerchantType, JdOpenMerchantStatus from apps.web.merchant.signal import merchant_user_submit, merchant_jd_access, create_customer_success, create_settle_success, create_shop_success, upload_attach_success, \ complete_success, merchant_enter from library.jdopen.constants import OPEN_SECRET_KEY, OPEN_ACCESS_KEY if TYPE_CHECKING: from apps.web.core.bridge.wechat.v3api import WechatApiProxy from apps.web.dealer.models import Dealer from apps.web.agent.models import Agent logger = logging.getLogger(__name__) class MerchantLog(Searchable): """ 商户的日志表 """ merchantId = StringField(verbose_name=u"商户的ID") action = StringField(verbose_name="u操作动作", choices=MerchantLogAction.choices()) dateTimeAdded = DateTimeField(verbose_name=u"操作时间", default=datetime.datetime.now) description = StringField(verbose_name=u"描述") meta = { 'collection': 'merchant_log', 'db_alias': 'logdata' } @classmethod def create_one(cls, merchantId, action, description=""): cls( merchantId=merchantId, action=action, description=description ).save() @classmethod def submit(cls, merchantId, description=""): """ 创建 提交/修改数据完毕 的记录 """ return cls.create_one( merchantId, MerchantLogAction.SUBMIT, str(description) ) @classmethod def add_app(cls, merchantId, description=""): return cls.create_one( merchantId, MerchantLogAction.ADD_JD_APP, str(description) ) @classmethod def change_pay_type(cls, merchantId, description=""): return cls.create_one( merchantId, MerchantLogAction.CHANGE_PAY_APP, str(description) ) @classmethod def submit_wechat(cls, merchantId, description=""): return cls.create_one( merchantId, MerchantLogAction.SUBMIT_WECHAT, str(description) ) @classmethod def submit_ali(cls, merchantId, description=""): return cls.create_one( merchantId, MerchantLogAction.SUBMIT_ALI, str(description) ) @classmethod def auth_apply_success(cls, merchantId, description=""): return cls.create_one( merchantId, MerchantLogAction.AUTH_APPLY_SUCCESS, str(description) ) @classmethod def fail(cls, merchantId, description=""): return cls.create_one( merchantId, MerchantLogAction.FAIL, str(description) ) class MerchantAgent(Searchable): """ 将商户号 和 代理商账号绑定起来 这样方便 代理商收取手续费的时候 直接从相应的网关获取 """ agentNo = StringField(verbose_name="商户号的服务商商户号") agentId = StringField(verbose_name="服务商的agentId", default="") agentSystemId = StringField(verbose_name="服务商的systemId", default="") dateTimeAdded = DateTimeField(verbose_name="添加进来的时间") def __str__(self): return self.agentNo @classmethod def get_agent_id(cls, agentSystemId): merchantAgent = cls.objects.filter(agentSystemId=agentSystemId).first() or cls() return merchantAgent.agentId @classmethod def default_merchant_agent(cls): wflSystemId = os.environ.get("JD_SYSTEM_ID") or "112122276PSP" return cls.objects.filter(agentSystemId=wflSystemId).first() class LadderList(EmbeddedDocument): type = StringField(default="1") minVal = StringField(default="0") maxVal = StringField(default="1000") cardType = StringField(default="DE") fee = JDMerchantPermillageField(default=JDMerchantPermillage(DEFAULT_TRADE_FEE)) maxfee = StringField("1000000") def to_dict(self): return { "type": self.type, "minVal": self.minVal, "maxVal": self.maxVal, "cardType": self.cardType, "fee": self.fee, "maxfee": self.maxfee } class MerchantProduct(EmbeddedDocument): productId = StringField(verbose_name=u"产品编码", choices=ProductType.choices()) status = IntField(verbose_name=u"产品的开通状态", choices=ProductStatus.choices(), default=ProductStatus.INIT) rateType = StringField(verbose_name=u"产品的费率类型", choices=ProductRateType.choices(), default=ProductRateType.PERCENTAGE) mfee = JDMerchantPermillageField(verbose_name=u"产品的费率 一般就是之前经销商的提现的费率 由代理商设置 需要注意的是发送给金东的时候 单位是100%", default=JDMerchantPermillage(6)) payToolId = StringField(verbose_name=u"支付工具的ID 固定值", default="0") # ladderList = ListField(verbose_name = u'京东的固定的费率(只有当产品id是403的时候这个字段才有用)') ladderList = EmbeddedDocumentField(verbose_name = u'京东的固定的费率(只有当产品id是403的时候这个字段才有用)', document_type=LadderList) def support_apply(self): """ 产品是否支持开通 主要看状态 初始化的产品可以开通 """ return self.status == ProductStatus.INIT def to_wait(self): self.status = ProductStatus.WAITING self.save() def to_fail(self): self.status = ProductStatus.FAIL self.save() def to_success(self): self.status = ProductStatus.SUCCESS self.save() @classmethod def created_product(cls, productId, mfee): product = cls(productId=productId) product.mfee = mfee # jd 的支付方式 加上费率阶梯 if product.productId == ProductType.JD: ladderMap = LadderList() ladderMap.fee = mfee product.ladderList = ladderMap return product class MerchantAddress(Searchable): name = StringField(verbose_name=u"行政区名称", required=True) code = StringField(verbose_name=u"行政区代码", required=True) parentCode = StringField(verbose_name=u"父级code") def to_dict(self): result = { "name": self.name, "code": self.code, } if self.parentCode != "000000": result.update({"parentCode": self.parentCode}) return result @classmethod def get_name(cls, code): record = cls.objects.filter(code=code).first() return record.name if record else "" @classmethod def get_all(cls): return [_addr.to_dict() for _addr in cls.objects.all()] @classmethod def get_addr_by_parent(cls, parentCode=None): if parentCode is None: parentCode = "000000" return [_addr.to_dict() for _addr in cls.objects.filter(parentCode=parentCode)] @classmethod def get_provide_code(cls, provinceName): """ 获取省级code """ try: province = cls.objects.get(name=provinceName, parentCode="000000") # type: MerchantAddress except Exception as e: logger.error("get province <{}> code error = {}".format(provinceName, e)) return "" return province.code @classmethod def get_city_code(cls, cityName, provinceCode): try: city = cls.objects.get(name=cityName, parentCode=provinceCode) # type: MerchantAddress except Exception as e: logger.error("get province <{}> city <{}> code error = {}".format(provinceCode, cityName, e)) return "" return city.code @classmethod def get_area_code(cls, areaName, cityCode): try: area = cls.objects.get(name=areaName, parentCode=cityCode) # type: MerchantAddress except Exception as e: logger.error("get city <{}> area <{}> code error = {}".format(cityCode, areaName, e)) return "" return area.code class WxMerchantAddress(Searchable): name = StringField(verbose_name=u"地址") code = StringField(verbose_name=u"编码") @classmethod def get_code(cls, name): try: return cls.objects.get(name=name).code except Exception: return "440305" # 营业执照信息 class BusinessLicenceInfo(EmbeddedDocument): """营业执照""" licenceNumber = StringField(verbose_name=u"营业执照注册号") licenceCopy = StringField(verbose_name=u"营业执照照片URL") merchantName = StringField(verbose_name=u"商户简称") legalPerson = StringField(verbose_name=u"法人姓名") companyAddress = StringField(verbose_name=u"注册地址") licenceStart = StringField(verbose_name=u"营业执照起始日期") licenceEnd = StringField(verbose_name=u"营业执照结束日期") def to_apply(self, server): # type:(WechatApiProxy) -> dict licenceCopy = AliOssFileUploader.load(self.licenceCopy) response = server.upload_image(licenceCopy, os.path.basename(self.licenceCopy)) return { "licence_number": self.licenceNumber, "licence_copy": response.get("media_id", ""), "merchant_name": self.merchantName, "legal_person": self.legalPerson, "company_address": self.companyAddress, "licence_valid_date": '["{}","{}"]'.format(self.licenceStart, self.licenceEnd), } def save_certificate_info(self, businessLicenceInfo): self.licenceNumber = businessLicenceInfo["busCode"] self.licenceCopy = businessLicenceInfo["busLicenseUrl"] self.merchantName = businessLicenceInfo["busName"] self.legalPerson = businessLicenceInfo["busLegal"] self.companyAddress = "{}{}{}{}".format( businessLicenceInfo["province"]["name"], businessLicenceInfo["city"]["name"], businessLicenceInfo["area"]["name"], businessLicenceInfo["addr"], ) self.licenceStart = businessLicenceInfo["startTime"] self.licenceEnd = businessLicenceInfo["endTime"] # 登记证书信息 class CertificateInfo(EmbeddedDocument): """登记证书""" certType = StringField(verbose_name=u"登记证书类型", choices=CertType.choices()) certNumber = StringField(verbose_name=u"证书编号") certCopy = StringField(verbose_name=u"证书的照片URL") merchantName = StringField(verbose_name=u"商户简称") legalPerson = StringField(verbose_name=u"法人姓名") companyAddress = StringField(verbose_name=u"注册地址") certStart = StringField(verbose_name=u"证书起始日期") certEnd = StringField(verbose_name=u"证书结束日期") def to_apply(self, server): # type:(WechatApiProxy) -> dict certCopy = AliOssFileUploader.load(self.certCopy) response = server.upload_image(certCopy, os.path.basename(self.certCopy)) return { "cert_type": self.certType, "cert_number": self.certNumber, "cert_copy": response.get("media_id", ""), "merchant_name": self.merchantName, "legal_person": self.legalPerson, "company_address": self.companyAddress, "cert_valid_date": '["{}","{}"]'.format(self.certStart, self.certEnd), } # 辅助材料信息 class AssistProveInfo(EmbeddedDocument): """辅助材料证明""" microBizType = StringField(verbose_name=u"小微商户类型", default=MicroBizType.MICRO_TYPE_STORE.code, choices=MicroBizType.choices()) storeName = StringField(verbose_name=u"门店名称") # 省市县 以,分割 storeAddressCode = StringField(verbose_name=u"门店的地址的code") storeAddress = StringField(verbose_name=u"门店的地址 具体区、街道") storeHeaderCopy = StringField(verbose_name=u"门头照") storeIndoorCopy = StringField(verbose_name=u"门内照") @staticmethod def load_addr_code(p, c, a): return WxMerchantAddress.get_code("{}{}{}".format(p, c, a)) def to_apply(self, server): # type:(WechatApiProxy) -> dict storeHeaderCopy = AliOssFileUploader.load(self.storeHeaderCopy) responseHeader = server.upload_image(storeHeaderCopy, os.path.basename(self.storeHeaderCopy)) storeIndoorCopy = AliOssFileUploader.load(self.storeIndoorCopy) responseIndoor = server.upload_image(storeIndoorCopy, os.path.basename(self.storeIndoorCopy)) return { "micro_biz_type": self.microBizType, "store_name": self.storeName, "store_address_code": self.storeAddressCode, "store_address": self.storeAddress, "store_header_copy": responseHeader.get("media_id"), "store_indoor_copy": responseIndoor.get("media_id") } def save_certificate_info(self, assistProveInfo): self.storeName = assistProveInfo["storeShotName"] self.storeHeaderCopy = assistProveInfo["storeAUrl"] self.storeIndoorCopy = assistProveInfo["storeBUrl"] province = assistProveInfo["province"]["name"] city = assistProveInfo["city"]["name"] area = assistProveInfo["area"]["name"] self.storeAddress = assistProveInfo["addr"] self.storeAddressCode = self.load_addr_code(province, city, area) return self # 法人相关信息 class LegalPersonInfo(EmbeddedDocument): """ 法人信息 """ mainType = StringField(verbose_name=u"法人证件类型(目前仅支持身份证)", default=IdentificationType.IDENTIFICATION_TYPE_IDCARD.code, choices=IdentificationType.choices()) lepName = StringField(verbose_name=u"法人姓名") lepCardNo = StringField(verbose_name=u"法人身份证号") lepCardStart = StringField(verbose_name=u"法人身份证起始日期") lepCardEnd = StringField(verbose_name=u"法人身份证结束日期") lepCardUrlA = StringField(verbose_name=u"法人身份证人像面") lepCardUrlB = StringField(verbose_name=u"法人身份证国徽面") # 以下都是不需要的 lepProvinceCode = StringField(verbose_name=u"法人身份证 省CODE") lepCityCode = StringField(verbose_name=u"法人身份证 市CODE") lepAreaCode = StringField(verbose_name=u"法人身份证 区CODE") lepProvince = StringField(verbose_name=u"法人身份证 省") lepCity = StringField(verbose_name=u"法人身份证 市") lepArea = StringField(verbose_name=u"法人身份证 区") lepAddr = StringField(verbose_name=u"法人地址 详细") def to_apply(self, server): # type:(WechatApiProxy) -> dict """ 法人的有三个信息需要加密处理 两个图片信息需要上传处理 """ # 上传图片 并获取其中的 media_id lepCardContentA = AliOssFileUploader.load(self.lepCardUrlA) responseA = server.upload_image(lepCardContentA, os.path.basename(self.lepCardUrlA)) lepCardContentB = AliOssFileUploader.load(self.lepCardUrlB) responseB = server.upload_image(lepCardContentB, os.path.basename(self.lepCardUrlB)) return { "identification_type": self.mainType, "identification_name": server.rsa_encrypt(self.lepName), "identification_number": server.rsa_encrypt(self.lepCardNo), "identification_address": server.rsa_encrypt("{}{}{}{}".format(self.lepProvince, self.lepCity, self.lepArea, self.lepAddr)), "identification_valid_date": '["{}","{}"]'.format(self.lepCardStart, self.lepCardEnd), "identification_front_copy": responseA.get("media_id", ""), "identification_back_copy": responseB.get("media_id", ""), "owner": True } def save_certificate_info(self, legalInfo): self.lepName = legalInfo["name"] self.lepCardNo = legalInfo["cardNo"] self.lepCardStart = legalInfo["startTime"] self.lepCardEnd = legalInfo["endTime"] self.lepCardUrlA = legalInfo["urlA"] self.lepCardUrlB = legalInfo["urlB"] self.lepProvinceCode = legalInfo["province"]["code"] self.lepCityCode = legalInfo["city"]["code"] self.lepAreaCode = legalInfo["area"]["code"] self.lepProvince = legalInfo["province"]["name"] self.lepCity = legalInfo["city"]["name"] self.lepArea = legalInfo["area"]["name"] self.lepAddr = legalInfo["addr"] return self # 经营主体相关信息 class SubjectInfo(EmbeddedDocument): """ 主体信息 最为关键的信息 主要是种类繁多 根据主体的类型会有变化 """ mainType = StringField(verbose_name=u"主体的类型", choices=WechatSubjectType.choices()) businessLicenceInfo = EmbeddedDocumentField(verbose_name="营业执照信息" ,document_type=BusinessLicenceInfo) certificateInfo = EmbeddedDocumentField(verbose_name=u"登记证书信息", document_type=CertificateInfo) companyProveCopy = StringField(verbose_name=u"单位证明函照片") assistProveInfo = EmbeddedDocumentField(verbose_name=u"辅助材料证明", document_type=AssistProveInfo) def to_apply(self, server): # type:(WechatApiProxy) -> dict data = { "subject_type": self.mainType, } # 存在营业执照信息 企业类型 if self.businessLicenceInfo: data["business_licence_info"] = self.businessLicenceInfo.to_apply(server) # 登记证书 事业单位和其他组织都需要 if self.certificateInfo: data["certificate_info"] = self.certificateInfo.to_apply(server) # 事业单位必带 if self.companyProveCopy: companyProveCopy = AliOssFileUploader.load(self.companyProveCopy) response = server.upload_image(companyProveCopy, os.path.basename(self.companyProveCopy)) data["company_prove_copy"] = response.get("media_id", "") # 小微企业必须有 if self.assistProveInfo: data["assist_prove_info"] = self.assistProveInfo.to_apply(server) return data def save_certificate_info(self, businessLicenceInfo=None, certificateInfo=None, companyProveCopy=None, assistProveInfo=None): if businessLicenceInfo: self.businessLicenceInfo = self.businessLicenceInfo or BusinessLicenceInfo() return self.businessLicenceInfo.save_certificate_info(businessLicenceInfo) elif certificateInfo: self.certificateInfo = self.certificateInfo or CertificateInfo() return self.certificateInfo.save_certificate_info(certificateInfo) elif companyProveCopy: self.companyProveCopy = companyProveCopy else: self.assistProveInfo = self.assistProveInfo or AssistProveInfo() return self.assistProveInfo.save_certificate_info(assistProveInfo) # 联系人相关信息 class ContactPersonInfo(EmbeddedDocument): """ 联系人信息 """ mainType = StringField(verbose_name=u"联系人证件类型(目前仅支持身份证)", default=IdentificationType.IDENTIFICATION_TYPE_IDCARD.code, choices=IdentificationType.choices()) contactType = StringField(verbose_name=u"联系人的类型", choices=ContactType.choices(), default=ContactType.LEGAL.code) businessAuthorizationLetter = StringField(verbose_name="业务办理授权函", default="") contactName = StringField(verbose_name=u"联系人姓名") contactMobile = StringField(verbose_name=u"联系人手机号") contactCardNo = StringField(verbose_name=u"联系人身份证号") # 以下四个信息是保存供显示 并不发送到微信 contactCardStart = StringField(verbose_name=u"联系人身份证起始日期") contactCardEnd = StringField(verbose_name=u"联系人身份证结束日期") contactCardUrlA = StringField(verbose_name=u"联系人身份证人像面") contactCardUrlB = StringField(verbose_name=u"联系人身份证国徽面") contactProvinceCode = StringField(verbose_name=u"联系人身份证 省CODE") contactCityCode = StringField(verbose_name=u"联系人身份证 市CODE") contactAreaCode = StringField(verbose_name=u"联系人身份证 区CODE") contactProvince = StringField(verbose_name=u"联系人身份证 省") contactCity = StringField(verbose_name=u"联系人身份证 市") contactArea = StringField(verbose_name=u"联系人身份证 区") contactAddr = StringField(verbose_name=u"联系人地址 详细") def to_apply(self, server): # type:(WechatApiProxy) -> dict """ 联系人的三个信息都需要加密进行处理 """ baseData = { "contact_type": str(self.contactType), "name": server.rsa_encrypt(self.contactName), "mobile": server.rsa_encrypt(self.contactMobile), "id_card_number": server.rsa_encrypt(self.contactCardNo) } if self.contactType == ContactType.SUPER: baseData["contact_id_doc_type"] = str(self.mainType) baseData["contact_id_doc_copy"] = server.upload_image_from_oss(self.contactCardUrlA).get("media_id", "") baseData["contact_id_doc_copy_back"] = server.upload_image_from_oss(self.contactCardUrlB).get("media_id", "") baseData["contact_period_begin"] = self.contactCardStart baseData["contact_period_end"] = self.contactCardEnd baseData["business_authorization_letter"] = server.upload_image_from_oss(self.businessAuthorizationLetter).get("media_id", "") return baseData def save_certificate_info(self, contactInfo): self.contactType = contactInfo["contactType"] self.businessAuthorizationLetter = contactInfo["businessAuthorizationLetter"] self.contactName = contactInfo["name"] self.contactCardNo = contactInfo["cardNo"] self.contactCardStart = contactInfo["startTime"] self.contactCardEnd = contactInfo["endTime"] self.contactCardUrlA = contactInfo["urlA"] self.contactCardUrlB = contactInfo["urlB"] self.contactProvinceCode = contactInfo["province"]["code"] self.contactCityCode = contactInfo["city"]["code"] self.contactAreaCode = contactInfo["area"]["code"] self.contactProvince = contactInfo["province"]["name"] self.contactCity = contactInfo["city"]["name"] self.contactArea = contactInfo["area"]["name"] self.contactAddr = contactInfo["addr"] return self def save_mobile_info(self, mobile): self.contactMobile = mobile return self # 商户的实名申请信息 class WechatApplyMerchant(Searchable): """ 微信侧申请商户号所需要的资料 """ # 原始的资料信息 contactInfo = EmbeddedDocumentField(verbose_name = u"联系人信息", document_type = ContactPersonInfo, default=ContactPersonInfo) legalInfo = EmbeddedDocumentField(verbose_name = u"法人信息", document_type = LegalPersonInfo, default=LegalPersonInfo) subjectInfo = EmbeddedDocumentField(verbose_name = u"经营主体信息", document_type = SubjectInfo, default=SubjectInfo) # 微信的业务申请信息 channelId = StringField(verbose_name=u"渠道商户号") subMerchantId = StringField(verbose_name=u"微信子商户编号") applymentId = StringField(verbose_name=u"申请的ID") businessCode = StringField(verbose_name=u"业务申请编号") # 支付宝的业务申请信息 subAliMerchantId = StringField(verbose_name=u"支付宝的子商编") aliApplymentId = StringField(verbose_name=u"支付宝的申请编号") aliBusinessCode = StringField(verbose_name=u"支付宝的业务编号") def update_sub_merchant(self, **kwargs): if "channel" in kwargs: self.channelId = kwargs["channel"] if "subMchId" in kwargs: self.subMerchantId = kwargs["subMchId"] if "subCustomerNum" in kwargs: self.subAliMerchantId = kwargs["subCustomerNum"] return self.save() def to_apply(self, server): # type:(WechatApiProxy) -> dict # 申请的时候 申请单编号刷新 business_code = "{}_{}_{}".format(self.channelId, self.subMerchantId, datetime.datetime.now().strftime("%Y%m%d%H%M%S")) self.businessCode = business_code self.save() # 获取联系人类型 小微商户和个人卖家 则联系人类型为法人;其余的 可选法人 或 经办人 if self.subjectInfo.mainType == WechatSubjectType.SUBJECT_TYPE_MICRO: contact_type = "LEGAL" else: if self.contactInfo.contactCardNo == self.legalInfo.lepCardNo: contact_type = "LEGAL" else: contact_type = "SUPER" # 根据联系人的类型 决定上传数据的不同 if contact_type == "LEGAL": contact_info = { "contact_type": contact_type, "name": server.rsa_encrypt(self.contactInfo.contactName), "mobile": server.rsa_encrypt(self.contactInfo.contactMobile), "id_card_number": server.rsa_encrypt(self.contactInfo.contactCardNo) } else: contact_info = { "contact_type": contact_type, "name": server.rsa_encrypt(self.contactInfo.contactName), "contact_id_doc_type": IdentificationType.IDENTIFICATION_TYPE_IDCARD.code, "id_card_number": server.rsa_encrypt(self.contactInfo.contactCardNo), "contact_id_doc_copy": server.upload_image_from_oss(self.contactInfo.contactCardUrlA).get("media_id", ""), "contact_id_doc_copy_back": server.upload_image_from_oss(self.contactInfo.contactCardUrlB).get("media_id", ""), "contact_period_begin": self.contactInfo.contactCardStart, "contact_period_end": self.contactInfo.contactCardEnd, "business_authorization_letter": server.upload_image_from_oss(self.contactInfo.businessAuthorizationLetter).get("media_id", ""), "mobile": server.rsa_encrypt(self.contactInfo.contactMobile) } return { "channel_id": self.channelId, "business_code": business_code, "contact_info": contact_info, "subject_info": self.subjectInfo.to_apply(server), "identification_info": self.legalInfo.to_apply(server), "addition_info": { "confirm_mchid_list": [self.subMerchantId] } } def to_ali_submit(self, applymentId, businessCode=""): self.aliApplymentId = str(applymentId) if businessCode: self.aliBusinessCode = businessCode return self.save() def to_wechat_submit(self, applymentId, businessCode=""): self.applymentId = str(applymentId) if businessCode: self.businessCode = businessCode return self.save() def to_success(self, applymentId, businessCode=""): """ 申请成功之后 写入申请单的编号 """ def to_cancel(self): """ 取消申请单成功后 将此次申请的参数全部清除 """ self.applymentId = "" self.businessCode = "" return self.save() # 京东商户申请所需信息 class MerchantSourceInfo(Searchable): """ 京东申请所需要的材料 """ ownerId = StringField(verbose_name=u"商户拥有者的ID") ownerRole = StringField(verbose_name=u"商户拥有者身份", choices=MERCHANT_OWNER_ROLE.choices(), default=MERCHANT_OWNER_ROLE.DEALER) merchantAgent = LazyReferenceField(verbose_name="商户号的服务商", document_type=MerchantAgent ) serial_no = StringField(verbose_name=u"订单流水号") merchantNo = StringField(verbose_name=u"商户号") desKey = StringField(verbose_name=u"商户密钥") mdKey = StringField(verbose_name=u"商户md") status = IntField(verbose_name=u"商户的状态", choices=MerchantStatus.choices(), default=MerchantStatus.INIT) merchantType = StringField(verbose_name=u"商户性质", choices=COMPANY_TYPE.choices()) errorDescription = StringField(verbose_name=u"失败原因", default="") dateTimeAdded = DateTimeField(verbose_name=u"创建时间") dateTimeUpdated = DateTimeField(verbose_name=u"状态更新时间") # 版本信息 用于控制兼容代码 version = StringField(verbose_name=u"商户版本信息", default=None) # 法人信息 identifyCardAUrl = StringField(verbose_name=u"法人证件(人像)") identifyCardBUrl = StringField(verbose_name=u"法人证件(国徽)") identifyCardCUrl = StringField(verbose_name=u"法人证件(手持)") identifyCardName = StringField(verbose_name=u"法人证件 姓名") identifyCardCode = StringField(verbose_name=u"法人证件 号码") identifyCardStartTime = StringField(verbose_name=u"法人证件 起始日期") identifyCardEndTime = StringField(verbose_name=u"法人证件 结束日期") identifyCardLongTime = BooleanField(verbose_name=u"法人证件 是否是长期") identifyCardProvinceCode = StringField(verbose_name="法人 省CODE") identifyCardCityCode = StringField(verbose_name=u"法人 市CODE") identifyCardAreaCode = StringField(verbose_name=u"法人 区CODE") identifyCardProvince = StringField(verbose_name=u"法人 省 ") identifyCardCity = StringField(verbose_name=u"法人 市") identifyCardArea = StringField(verbose_name=u"法人 区") identifyCardAddr = StringField(verbose_name=u"法人 详细地址") # 联系人信息 contactPersonName = StringField(verbose_name=u"联系人 姓名") contactPersonPhone = StringField(verbose_name=u"联系人 手机") contactPersonEmail = StringField(verbose_name="联系人 邮箱") # 营业执照相关的信息 当商户为企业的时候存在 busLicenseUrl = StringField(verbose_name=u"企业的营业执照") busName = StringField(verbose_name=u"企业名称") busCode = StringField(verbose_name=u"营业执照统一社会信用码") busProvinceCode = StringField(verbose_name=u"营业地址所在省code") busCityCode = StringField(verbose_name=u"营业地址所在市code") busAreaCode = StringField(verbose_name=u"营业地址所在区code") busProvince = StringField(verbose_name=u"营业地址所在省") busCity = StringField(verbose_name=u"营业地址所在市") busArea = StringField(verbose_name=u"营业地址所在区") busAddr = StringField(verbose_name=u"营业地址") # 结算的相关信息 bankCardUrl = StringField(verbose_name=u"银行卡/开户许可证") bankCardCode = StringField(verbose_name=u"银行卡/开户许可证 名称") bankCardName = StringField(verbose_name=u"银行卡/开户许可证 开户行") bankCardSubCode = StringField(verbose_name=u"银行卡/开户许可证 支行CODE") bankCardSubName = StringField(verbose_name=u"银行卡/开户许可证 支行名称") # 经营的相关信息 storeShotName = StringField(verbose_name=u"门店简称") storeAUrl = StringField(verbose_name=u"门店的照片 门头照") storeBUrl = StringField(verbose_name=u"门店的照片 出入口") storeCUrl = StringField(verbose_name=u"门店的照片 店内") shopProvinceCode = StringField(verbose_name=u"门店所在省code") shopCityCode = StringField(verbose_name=u"门店所在市code") shopAreaCode = StringField(verbose_name=u"门店所在地区code") shopProvince = StringField(verbose_name=u"门店所在省") shopCity = StringField(verbose_name=u"门店所在市") shopArea = StringField(verbose_name=u"门店所在地区") shopAddr = StringField(verbose_name=u"商户所在详细地址") products = MapField(EmbeddedDocumentField(verbose_name=u"开通的支付产品", document_type=MerchantProduct)) regEmail = StringField(verbose_name=u"注册邮箱号. 也这个作为商户登录账号") wxApplier = LazyReferenceField(verbose_name=u"微信申请的信息", document_type= WechatApplyMerchant) def __repr__(self): return "Merchant Source Info <{}>".format(self.id) def load_enter_image_info(self): """ 加载 商户入驻所需要的图片信息 :return: """ result = dict() # 营业执照的照片 result['blicUrla'] = self.blicUrla # 如果是企业用户 还需要上传银行开户许可证的照片 if self.companyType == COMPANY_TYPE.ENTERPRISE: result['occUrla'] = self.occUrla # 身份证的照片 result['lepUrla'] = self.lepUrla result['lepUrlb'] = self.lepUrlb result['lepUrlc'] = self.lepUrlc # 门店的照片 result['img'] = self.img result['enterimg'] = self.enterimg result['innerimg'] = self.innerimg # 结算类照片 result['cardPhoto'] = self.cardPhoto result['settleManPhotoFront'] = self.settleManPhotoFront result['settleManPhotoBack'] = self.settleManPhotoBack result['settleHoldingIDCard'] = self.settleHoldingIDCard return result def load_enter_entity_info(self): """ 加载商户进件所需要的 entity的信息 :return: """ result = dict() # 首先添加公共类信息 即必传递的信息 result['companyType'] = self.companyType result['serialNo'] = self.serialNo result['agentNo'] = self.agentNo result['regEmail'] = self.regEmail result['regPhone'] = self.regPhone result['blicCardType'] = self.blicCardType result['blicCompanyName'] = self.blicCompanyName result['abMerchantName'] = self.abMerchantName # 企业商户需要增加的部分信息 if self.companyType == COMPANY_TYPE.ENTERPRISE: result['blicUscc'] = self.blicUscc result['blicScope'] = self.blicScope result['indTwoCode'] = self.indTwoCode result['blicProvince'] = self.blicProvince result['blicCity'] = self.blicCity result['blicAddress'] = self.blicAddress result['blicLongTerm'] = self.blicLongTerm result['blicValidityStart'] = self.blicValidityStart result['blicValidityEnd'] = self.blicValidityEnd result['lepCardType'] = self.lepCardType result['lepName'] = self.lepName result['lepCardNo'] = self.lepCardNo result['lepLongTerm'] = self.lepLongTerm result['lepValidityStart'] = self.lepValidityStart result['lepValidityEnd'] = self.lepValidityEnd result['contactName'] = self.contactName result['contactPhone'] = self.contactPhone result['contactEmail'] = self.contactEmail result['contactProvince'] = self.contactProvince result['contactCity'] = self.contactCity result['contactAddress'] = self.contactAddress result['ifPhyStore'] = self.ifPhyStore result['storeProvince'] = self.storeProvince result['storeCity'] = self.storeCity result['storeAddress'] = self.storeAddress result['settleToCard'] = self.settleToCard result['priatePublic'] = self.priatePublic result['bankName'] = self.bankName result['subBankCode'] = self.subBankCode result['bankAccountNo'] = self.bankAccountNo result['bankAccountName'] = self.bankAccountName result['settleCardPhone'] = self.settleCardPhone result['settlementPeriod'] = self.settlementPeriod result['directoryList'] = self.directoryList # 如果存在商户的商户号 说明是修改了 if self.merchantNo: result['merchantNo'] = self.merchantNo return result def load_product_info(self, product): """ 加载京东产品申请的产品信息 :return: """ serialNo = self.generate_serial_no(self.ownerId) result = { "agentNo": self.agentNo, "merchantNo": self.merchantNo, "serialNo": serialNo, "productId": product.productId, "payToolId": product.payToolId, "mfeeType": product.rateType, } if product.productId in [ProductType.WECHAT, ProductType.ALIPAY]: result.update({"mfee": product.mfee}) elif product.productId in [ProductType.JD]: result.update({"ladderList": [product.ladderList.to_dict()]}) return result def load_query_info(self): """ 获取查询 京东商户的 条件信息 :return: """ serialNo = self.generate_serial_no(self.ownerId) result = { "serialNo": serialNo, "merchantNo": self.merchantNo, } return result @staticmethod def load_address_name(code): return MerchantAddress.get_name(code) def add_product(self, productType): """ 初始化微信和支付宝两个产品 wechat alipay 再加上一个 京东的 """ productId = getattr(ProductType, productType.upper(), None) assert productId in ProductType.choices(), u"不支持的产品类型" product = self.products.get(productType) if product and product.status != ProductStatus.FAIL: return # 费率固定为 千分之6 mfee = JDMerchantPermillage(DEFAULT_TRADE_FEE) self.products[productType] = MerchantProduct.created_product( productId=productId, mfee=mfee ) def is_product_fail(self): """ 产品有无开通失败的 """ return any(map(lambda x: x.status == ProductStatus.FAIL, self.products.values())) def is_product_success(self): """ 产品是否均开通成功 """ return all(map(lambda x: x.status == ProductStatus.SUCCESS, self.products.values())) def enter_success(self, merchantNo, serialNo): """ 将商户申请状态切换为 等待 同时初始化 支付产品 """ # 修改的时候不会有 merchantNo if merchantNo: self.merchantNo = merchantNo if serialNo: self.serial_no = serialNo self.errorDescription = "" self.add_product("wechat") self.add_product("alipay") self.add_product("jd") # 重置错误信息 self.save() merchant_enter.send(sender=self.__class__, merchantId=str(self.id)) return self def support_apply(self): """ 是否支持 开通商户产品 """ if self.status != MerchantStatus.WAITING: return False if not self.products: return False return True @staticmethod def load_image_content(url): """ 获取图像的二进制数据 :return: """ return AliOssFileUploader.load(url) @staticmethod def generate_serial_no(ownerId): return "{}{}{}".format(datetime.datetime.now().strftime("%Y%m%d%H%M%S"), ownerId, random.randint(1000, 9999)).upper() @staticmethod def trans_merchant_type(merchantType): """转换京东进件的类型""" # 个人商户 if merchantType == "SUBJECT_TYPE_MICRO": return COMPANY_TYPE.NORMAL_PERSON # 企业商户 return COMPANY_TYPE.ENTERPRISE @staticmethod def trans_end_time(endTime): if endTime == "forever": return u"长期" return endTime @classmethod def get_source_record(cls, owner): # type:(Optional[Agent, Dealer]) -> MerchantSourceInfo """ 获取原始的申请记录 """ _owner = owner.merchantRegister return cls.objects.filter(ownerId=str(_owner.id), ownerRole=str(_owner.role)).first() or cls(ownerId=str(_owner.id), ownerRole=str(_owner.role)) @property def owner(self): """ 做一次缓存 防止频繁访问数据库 """ if hasattr(self, "_owner"): return self._owner owner = ROLE.from_role_id(self.ownerRole, self.ownerId) setattr(self, "_owner", owner) return owner @property def agentNo(self): """服务商 修改为 和我们系统的agent绑定""" merchantAgent = self.merchantAgent.fetch() return merchantAgent.agentNo # 照片信息类 @property def blicUrla(self): """ 营业执照的照片 文档规定 自然人的情况下 营业执照传递合同租凭 和对方技术人员沟通 这个地方可以就传身份证件 :return: """ url = self.busLicenseUrl if self.companyType == COMPANY_TYPE.NORMAL_PERSON: url = self.identifyCardAUrl return self.load_image_content(url) @property def occUrla(self): """ 银行开户许可证 非必传选项 当商户类型为企业的时候必传递 沟通就传递营业执照 :return: """ return self.load_image_content(self.busLicenseUrl) @property def blicObaUrla(self): """ 税字号图片 企业商户五类证件的时候才需要(目前应该不需要) :return: """ return @property def blicTrcUrla(self): """ 组织机构代码 企业商户五类证件的时候才需要(目前应该不需要) :return: """ return @property def lepUrla(self): """ 身份证证件的正面 :return: """ return self.load_image_content(self.identifyCardAUrl) @property def lepUrlb(self): """ 身份证证件的反面 :return: """ return self.load_image_content(self.identifyCardBUrl) @property def lepUrlc(self): """ 手持身份证 照片 只有当商户类型为自然人的时候需要 经过宋伟沟通 这个地方也可以传递身份证的正面信息 :return: """ return self.load_image_content(self.identifyCardCUrl) @property def img(self): """ 经营门店的门头照片 :return: """ return self.load_image_content(self.storeAUrl) @property def enterimg(self): """ 经营门店的入口照片 :return: """ return self.load_image_content(self.storeBUrl) @property def innerimg(self): """ 经营门店的店内信息 :return: """ return self.load_image_content(self.storeCUrl) @property def cardPhoto(self): """ 结算银行卡正面图片 :return: """ return self.load_image_content(self.bankCardUrl) @property def settleManPhotoFront(self): """ 结算人身份证的正面照 :return: """ return self.lepUrla @property def settleManPhotoBack(self): """ 结算人身份证背面照 :return: """ return self.lepUrlb @property def settleHoldingIDCard(self): """ 结算人身份证的手持照 :return: """ return self.load_image_content(self.identifyCardCUrl) @property def settleHoldingBankCard(self): """ 结算人手持银行卡 暂时不需要 :return: """ return # 报文信息(entity) @property def companyType(self): """ 公司的性质 目前支持的就是企业性质或个人性质 :return: """ return self.merchantType @property def serialNo(self): """ 订单流水号 需要注意的是 一旦商户入驻成功, 订单流水号不变 修改信息的时候 以成功入驻的流水号为准 这个地方处理的逻辑是 用户入驻成功之后 才会将流水号写入进去 否则的话就为空 就会重新生成 :return: """ if not self.serial_no: self.serial_no = self.generate_serial_no(self.ownerId) return self.serial_no else: return self.serial_no @serialNo.setter def serialNo(self, value): """ 当设置 流水号的时候 说明商户入驻已经提交成功了 这个时候顺便将商户的状态 从init 转换为 等待中 :param value: :return: """ if self.status != MerchantStatus.INIT: return self.status = MerchantStatus.WAITING self.serial_no = value self.save() self.reload() @property def regPhone(self): return self.owner.username @property def blicCardType(self): """ 企业包含:统一社会信用代码类-USC,普通五证类-BLI,多证合一类-OCI 自然人:身份证-ID 目前企业的简化了 只支持统一社会信用代码 即USC :return: """ if self.companyType == COMPANY_TYPE.ENTERPRISE: return "USC" return "ID" @property def blicCompanyName(self): """ 实体商户的名称 企业商户 的时候就传递企业商户证件照上面的名称 个人商户时填姓名+(自然人) :return: """ if self.companyType == COMPANY_TYPE.ENTERPRISE: return self.busName return u"商户_{}".format(self.identifyCardName) @property def abMerchantName(self): """ 商户简称 :return: """ return self.storeShotName @property def blicUscc(self): """ 统一社会信用码 :return: """ return self.busCode @property def blicObaCardNo(self): """ 税务登记号 暂时不需要 :return: """ return @property def blicTrcCardNo(self): """ 组织机构代码 目前不需要 :return: """ return @property def blicScope(self): """ TODO 经营范围 企业商户需要 :return: """ return u"自主类设备经营" @property def indTwoCode(self): # 行业编号 return "033" @property def blicProvince(self): """ 营业地址所在省 对于个人用户 可以填写联系人所在的 :return: """ if self.companyType == COMPANY_TYPE.ENTERPRISE: return self.busProvince return self.shopProvince @property def blicCity(self): """ 营业地址所在市 对于个人商户 可以填写联系人所在的市 :return: """ if self.companyType == COMPANY_TYPE.ENTERPRISE: return self.busCity return self.shopCity @property def blicAddress(self): """ 营业地址的地区 对于个人商户而言 可以填写联系人所在的地址 :return: """ if self.companyType == COMPANY_TYPE.ENTERPRISE: return self.busArea + self.busAddr return self.shopArea + self.shopAddr @property def blicLongTerm(self): """ 营业执照 是否长期 :return: """ # TODO zjl return self.identifyCardLongTime @property def blicValidityStart(self): """ 营业执照起始时间 :return: """ return self.identifyCardStartTime @property def blicValidityEnd(self): """ 营业执照结束时间 :return: """ return self.identifyCardEndTime if not self.identifyCardLongTime else u"长期" @property def lepCardType(self): """ 法人证件类型 目前固定为ID :return: """ return "ID" @property def lepName(self): """ 法人证件姓名 就是身份证 :return: """ return self.identifyCardName @property def lepCardNo(self): """ 法人的证件号 就是身份证号 :return: """ return self.identifyCardCode @property def lepLongTerm(self): """ 法人证件是否长期 :return: """ return self.identifyCardLongTime @property def lepValidityStart(self): """ 法人证件的起始类型 :return: """ return self.identifyCardStartTime @property def lepValidityEnd(self): """ 法人证件的类型到期 :return: """ return self.identifyCardEndTime if not self.identifyCardLongTime else u"长期" @property def contactName(self): """ 联系人姓名 :return: """ if self.contactPersonName: return self.contactPersonName return self.identifyCardName @property def contactPhone(self): """ 联系人的电话号码 :return: """ return self.contactPersonPhone @property def contactEmail(self): """ 联系人的电子邮箱 :return: """ return self.contactPersonEmail @property def contactProvince(self): """ 联系人的省 :return: """ return self.identifyCardProvince @property def contactCity(self): """ 联系人的市 :return: """ return self.identifyCardCity @property def contactAddress(self): """ 联系人的详细地址 :return: """ return self.identifyCardArea + self.identifyCardAddr @property def ifPhyStore(self): """ 门店是否线下 固定值 :return: """ return True @property def storeProvince(self): """ 门店所在的省 :return: """ return self.shopProvince @property def storeCity(self): """ 门店所在的市 :return: """ return self.shopCity @property def storeAddress(self): """ 门店所在的地址 :return: """ return self.shopArea + self.shopAddr @property def settleToCard(self): """ 是否结算到卡 固定值 :return: """ return "1" @property def priatePublic(self): """ 结算账户的公私标志 企业用户一律是对公账户 个人账户一律是私人账户 :return: """ if self.companyType == COMPANY_TYPE.ENTERPRISE: return PRIATE_OR_PUBLIC.PUBLIC.value return PRIATE_OR_PUBLIC.PRIATE.value @property def bankName(self): """ 结算银行的名称 :return: """ return self.bankCardName @property def subBankCode(self): """ 结算银行的支行联行号 :return: """ return self.bankCardSubCode @property def bankAccountNo(self): """ 结算银行卡的账号 :return: """ return self.bankCardCode @property def bankAccountName(self): """ 结算的账户名称 :return: """ if self.companyType == COMPANY_TYPE.ENTERPRISE: return self.busName return self.identifyCardName @property def settleCardPhone(self): """ 结算银行卡绑定的手机号码 :return: """ return self.owner.username @property def settlementPeriod(self): """ 结算的周期 固定D1 :return: """ return "D1" @property def directoryList(self): """ 商户的授权目录 :return: """ return ["{}/".format(settings.SERVER_END_BASE_URL)] @property def loginLink(self): return "https://passport.jdpay.com/login/index.do" @property def wxSource(self): # type:() -> WechatApplyMerchant """ """ if not getattr(self, "_wxSource", None): setattr(self, "_wxSource", self.wxApplier.fetch() if self.wxApplier else WechatApplyMerchant()) return getattr(self, "_wxSource") @property def merchantStatus(self): """ 商户的申请状态 做兼容使用 """ if self.status in [ MerchantStatus.INIT, MerchantStatus.WAITING, MerchantStatus.FAIL, MerchantStatus.SUCCESS, MerchantStatus.AUTH_WAITING, MerchantStatus.AUTH_SUCCESS ]: return int(self.status) # 微信等待审核的状态 当客户是实名等待确认的时候 每次都去拉取同步一次 保证信息的真实准确 elif self.status in [int(MerchantStatus.AUTH_APPLY_SUCCESS)]: from apps.web.merchant.utils import is_wechat_authorized, is_alipay_authorized if is_wechat_authorized(self) and is_alipay_authorized(self): self.to_wx_success() return int(MerchantStatus.AUTH_SUCCESS) else: return int(self.status) def get_help_message(self): """ 显示当前步骤的帮助信息 """ if self.status == MerchantStatus.INIT: return u"您尚未提交商户资料,请及时提交商户资料,避免影响您后续收款" if self.status == MerchantStatus.WAITING: return u"您已提交资料,请耐心等待商户审核通过" if self.status == MerchantStatus.FAIL: return u"商户申请失败,失败原因为 <{}>".format(self.errorDescription) if self.status == MerchantStatus.CONFIRM: return u"您的商户申请已经通过,正准备提交微信完成商户实名" if self.status == MerchantStatus.AUTH_WAITING: return u"您的资料资料已提交到微信平台,正在进行商户实名申请中,请耐心等待实名申请通过" if self.status == MerchantStatus.AUTH_APPLY_SUCCESS: return u"您的实名申请已经通过审核,请点击下方按钮前往确认实名意愿" if self.status == MerchantStatus.AUTH_SUCCESS: return u"你的商户已经完成开通,请点击下方按钮完成收款方式切换" return u"商户开通完成" def get_merchant_info(self): # type:() -> dict """ 获取商户的基本信息 """ data = { # 商户类型 "merchantType": self.wxSource.subjectInfo.mainType, # 商户号 "merchantNo": self.merchantNo, # 商户的状态 "status": self.merchantStatus, # 提交资料的时间 "created": self.dateTimeAdded, # 联系人 "contactName": self.contactName, # 联系电话 "contactPhone": self.contactPhone, # 登录账号: "regEmail": self.regEmail, # 数据的更新时间 "updated": self.dateTimeUpdated } return data def get_help_info(self): """ 获取帮助信息 """ return { # 帮助按钮的链接 "helpHtml": "http://mp.weixin.qq.com/s?__biz=MzU2NDQ1MTM2NQ==&mid=2247483688&idx=1&sn=d4f935020d8051d7af1236019a76eae3&chksm=fc4b8062cb3c0974b47b75036012e01a28ba88172f91f3f63abbb23d177a25526671ae1d77e1&scene=18#wechat_redirect", # 帮助的文字 或提示信息 "helpMessage": self.get_help_message() } def get_legal_info(self): """ 获取法人的信息 """ return { "urlA": self.wxSource.legalInfo.lepCardUrlA, "urlB": self.wxSource.legalInfo.lepCardUrlB, "name": self.wxSource.legalInfo.lepName, "cardNo": self.wxSource.legalInfo.lepCardNo, "startTime": self.wxSource.legalInfo.lepCardStart, "endTime": self.wxSource.legalInfo.lepCardEnd, "province": { "code": self.wxSource.legalInfo.lepProvinceCode, "name": self.wxSource.legalInfo.lepProvince }, "city": { "code": self.wxSource.legalInfo.lepCityCode, "name": self.wxSource.legalInfo.lepCity }, "area": { "code": self.wxSource.legalInfo.lepAreaCode, "name": self.wxSource.legalInfo.lepArea }, "addr": self.wxSource.legalInfo.lepAddr } def get_contact_info(self): """ 获取联系人的信息 """ # 只有自然人 if self.merchantType == COMPANY_TYPE.NORMAL_PERSON: return None return { "urlA": self.wxSource.contactInfo.contactCardUrlA, "urlB": self.wxSource.contactInfo.contactCardUrlB, "name": self.wxSource.contactInfo.contactName, "cardNo": self.wxSource.contactInfo.contactCardNo, "startTime": self.wxSource.contactInfo.contactCardStart, "endTime": self.wxSource.contactInfo.contactCardEnd, "province": { "code": self.wxSource.contactInfo.contactProvinceCode, "name": self.wxSource.contactInfo.contactProvince }, "city": { "code": self.wxSource.contactInfo.contactCityCode, "name": self.wxSource.contactInfo.contactCity }, "area": { "code": self.wxSource.contactInfo.contactAreaCode, "name": self.wxSource.contactInfo.contactArea }, "addr": self.wxSource.contactInfo.contactAddr } def get_licence_info(self): """ 获取营业执照的信息 """ # 只有自然人 if self.merchantType == COMPANY_TYPE.NORMAL_PERSON: return None if self.wxSource.subjectInfo.businessLicenceInfo: return { "businessLicenceInfo": { "busLicenseUrl": self.wxSource.subjectInfo.businessLicenceInfo.licenceCopy, "busCode": self.wxSource.subjectInfo.businessLicenceInfo.licenceNumber, "busName": self.wxSource.subjectInfo.businessLicenceInfo.merchantName, "startTime": self.wxSource.subjectInfo.businessLicenceInfo.licenceStart, "endTime": self.wxSource.subjectInfo.businessLicenceInfo.licenceEnd, "province": { "code": self.busProvinceCode, "name": self.busProvince }, "city": { "code": self.busCityCode, "name": self.busCity }, "area": { "code": self.busAreaCode, "name": self.busArea }, "addr": self.busAddr } } def get_certificate_info(self): """ 获取商户提交的证件资料 """ return { # 商户类型 "contactType": self.wxSource.contactInfo.contactType, "businessAuthorizationLetter": self.wxSource.contactInfo.businessAuthorizationLetter, "legalInfo": self.get_legal_info(), "contactInfo": self.get_contact_info(), "subjectInfo": self.get_licence_info(), } def save_certificate_info(self, payload): """ 保存商户提交的证件资料 """ # 首先处理商户类型的信息 self.errorDescription = "" self.merchantAgent = MerchantAgent.default_merchant_agent() self.merchantType = self.trans_merchant_type(payload["merchantType"]) # 配置法人的证件照片信息 self.identifyCardAUrl = payload["legalInfo"]["urlA"] self.identifyCardBUrl = payload["legalInfo"]["urlB"] self.identifyCardCUrl = payload["legalInfo"]["urlA"] # 配置法人的证件文字信息 self.identifyCardName = payload["legalInfo"]["name"] self.identifyCardCode = payload["legalInfo"]["cardNo"] self.identifyCardStartTime = payload["legalInfo"]["startTime"] self.identifyCardEndTime = self.trans_end_time(payload["legalInfo"]["endTime"]) self.identifyCardLongTime = self.identifyCardEndTime == u"长期" # 配置法人证件的地址信息 self.identifyCardProvinceCode = payload["legalInfo"]["province"]["code"] self.identifyCardCityCode = payload["legalInfo"]["city"]["code"] self.identifyCardAreaCode = payload["legalInfo"]["area"]["code"] self.identifyCardProvince = payload["legalInfo"]["province"]["name"] self.identifyCardCity = payload["legalInfo"]["city"]["name"] self.identifyCardArea = payload["legalInfo"]["area"]["name"] self.identifyCardAddr = payload["legalInfo"]["addr"] # 存储商户的联系人信息 如果商户类型是个人企业 联系人即为自身 if self.merchantType == COMPANY_TYPE.NORMAL_PERSON: self.contactPersonName = payload["legalInfo"]["name"] else: self.contactPersonName = payload["contactInfo"]["name"] # 如果商户号类型为企业的商户 则需要保存商户信息 if self.merchantType != COMPANY_TYPE.NORMAL_PERSON: self.busLicenseUrl = payload["subjectInfo"]["businessLicenceInfo"]["busLicenseUrl"] self.busName = payload["subjectInfo"]["businessLicenceInfo"]["busName"] self.busCode = payload["subjectInfo"]["businessLicenceInfo"]["busCode"] self.busProvinceCode = payload["subjectInfo"]["businessLicenceInfo"]["province"]["code"] self.busCityCode = payload["subjectInfo"]["businessLicenceInfo"]["city"]["code"] self.busAreaCode = payload["subjectInfo"]["businessLicenceInfo"]["area"]["code"] self.busProvince = payload["subjectInfo"]["businessLicenceInfo"]["province"]["name"] self.busCity = payload["subjectInfo"]["businessLicenceInfo"]["city"]["name"] self.busArea = payload["subjectInfo"]["businessLicenceInfo"]["area"]["name"] self.busAddr = payload["subjectInfo"]["businessLicenceInfo"]["addr"] # 保存微信申请所需的信息 self.wxSource.subjectInfo.mainType = payload["merchantType"] self.wxSource.legalInfo.save_certificate_info(payload["legalInfo"]) self.wxSource.contactInfo.save_certificate_info(payload["contactInfo"]) # 如果是 企业商户 保存一下营业执照的信息 if self.merchantType != COMPANY_TYPE.NORMAL_PERSON: businessLicenceInfo = payload["subjectInfo"]["businessLicenceInfo"] businessLicenceInfo["busLegal"] = self.identifyCardName self.wxSource.subjectInfo.save_certificate_info(businessLicenceInfo=businessLicenceInfo) self.wxApplier = self.wxSource.save() if self.status == int(MerchantStatus.INIT): self.dateTimeAdded = datetime.datetime.now() self.dateTimeUpdated = datetime.datetime.now() return self.save() def get_settlement_info(self): """ 获取用户提交的结算信息资料 """ return { "bankCardImg": self.bankCardUrl, "bankCardCode": self.bankCardCode, "bankName": self.bankCardName, "bankCardSubCode": self.bankCardSubCode, "bankCardSubName": self.bankCardSubName } def save_settlement_info(self, payload): """ 保存商户的结算信息 """ # 图片的照片 self.bankCardUrl = payload["bankCardImg"] # 银行名称 self.bankCardName = payload["bankName"] # 银行卡号码 self.bankCardCode = payload["bankCardCode"] # 支行联行号 self.bankCardSubCode = payload["bankCardSubCode"] # 支行名称 self.bankCardSubName = payload["bankCardSubName"] return self.save() def get_business_info(self): """ 获取用户提交的营业信息 """ return { "storeAUrl": self.storeAUrl, "storeBUrl": self.storeBUrl, "storeCUrl": self.storeCUrl, # 商户简称 "storeShotName": self.storeShotName, # 地址 "province": { "code": self.shopProvinceCode, "name": self.shopProvince }, "city": { "code": self.shopCityCode, "name": self.shopCity }, "area": { "code": self.shopAreaCode, "name": self.shopArea }, "addr": self.shopAddr, "mobile": self.contactPersonPhone, } def save_business_info(self, payload): """ 保存营业类的信息 """ # 商户号一旦申请了,商户简称不允许修改 self.storeShotName = payload["storeShotName"] # 照片信息是可变的 self.storeAUrl = payload["storeAUrl"] self.storeBUrl = payload["storeBUrl"] self.storeCUrl = payload["storeCUrl"] # 地址信息是可变的 self.shopProvinceCode = payload["province"]["code"] self.shopCityCode = payload["city"]["code"] self.shopAreaCode = payload["area"]["code"] self.shopProvince = payload["province"]["name"] self.shopCity = payload["city"]["name"] self.shopArea = payload["area"]["name"] self.shopAddr = payload["addr"] # 个人信息小微商户的时候 需要保存 if self.merchantType == COMPANY_TYPE.NORMAL_PERSON: self.wxSource.subjectInfo.save_certificate_info(assistProveInfo=payload) self.wxApplier = self.wxSource.save() return self.save() def save_mobile_info(self, mobile): """ 保存手机号信息 商户号一旦确认 手机号不允许修改 """ if not self.merchantNo: self.contactPersonPhone = mobile self.contactPersonEmail = self.regEmail = "{}@163.com".format(self.contactPersonPhone) self.wxSource.contactInfo.save_mobile_info(mobile) self.wxApplier = self.wxSource.save() return self.save() return self def support_modify(self): """ 只有初始化以及审核失败的时候 才允许填写、修改资料 """ return self.status in [int(MerchantStatus.FAIL), int(MerchantStatus.INIT)] def support_enter(self): """ 是否支持进件 只有状态为1的时候 才会触发进件 """ return self.status in [int(MerchantStatus.WAITING)] def support_query_audit(self): return self.status in [int(MerchantStatus.WAITING)] def support_jdaggre(self): """ 京东app已经可以使用 等待微信实名认证 """ return self.status in [int(MerchantStatus.CONFIRM)] def support_wechat_audit(self): """ 查询微信的 申请状态 """ return self.status in [int(MerchantStatus.AUTH_WAITING)] @property def is_wechat_submit(self): return self.wxSource.applymentId @property def is_ali_submit(self): """ 阿里的 暂时都视为已经提交 """ return True def to_waiting(self, **kwargs): """ 切换到入驻申请状态 """ assert self.status in [MerchantStatus.INIT, MerchantStatus.FAIL] self.status = int(MerchantStatus.WAITING) self.dateTimeUpdated = datetime.datetime.now() self.save() MerchantLog.submit(str(self.id)) merchant_user_submit.send(sender=self.__class__, merchantId=str(self.id)) def to_confirm(self, **kwargs): """ 商户此时已经完成开通 准备各项准备工作 录入秘钥 录入APP 录入子商户编号等 """ assert self.status == MerchantStatus.WAITING desKey, mdKey = kwargs["desKey"], kwargs["mdKey"] if not all([desKey, mdKey]): return self.status = int(MerchantStatus.CONFIRM) self.desKey, self.mdKey = desKey, mdKey self.dateTimeUpdated = datetime.datetime.now() self.save() # 代理商、经销商预处理 self.owner.confirm_merchant(self) # 记录一次操作日志 MerchantLog.add_app(str(self.id)) # 发送信号 触发下一轮的行动 merchant_jd_access.send(sender=self.__class__, merchantId=str(self.id)) def to_wx_waiting(self, **kwargs): """ 状态不再发生变化 """ assert self.status == int(MerchantStatus.CONFIRM) self.wxSource.to_wechat_submit(kwargs["applymentId"]) self.dateTimeUpdated = datetime.datetime.now() self.save() # 记录一次操作日志 MerchantLog.submit_wechat(str(self.id), description=kwargs["applymentId"]) def to_ali_waiting(self, **kwargs): assert self.status == int(MerchantStatus.CONFIRM) self.wxSource.to_ali_submit(kwargs["applymentId"]) self.dateTimeUpdated = datetime.datetime.now() self.status = int(MerchantStatus.AUTH_WAITING) self.save() # 记录一次操作日志 MerchantLog.submit_ali(str(self.id), description=kwargs["applymentId"]) def to_auth_wait(self): """ 实名信息提交完毕 """ assert self.status == int(MerchantStatus.CONFIRM) self.status = int(MerchantStatus.AUTH_WAITING) self.dateTimeUpdated = datetime.datetime.now() self.save() def to_auth_apply_success(self, **kwargs): """ 全部实名已经通过 内部状态 做强制商户时候使用 """ assert self.status == int(MerchantStatus.AUTH_WAITING) self.status = int(MerchantStatus.AUTH_APPLY_SUCCESS) self.dateTimeUpdated = datetime.datetime.now() self.save() MerchantLog.auth_apply_success(str(self.id)) def to_wx_success(self, **kwargs): """ 微信审核通过 防止有些人通过扫描二维码小程序自行提交资料申请 状态放的宽泛一点点 """ self.status = int(MerchantStatus.AUTH_SUCCESS) self.dateTimeUpdated = datetime.datetime.now() self.save() def to_success(self, **kwargs): """ 经销商的商户确认开通 需要切换经销商的支付方式 而代理商的仅仅改变状态就可以了 """ assert self.status == MerchantStatus.AUTH_SUCCESS # 更改商户的状态 self.status = int(MerchantStatus.SUCCESS) self.dateTimeUpdated = datetime.datetime.now() self.save() # 然后是角色各自处理 self.owner.success_merchant() # 记录一次操作日志 MerchantLog.change_pay_type(str(self.id)) def to_fail(self, errorMsg): """ 切换为失败的状态 只有开通产品的时候会调用这个接口 如果入驻的时候失败 直接切换成为初始状态就好 """ self.status = int(MerchantStatus.FAIL) self.dateTimeUpdated = datetime.datetime.now() self.wxApplier = self.wxSource.to_cancel() self.errorDescription = errorMsg self.save() self.reload() # 记录一次日志操作 MerchantLog.fail(str(self.id), description=errorMsg) def create_app(self): return JDAggrePayApp.get_or_create_by_merchant(self) class Area(EmbeddedDocument): code = StringField(verbose_name="地区编码") name = StringField(verbose_name=u"地区名称") def __str__(self): return self.name def to_dict(self): return { "name": self.name, "code": self.code } class Attach(EmbeddedDocument): url = StringField(verbose_name=u"源") attachNum = StringField(verbose_name=u"编号") @property def content(self): res = requests.get(url=self.url, timeout=3) return res.content def upload_success(self, attachNum): self.attachNum = attachNum return self.save() def update_url(self, url, save=False): self.url = url return self if not save else self.save() class PayBank(EmbeddedDocument): num = StringField(verbose_name="产品编号") rate = StringField(verbose_name=u"费率", default="0.6") @classmethod def default_pay_type(cls): return [ # 京东 cls(num="10031414639876930831001", rate="0.60"), cls(num="10031414639876930831004", rate="0.60"), cls(num="10031414639876930831005", rate="0.60"), cls(num="10031414639876930831013", rate="0.60") ] def to_dict(self): return { "num": self.num, "rate": self.rate } class JDOpenApplyInfo(Searchable): """ 京东openAPI 的用户先写的原始资料 """ dateTimeAdded = DateTimeField(verbose_name=u"录入信息的时间", default=datetime.datetime.now) dateTimeUpdated = DateTimeField(verbose_name=u"记录更新的时间", default=datetime.datetime.now) status = IntField(verbose_name=u"商户状态", default=JdOpenMerchantStatus.INIT) isDelete = BooleanField(verbose_name=u"是否已经删除", default=False) ownerId = StringField(verbose_name=u"商户申请人ID") ownerRole = StringField(verbose_name=u"商户申请人角色") errorDesc = StringField(verbose_name=u"错误描述") # 通过接口返回的参数 agentNum = StringField(verbose_name=u"服务商编号", default="10001016435484143212321") customerNum = StringField(verbose_name=u"商户编号") settleNum = StringField(verbose_name=u"结算账户编号") shopNum = StringField(verbose_name="商店编号") # 商户基础参数 目前行业类型不对外开放 customerType = StringField(verbose_name=u"商户类型") fullName = StringField(verbose_name=u"商户全称") shortName = StringField(verbose_name=u"商户简称") industry = StringField(verbose_name=u"一级行业", default=u"生活服务") # 统一属于 生活服务 中的 自助服务 subIndustry = StringField(verbose_name=u"二级行业", default=u"自助") # 统一属于 生活服务 中的 自助服务 province = EmbeddedDocumentField(verbose_name=u"商户省", document_type=Area) city = EmbeddedDocumentField(verbose_name=u"商户市", document_type=Area) district = EmbeddedDocumentField(verbose_name=u"商户区", document_type=Area) address = StringField(verbose_name=u"商户详细地址") mapLng = StringField(verbose_name=u"商户经度") mapLat = StringField(verbose_name=u"商户维度") # 法人信息参数 目前证件类型不对外开放 certificateType = StringField(verbose_name=u"证件类型", default="IDENTIFICATION") legalImgFront = EmbeddedDocumentField(verbose_name=u"法人身份证正面", document_type=Attach) legalImgBack = EmbeddedDocumentField(verbose_name=u"法人身份证背面", document_type=Attach) legalName = StringField(verbose_name=u"法人姓名") legalCardNo = StringField(verbose_name=u"证件号码") legalStart = StringField(verbose_name=u"法人的证件起始") legalEnd = StringField(verbose_name=u"法人的证件结束") legalProvince = EmbeddedDocumentField(verbose_name=u"法人省", document_type=Area) legalCity = EmbeddedDocumentField(verbose_name=u"法人市", document_type=Area) legalDistrict = EmbeddedDocumentField(verbose_name=u"法人区", document_type=Area) legalAddress = StringField(verbose_name=u"法人详细地址") # 联系人信息参数 contactImgFront = EmbeddedDocumentField(verbose_name=u"联系人身份证正面", document_type=Attach) contactImgBack = EmbeddedDocumentField(verbose_name=u"联系人身份证背面", document_type=Attach) contactName = StringField(verbose_name=u"联系人姓名") contactCardNo = StringField(verbose_name=u"联系人卡号") contactStart = StringField(verbose_name=u"联系人证件开始") contactEnd = StringField(verbose_name=u"联系人证件结束") phoneNumber = StringField(verbose_name=u"登录账号、手机号码") # 收款账号相应参数 accountType = StringField(verbose_name=u"账户类型") bankImg = EmbeddedDocumentField(verbose_name=u"银行卡", document_type=Attach) bankCardNo = StringField(verbose_name=u"银行卡号") bankName = StringField(verbose_name=u"银行名称") bankBranchName = StringField(verbose_name=u"支行名称") bankProvince = EmbeddedDocumentField(verbose_name=u"银行省", document_type=Area) bankCity = EmbeddedDocumentField(verbose_name=u"银行市", document_type=Area) settleAmount = StringField(verbose_name=u"起结算金额", default="1") payBankList = EmbeddedDocumentListField(verbose_name=u"支付方式", document_type=PayBank) bankPhone = StringField(verbose_name=u"银行预留手机号") # 营业执照相应参数 organizationImg = EmbeddedDocumentField(verbose_name=u"营业执照", document_type=Attach) organizationName = StringField(verbose_name=u"企业名称") organizationNo = StringField(verbose_name=u"统一组织机构代码") organizationStart = StringField(verbose_name=u"营业执照的起始") organizationEnd = StringField(verbose_name=u"营业执照的结束") organizationProvince = EmbeddedDocumentField(verbose_name=u"营业执照省", document_type=Area) organizationCity = EmbeddedDocumentField(verbose_name=u"营业执照市", document_type=Area) organizationDistrict = EmbeddedDocumentField(verbose_name=u"营业执照区", document_type=Area) organizationAddress = StringField(verbose_name=u"营业执照详细地址") # 事业单位证书相关参数 certType = StringField(verbose_name=u"证书类型") certImg = EmbeddedDocumentField(verbose_name=u"证书", document_type=Attach) certName = StringField(verbose_name=u"组织机构名称") certNo = StringField(verbose_name=u"证书编号") certStart = StringField(verbose_name=u"营业执照起始") certEnd = StringField(verbose_name=u"营业执照结束") certProvince = EmbeddedDocumentField(verbose_name=u"证书省", document_type=Area) certCity = EmbeddedDocumentField(verbose_name=u"证书市", document_type=Area) certDistrict = EmbeddedDocumentField(verbose_name=u"证书区", document_type=Area) certAddress = StringField(verbose_name=u"证书详细地址") # 门店照相应参数 shopImgA = EmbeddedDocumentField(verbose_name=u"店铺照", document_type=Attach) shopImgB = EmbeddedDocumentField(verbose_name=u"门头照", document_type=Attach) shopImgC = EmbeddedDocumentField(verbose_name=u"店内照", document_type=Attach) # 个人需要 identifyhandhold = EmbeddedDocumentField(verbose_name=u"个人手持身份照", document_type=Attach) # 企业&个体工商户 需要 organizationcode = EmbeddedDocumentField(verbose_name=u"税务登记证", document_type=Attach) taxregistration = EmbeddedDocumentField(verbose_name=u"税务登记证", document_type=Attach) unifiedsocialcreditcode = EmbeddedDocumentField(verbose_name=u"税务登记证", document_type=Attach) # 事业单位独有参数 certificateFile = EmbeddedDocumentField(verbose_name=u"事业单位证明函", document_type=Attach) specialQualification = EmbeddedDocumentField(verbose_name=u"特殊资质证书", document_type=Attach) # 经办人信息 businessAuthorizationLetter = EmbeddedDocumentField(verbose_name=u"业务办理授权函", document_type=Attach) # 微信申请的消息 subMerchantId = StringField(verbose_name=u"微信子商编") businessCode = StringField(verbose_name=u"微信业务申请单编号") applymentId = StringField(verbose_name=u"微信申请编号") # 支付宝申请的信息 subAliMerchantId = StringField(verbose_name=u"支付宝子商编") aliApplymentId = StringField(verbose_name=u"支付宝申请编号") aliBusinessCode = StringField(verbose_name=u"支付宝实名申请单编号") meta = { 'collection': 'JDOpenApplyInfo', # TODO 需要切换数据库 # "db_alias": "logdata" } def __str__(self): return "{}_{}".format(self.__class__.__name__, self.id) @classmethod def create_personal(cls, owner, **kwargs): """ 新建个人商户的信息 """ mer = cls.get_merchant_by_owner(owner) # if mer and str(mer.id) != kwargs["id"]: raise ValueError(u"非所属经销商ID") else: # 新创建或者是修改 mer = mer or cls(ownerId=str(owner.id), ownerRole=owner.role) mer.customerType = kwargs["customerType"] mer.fullName = kwargs["fullName"] mer.shortName = kwargs["shortName"] mer.province = Area(**kwargs["province"]) mer.city = Area(**kwargs["city"]) mer.district = Area(**kwargs["district"]) mer.address = kwargs["address"] mer.mapLng = kwargs["mapLng"] mer.mapLat = kwargs["mapLat"] mer.legalImgFront = (mer.legalImgFront or Attach()).update_url(kwargs["legalImgFront"]) mer.legalImgBack = (mer.legalImgBack or Attach()).update_url(kwargs["legalImgBack"]) mer.legalName = kwargs["legalName"] mer.legalCardNo = kwargs["legalCardNo"] mer.legalStart = kwargs["legalStart"] mer.legalEnd = kwargs["legalEnd"] mer.phoneNumber = kwargs["phoneNumber"] mer.accountType = kwargs["accountType"] mer.bankImg = (mer.bankImg or Attach()).update_url(kwargs["bankImg"]) mer.bankCardNo = kwargs["bankCardNo"] mer.bankName = kwargs["bankName"] mer.bankBranchName = kwargs["bankBranchName"] mer.bankProvince = Area(**kwargs["bankProvince"]) mer.bankCity = Area(**kwargs["bankCity"]) mer.payBankList = PayBank.default_pay_type() mer.bankPhone = kwargs["bankPhone"] mer.shopImgA = (mer.shopImgA or Attach()).update_url(kwargs["shopImgA"]) mer.shopImgB = (mer.shopImgB or Attach()).update_url(kwargs["shopImgB"]) mer.shopImgC = (mer.shopImgC or Attach()).update_url(kwargs["shopImgC"]) mer.identifyhandhold = (mer.identifyhandhold or Attach()).update_url(kwargs["legalImgHold"]) mer = mer.save() return mer @classmethod def create_company(cls, owner, **kwargs): mer = cls.get_merchant_by_owner(owner) # if mer and str(mer.id) != kwargs["id"]: raise ValueError(u"非所属经销商ID") else: # 新创建或者是修改 mer = mer or cls(ownerId=str(owner.id), ownerRole=owner.role) mer.customerType = kwargs["customerType"] mer.fullName = kwargs["fullName"] mer.shortName = kwargs["shortName"] mer.province = Area(**kwargs["province"]) mer.city = Area(**kwargs["city"]) mer.district = Area(**kwargs["district"]) mer.address = kwargs["address"] mer.mapLng = kwargs["mapLng"] mer.mapLat = kwargs["mapLat"] # 企业上户需要加上法人证件的地址 便于微信的实名 mer.legalImgFront = (mer.legalImgFront or Attach()).update_url(kwargs["legalImgFront"]) mer.legalImgBack = (mer.legalImgBack or Attach()).update_url(kwargs["legalImgBack"]) mer.legalName = kwargs["legalName"] mer.legalCardNo = kwargs["legalCardNo"] mer.legalStart = kwargs["legalStart"] mer.legalEnd = kwargs["legalEnd"] mer.legalProvince = Area(**kwargs["legalProvince"]) mer.legalCity = Area(**kwargs["legalCity"]) mer.legalDistrict = Area(**kwargs["legalDistrict"]) mer.legalAddress = kwargs["legalAddress"] mer.contactImgFront = (mer.contactImgFront or Attach()).update_url(kwargs["contactImgFront"]) mer.contactImgBack = (mer.contactImgBack or Attach()).update_url(kwargs["contactImgBack"]) mer.contactName = kwargs["contactName"] mer.contactCardNo = kwargs["contactCardNo"] mer.contactStart = kwargs["contactStart"] mer.contactEnd = kwargs["contactEnd"] mer.phoneNumber = kwargs["phoneNumber"] mer.accountType = kwargs["accountType"] mer.bankImg = (mer.bankImg or Attach()).update_url(kwargs["bankImg"]) mer.bankCardNo = kwargs["bankCardNo"] mer.bankName = kwargs["bankName"] mer.bankBranchName = kwargs["bankBranchName"] mer.bankProvince = Area(**kwargs["bankProvince"]) mer.bankCity = Area(**kwargs["bankCity"]) mer.payBankList = PayBank.default_pay_type() mer.bankPhone = kwargs["bankPhone"] mer.organizationImg = (mer.organizationImg or Attach()).update_url(kwargs["organizationImg"]) mer.organizationName = kwargs["organizationName"] mer.organizationNo = kwargs["organizationNo"] mer.organizationStart = kwargs["organizationStart"] mer.organizationEnd = kwargs["organizationEnd"] mer.organizationProvince = Area(**kwargs["organizationProvince"]) mer.organizationCity = Area(**kwargs["organizationCity"]) mer.organizationDistrict = Area(**kwargs["organizationDistrict"]) mer.organizationAddress = kwargs["organizationAddress"] mer.shopImgA = (mer.shopImgA or Attach()).update_url(kwargs["shopImgA"]) mer.shopImgB = (mer.shopImgB or Attach()).update_url(kwargs["shopImgB"]) mer.shopImgC = (mer.shopImgC or Attach()).update_url(kwargs["shopImgC"]) mer.organizationcode = (mer.organizationcode or Attach()).update_url(kwargs["organizationcode"]) mer.taxregistration = (mer.taxregistration or Attach()).update_url(kwargs["taxregistration"]) mer.unifiedsocialcreditcode = (mer.unifiedsocialcreditcode or Attach()).update_url(kwargs["unifiedsocialcreditcode"]) # 经办人的信息 mer.businessAuthorizationLetter = (mer.taxregistration or Attach()).update_url(kwargs["businessAuthorizationLetter"]) mer = mer.save() return mer @classmethod def create_individualbiss(cls, owner, **kwargs): """ 创建个体工商户 """ mer = cls.get_merchant_by_owner(owner) # if mer and str(mer.id) != kwargs["id"]: raise ValueError(u"非所属经销商ID") else: # 新创建或者是修改 mer = mer or cls(ownerId=str(owner.id), ownerRole=owner.role) mer.customerType = kwargs["customerType"] mer.fullName = kwargs["fullName"] mer.shortName = kwargs["shortName"] mer.province = Area(**kwargs["province"]) mer.city = Area(**kwargs["city"]) mer.district = Area(**kwargs["district"]) mer.address = kwargs["address"] mer.mapLng = kwargs["mapLng"] mer.mapLat = kwargs["mapLat"] mer.legalImgFront = (mer.legalImgFront or Attach()).update_url(kwargs["legalImgFront"]) mer.legalImgBack = (mer.legalImgBack or Attach()).update_url(kwargs["legalImgBack"]) mer.legalName = kwargs["legalName"] mer.legalCardNo = kwargs["legalCardNo"] mer.legalStart = kwargs["legalStart"] mer.legalEnd = kwargs["legalEnd"] mer.contactImgFront = (mer.contactImgFront or Attach()).update_url(kwargs["contactImgFront"]) mer.contactImgBack = (mer.contactImgBack or Attach()).update_url(kwargs["contactImgBack"]) mer.contactName = kwargs["contactName"] mer.contactCardNo = kwargs["contactCardNo"] mer.contactStart = kwargs["contactStart"] mer.contactEnd = kwargs["contactEnd"] mer.phoneNumber = kwargs["phoneNumber"] mer.accountType = kwargs["accountType"] mer.bankImg = (mer.bankImg or Attach()).update_url(kwargs["bankImg"]) mer.bankCardNo = kwargs["bankCardNo"] mer.bankName = kwargs["bankName"] mer.bankBranchName = kwargs["bankBranchName"] mer.bankProvince = Area(**kwargs["bankProvince"]) mer.bankCity = Area(**kwargs["bankCity"]) mer.payBankList = PayBank.default_pay_type() mer.bankPhone = kwargs["bankPhone"] mer.organizationImg = (mer.organizationImg or Attach()).update_url(kwargs["organizationImg"]) mer.organizationName = kwargs["organizationName"] mer.organizationNo = kwargs["organizationNo"] mer.organizationStart = kwargs["organizationStart"] mer.organizationEnd = kwargs["organizationEnd"] mer.organizationProvince = Area(**kwargs["organizationProvince"]) mer.organizationCity = Area(**kwargs["organizationCity"]) mer.organizationDistrict = Area(**kwargs["organizationDistrict"]) mer.organizationAddress = kwargs["organizationAddress"] mer.shopImgA = (mer.shopImgA or Attach()).update_url(kwargs["shopImgA"]) mer.shopImgB = (mer.shopImgB or Attach()).update_url(kwargs["shopImgB"]) mer.shopImgC = (mer.shopImgC or Attach()).update_url(kwargs["shopImgC"]) mer.organizationcode = (mer.organizationcode or Attach()).update_url(kwargs["organizationcode"]) mer.taxregistration = (mer.taxregistration or Attach()).update_url(kwargs["taxregistration"]) # 经办人的信息 mer.businessAuthorizationLetter = (mer.taxregistration or Attach()).update_url(kwargs["businessAuthorizationLetter"]) mer = mer.save() return mer @classmethod def create_institution(cls, owner, **kwargs): """ 创建事业单位 """ mer = cls.get_merchant_by_owner(owner) # if mer and str(mer.id) != kwargs["id"]: raise ValueError(u"非所属经销商ID") else: # 新创建或者是修改 mer = mer or cls(ownerId=str(owner.id), ownerRole=owner.role) mer.customerType = kwargs["customerType"] mer.fullName = kwargs["fullName"] mer.shortName = kwargs["shortName"] mer.province = Area(**kwargs["province"]) mer.city = Area(**kwargs["city"]) mer.district = Area(**kwargs["district"]) mer.address = kwargs["address"] mer.mapLng = kwargs["mapLng"] mer.mapLat = kwargs["mapLat"] mer.legalImgFront = (mer.legalImgFront or Attach()).update_url(kwargs["legalImgFront"]) mer.legalImgBack = (mer.legalImgBack or Attach()).update_url(kwargs["legalImgBack"]) mer.legalName = kwargs["legalName"] mer.legalCardNo = kwargs["legalCardNo"] mer.legalStart = kwargs["legalStart"] mer.legalEnd = kwargs["legalEnd"] mer.contactImgFront = (mer.contactImgFront or Attach()).update_url(kwargs["contactImgFront"]) mer.contactImgBack = (mer.contactImgBack or Attach()).update_url(kwargs["contactImgBack"]) mer.contactName = kwargs["contactName"] mer.contactCardNo = kwargs["contactCardNo"] mer.contactStart = kwargs["contactStart"] mer.contactEnd = kwargs["contactEnd"] mer.phoneNumber = kwargs["phoneNumber"] mer.accountType = kwargs["accountType"] mer.bankImg = (mer.bankImg or Attach()).update_url(kwargs["bankImg"]) mer.bankCardNo = kwargs["bankCardNo"] mer.bankName = kwargs["bankName"] mer.bankBranchName = kwargs["bankBranchName"] mer.bankProvince = Area(**kwargs["bankProvince"]) mer.bankCity = Area(**kwargs["bankCity"]) mer.payBankList = PayBank.default_pay_type() mer.bankPhone = kwargs["bankPhone"] mer.certType = kwargs["certType"] mer.certImg = (mer.certImg or Attach()).update_url(kwargs["certImg"]) mer.certName = kwargs["certName"] mer.certNo = kwargs["certNo"] mer.certStart = kwargs["certStart"] mer.certEnd = kwargs["certEnd"] mer.certProvince = Area(**kwargs["certProvince"]) mer.certCity = Area(**kwargs["certCity"]) mer.certDistrict = Area(**kwargs["certDistrict"]) mer.certAddress = kwargs["certAddress"] mer.shopImgA = (mer.shopImgA or Attach()).update_url(kwargs["shopImgA"]) mer.shopImgB = (mer.shopImgB or Attach()).update_url(kwargs["shopImgB"]) mer.shopImgC = (mer.shopImgC or Attach()).update_url(kwargs["shopImgC"]) mer.certificateFile = (mer.certificateFile or Attach()).update_url(kwargs["certificateFile"]) mer.specialQualification = (mer.specialQualification or Attach()).update_url(kwargs["specialQualification"]) mer.organizationcode = (mer.organizationcode or Attach()).update_url(kwargs["organizationcode"]) mer.taxregistration = (mer.taxregistration or Attach()).update_url(kwargs["taxregistration"]) mer.unifiedsocialcreditcode = (mer.unifiedsocialcreditcode or Attach()).update_url(kwargs["unifiedsocialcreditcode"]) # 经办人的信息 mer.businessAuthorizationLetter = (mer.taxregistration or Attach()).update_url(kwargs["businessAuthorizationLetter"]) mer = mer.save() return mer @classmethod def get_merchant_by_status(cls, status): return cls.objects.filter(status=status, isDelete=False) @classmethod def get_merchant_by_owner(cls, owner): return cls.objects.filter(ownerId=str(owner.id), ownerRole=str(owner.role), isDelete=False).first() @classmethod def get_merchant_by_id(cls, _id): # type:(str) -> JDOpenApplyInfo return cls.objects.filter(id=_id, isDelete=False).first() @property def is_personal(self): """ 个人类型商户 """ return self.customerType == JdOpenMerchantType.PERSON @property def is_company(self): """ 企业类型商户 """ return self.customerType == JdOpenMerchantType.COMPANY @property def is_individualbiss(self): """ 个体工商户 """ return self.customerType == JdOpenMerchantType.INDIVIDUALBISS @property def is_institution(self): """ 事业单位 """ return self.customerType == JdOpenMerchantType.INSTITUTION @property def merchantAddr(self): return u"{}{}{}{}".format(self.province, self.city, self.district, self.address) @property def organizationAddr(self): return u"{}{}{}{}".format(self.organizationProvince, self.organizationCity, self.organizationDistrict, self.organizationAddress) @property def certAddr(self): return u"{}{}{}{}".format(self.certProvince, self.certCity, self.certDistrict, self.certAddress) @property def legalAddr(self): return u"{}{}{}{}".format(self.legalProvince, self.legalCity, self.legalDistrict, self.legalAddress) @property def owner(self): if hasattr(self, "_owner"): return self._owner owner = ROLE.from_role_id(self.ownerRole, self.ownerId) setattr(self, "_owner", owner) return owner @property def wxSource(self): return self def get_access_and_secret(self): logger.info("[get_access_and_secret] get merchant id = {}".format(self.id)) return OPEN_ACCESS_KEY, OPEN_SECRET_KEY def get_info(self): return { "id": str(self.id), "status": int(self.status), "agentNum": str(self.agentNum), "customerNum": str(self.customerNum), "settleNum": str(self.settleNum), "shopNum": str(self.shopNum), "customerType": self.customerType, "shortName": self.shortName, "province": self.province.to_dict() if self.province else {}, "city": self.city.to_dict() if self.city else {}, "district": self.district.to_dict() if self.district else {}, "address": self.address, "mapLng": self.mapLng, "mapLat": self.mapLat, "certificateType": self.certificateType, "legalImgFront": self.legalImgFront.url if self.legalImgFront else "", "legalImgBack": self.legalImgBack.url if self.legalImgBack else "", "legalName": self.legalName, "legalCardNo": self.legalCardNo, "legalStart": self.legalStart, "legalEnd": self.legalEnd, "legalForever": True if self.legalEnd == "forever" else False, "contactImgFront": self.contactImgFront.url if self.contactImgFront else "", "contactImgBack": self.contactImgBack.url if self.contactImgBack else "", "contactName": self.contactName, "contactCardNo": self.contactCardNo, "contactStart": self.contactStart, "contactEnd": self.contactEnd, "contactForever": True if self.contactEnd == "forever" else False, "phoneNumber": self.phoneNumber, "accountType": self.accountType, "bankImg": self.bankImg.url if self.bankImg else "", "bankCardNo": self.bankCardNo, "bankName": self.bankName, "bankBranchName": self.bankBranchName, "bankProvince": self.bankProvince.to_dict() if self.bankProvince else {}, "bankCity": self.bankCity.to_dict() if self.bankCity else {}, "bankPhone": self.bankPhone, "organizationImg": self.organizationImg.url if self.organizationImg else "", "organizationName": self.organizationName, "organizationNo": self.organizationNo, "organizationStart": self.organizationStart, "organizationEnd": self.organizationEnd, "organizationForever": True if self.organizationEnd == "forever" else False, "organizationProvince": self.organizationProvince.to_dict() if self.organizationProvince else {}, "organizationCity": self.organizationCity.to_dict() if self.organizationCity else {}, "organizationDistrict": self.organizationDistrict.to_dict() if self.organizationDistrict else {}, "organizationAddress": self.organizationAddress, "certType": self.certType, "certImg": self.certImg.url if self.certImg else "", "certNo": self.certNo, "certStart": self.certStart, "certEnd": self.certEnd, "certForever": True if self.certEnd == "forever" else False, "certProvince": self.certProvince.to_dict() if self.certProvince else {}, "certCity": self.certCity.to_dict() if self.certCity else {}, "certDistrict": self.certDistrict.to_dict() if self.certDistrict else {}, "certAddress": self.certAddress, "shopImgA": self.shopImgA.url if self.shopImgA else "", "shopImgB": self.shopImgB.url if self.shopImgB else "", "shopImgC": self.shopImgC.url if self.shopImgC else "", "legalImgHold": self.identifyhandhold.url if self.identifyhandhold else "", "organizationcode": self.organizationcode.url if self.organizationcode else "", "taxregistration": self.taxregistration.url if self.taxregistration else "", "unifiedsocialcreditcode": self.unifiedsocialcreditcode.url if self.unifiedsocialcreditcode else "", "certificateFile": self.certificateFile.url if self.certificateFile else "", "specialQualification": self.specialQualification.url if self.specialQualification else "", } def to_submit(self): self.status = JdOpenMerchantStatus.SUBMIT self.dateTimeUpdated = datetime.datetime.now() MerchantLog.submit(str(self.id)) self.save() merchant_user_submit.send(sender=self.__class__, merchantId=str(self.id)) return self def to_fail(self, message): self.status = JdOpenMerchantStatus.FAIL self.errorDesc = message self.dateTimeUpdated = datetime.datetime.now() MerchantLog.fail(str(self.id)) return self.save() def to_customer(self, customerNum): self.status = JdOpenMerchantStatus.CUSTOMER self.customerNum = customerNum self.dateTimeUpdated = datetime.datetime.now() self.save() create_customer_success.send(sender=self.__class__, merchantId=str(self.id)) return self def to_settle(self, settleNum): self.status = JdOpenMerchantStatus.SETTLE self.settleNum = settleNum self.dateTimeUpdated = datetime.datetime.now() self.save() create_settle_success.send(sender=self.__class__, merchantId=str(self.id)) return self def to_shop(self, shopNum): self.status = JdOpenMerchantStatus.SHOP self.shopNum = shopNum self.dateTimeUpdated = datetime.datetime.now() self.save() create_shop_success.send(sender=self.__class__, merchantId=str(self.id)) return self def to_attach(self): self.status = JdOpenMerchantStatus.ATTACH self.dateTimeUpdated = datetime.datetime.now() self.save() upload_attach_success.send(sender=self.__class__, merchantId=str(self.id)) return self def to_complete(self): self.status = JdOpenMerchantStatus.COMPLETE self.dateTimeUpdated = datetime.datetime.now() self.save() complete_success.send(sender=self.__class__, merchantId=str(self.id)) return self def to_confirm(self): self.status = JdOpenMerchantStatus.CONFIRM self.dateTimeUpdated = datetime.datetime.now() self.save() merchant_jd_access.send(sender=self.__class__, merchantId=str(self.id)) return self def to_success(self): """ 京东的商户审核完成 审核完成的时候 创建app """ self.owner.confirm_merchant(self) self.status = JdOpenMerchantStatus.SUCCESS self.dateTimeUpdated = datetime.datetime.now() MerchantLog.add_app(str(self.id)) return self.save() def to_wx_waiting(self, **kwargs): self.applymentId = str(kwargs["applymentId"]) self.dateTimeUpdated = datetime.datetime.now() MerchantLog.submit_wechat(str(self.id)) return self.save() def to_wx_audit(self): self.status = JdOpenMerchantStatus.AUTH_APPLY_SUCCESS self.dateTimeUpdated = datetime.datetime.now() return self.save() def to_apply(self, server): # type:(WechatApiProxy) -> dict """ 生成微信所需要的信息 """ businessCode = "{}{}".format(datetime.datetime.now().strftime("%Y%m%d%H%M%S"), random.randint(1000, 9999)), self.businessCode = businessCode self.save() data = { "business_code": businessCode, "addition_info": {"confirm_mchid_list": [self.subMerchantId]} } if self.is_personal: contact_info = { "contact_type": ContactType.LEGAL.code, "name": server.rsa_encrypt(self.legalName), "id_card_number": server.rsa_encrypt(self.legalCardNo), "mobile": server.rsa_encrypt(self.phoneNumber), } subject_info = { "subject_type": "SUBJECT_TYPE_MICRO", "assist_prove_info": { "micro_biz_type": "MICRO_TYPE_STORE", "store_name": self.shortName, "store_address_code": WxMerchantAddress.get_code(u"{}省{}市{}".format( self.province.name, self.city.name, self.district.name )), "store_address": self.merchantAddr, "store_header_copy": server.upload_image_from_oss(self.shopImgA.url).get("media_id", ""), "store_indoor_copy": server.upload_image_from_oss(self.shopImgB.url).get("media_id", ""), } } identification_info = { "identification_type": "IDENTIFICATION_TYPE_IDCARD", "identification_name": server.rsa_encrypt(self.legalName), "identification_number": server.rsa_encrypt(self.legalCardNo), "identification_valid_date": '["{}","{}"]'.format(self.legalStart, self.legalEnd), "identification_front_copy": server.upload_image_from_oss(self.legalImgFront.url).get("media_id", ""), "identification_back_copy": server.upload_image_from_oss(self.legalImgBack.url).get("media_id", ""), } elif self.is_company: isLegal = self.legalCardNo == self.contactCardNo and self.legalName == self.contactName contact_info = { "contact_type": ContactType.LEGAL.code if isLegal else ContactType.SUPER.code, "name": server.rsa_encrypt(self.contactName), "id_card_number": server.rsa_encrypt(self.contactCardNo), "mobile": server.rsa_encrypt(self.phoneNumber), } if not isLegal: contact_info.update({ "contact_id_doc_type": "IDENTIFICATION_TYPE_IDCARD", "contact_id_doc_copy": server.upload_image_from_oss(self.contactImgFront.url).get("media_id", ""), "contact_id_doc_copy_back": server.upload_image_from_oss(self.contactImgBack.url).get("media_id", ""), "contact_period_begin": self.contactStart, "contact_period_end": u"长期" if self.contactEnd == "forever" else self.contactEnd, "business_authorization_letter": server.upload_image_from_oss(self.businessAuthorizationLetter.url).get("media_id", "") }) subject_info = { "subject_type": "SUBJECT_TYPE_ENTERPRISE", "business_licence_info": { "licence_number": self.organizationcode, "licence_copy": server.upload_image_from_oss(self.organizationImg.url).get("media_id", ""), "merchant_name": self.organizationName, "legal_person": self.legalName, "company_address": self.organizationAddr, "licence_valid_date": '["{}","{}"]'.format(self.organizationStart, self.organizationEnd), }, } identification_info = { "identification_type": "IDENTIFICATION_TYPE_IDCARD", "identification_name": server.rsa_encrypt(self.legalName), "identification_number": server.rsa_encrypt(self.legalCardNo), "identification_valid_date": '["{}","{}"]'.format(self.legalStart, self.legalEnd), "identification_address": self.legalAddr, "identification_front_copy": server.upload_image_from_oss(self.legalImgFront.url).get("media_id", ""), "identification_back_copy": server.upload_image_from_oss(self.legalImgBack.url).get("media_id", ""), "owner": True } elif self.is_individualbiss: isLegal = self.legalCardNo == self.contactCardNo and self.legalName == self.contactName contact_info = { "contact_type": ContactType.LEGAL.code if isLegal else ContactType.SUPER.code, "name": server.rsa_encrypt(self.contactName), "id_card_number": server.rsa_encrypt(self.contactCardNo), "mobile": server.rsa_encrypt(self.phoneNumber), } if not isLegal: contact_info.update({ "contact_id_doc_type": "IDENTIFICATION_TYPE_IDCARD", "contact_id_doc_copy": server.upload_image_from_oss(self.contactImgFront.url).get("media_id", ""), "contact_id_doc_copy_back": server.upload_image_from_oss(self.contactImgBack.url).get("media_id", ""), "contact_period_begin": self.contactStart, "contact_period_end": u"长期" if self.contactEnd == "forever" else self.contactEnd, "business_authorization_letter": server.upload_image_from_oss(self.businessAuthorizationLetter.url).get("media_id", "") }) subject_info = { "subject_type": "SUBJECT_TYPE_INDIVIDUAL", "business_licence_info": { "licence_number": self.organizationcode, "licence_copy": server.upload_image_from_oss(self.organizationImg.url).get("media_id", ""), "merchant_name": self.organizationName, "legal_person": self.legalName, "company_address": self.organizationAddr, "licence_valid_date": '["{}","{}"]'.format(self.organizationStart, self.organizationEnd), } } identification_info = { "identification_type": "IDENTIFICATION_TYPE_IDCARD", "identification_name": server.rsa_encrypt(self.legalName), "identification_number": server.rsa_encrypt(self.legalCardNo), "identification_valid_date": '["{}","{}"]'.format(self.legalStart, self.legalEnd), "identification_address": self.legalAddr, "identification_front_copy": server.upload_image_from_oss(self.legalImgFront.url).get("media_id", ""), "identification_back_copy": server.upload_image_from_oss(self.legalImgBack.url).get("media_id", ""), } else: isLegal = self.legalCardNo == self.contactCardNo and self.legalName == self.contactName contact_info = { "contact_type": ContactType.LEGAL.code if isLegal else ContactType.SUPER.code, "name": server.rsa_encrypt(self.contactName), "id_card_number": server.rsa_encrypt(self.contactCardNo), "mobile": server.rsa_encrypt(self.phoneNumber), } if not isLegal: contact_info.update({ "contact_id_doc_type": "IDENTIFICATION_TYPE_IDCARD", "contact_id_doc_copy": server.upload_image_from_oss(self.contactImgFront.url).get("media_id", ""), "contact_id_doc_copy_back": server.upload_image_from_oss(self.contactImgBack.url).get("media_id", ""), "contact_period_begin": self.contactStart, "contact_period_end": u"长期" if self.contactEnd == "forever" else self.contactEnd, "business_authorization_letter": server.upload_image_from_oss(self.businessAuthorizationLetter.url).get("media_id", "") }) subject_info = { "subject_type": "SUBJECT_TYPE_INSTITUTIONS_CLONED", "certificate_info": { "cert_type": self.certType, "cert_number": self.certNo, "cert_copy": server.upload_image_from_oss(self.certImg.url).get("media_id", ""), "merchant_name": self.certName, "legal_person": self.legalName, "company_address": self.certAddr, "cert_valid_date": '["{}","{}"]'.format(self.certStart, self.certEnd), } } company_prove_copy = server.upload_image_from_oss(self.certificateFile.url).get("media_id", "") # TODO 特殊行业资质许可证填充 special_operation_list = { "category_id": 1, "operation_copy_list": server.upload_image_from_oss(self.specialQualification.url).get("media_id", "") } identification_info = { "identification_type": "IDENTIFICATION_TYPE_IDCARD", "identification_name": server.rsa_encrypt(self.legalName), "identification_number": server.rsa_encrypt(self.legalCardNo), "identification_valid_date": '["{}","{}"]'.format(self.legalStart, self.legalEnd), "identification_address": self.legalAddr, "identification_front_copy": server.upload_image_from_oss(self.legalImgFront.url).get("media_id", ""), "identification_back_copy": server.upload_image_from_oss(self.legalImgBack.url).get("media_id", ""), } data["company_prove_copy"] = company_prove_copy data["special_operation_list"] = special_operation_list data["contact_info"] = contact_info data["subject_info"] = subject_info data["identification_info"] = identification_info return data def to_ali_auth(self, server): """ 转换阿里所需要的实名信息 """ businessCode = "{}{}".format(datetime.datetime.now().strftime("%Y%m%d%H%M%S"), random.randint(1000, 9999)), self.aliBusinessCode = businessCode self.save() data = { "out_biz_no": businessCode, "extra_credentials": {"smid_list": [self.subAliMerchantId]} } if self.is_personal: contact_person_info = { "contact_name": self.legalName, "contact_phone_no": self.phoneNumber, "contact_card_no": self.legalCardNo } auth_identity_info = { "identity_type": "MSE", "support_credentials": { "merchant_type": "STORE", "store_name": self.shortName, "province_code": "", "province": self.province.name, "city_code": "", "city": self.city.name, "district_code": "", "district": self.district.name, "store_address": self.address, "store_door_img": server.upload_image_from_oss(self.shopImgA.url).get("media_id", ""), "store_inner_img": server.upload_image_from_oss(self.shopImgB.url).get("media_id", ""), } } legal_person_info = { "card_type": "RESIDENT", "person_name": self.legalName, "card_no": self.legalCardNo, "effect_time": self.legalStart, "expire_time": self.legalEnd, "card_front_img": server.upload_image_from_oss(self.legalImgFront.url).get("media_id", ""), "card_back_img": server.upload_image_from_oss(self.legalImgBack.url).get("media_id", "") } elif self.is_company: contact_person_info = { "contact_name": self.contactName, "contact_phone_no": self.phoneNumber, "contact_card_no": self.contactCardNo } auth_identity_info = { "identity_type": "ENTERPRISE", "certificate_type": "BUSINESS_CERT", "certificate_info": { "cert_no": self.organizationcode, "cert_image": server.upload_image_from_oss(self.organizationImg.url).get("media_id", ""), "merchant_name": self.organizationName, "legal_person_name": self.legalName, "register_address": self.organizationAddr, "effect_time": self.organizationStart, "expire_time": self.organizationEnd } } legal_person_info = { "card_type": "RESIDENT", "person_name": self.legalName, "card_no": self.legalCardNo, "effect_time": self.legalStart, "expire_time": self.legalEnd, "card_front_img": server.upload_image_from_oss(self.legalImgFront.url).get("media_id", ""), "card_back_img": server.upload_image_from_oss(self.legalImgBack.url).get("media_id", "") } elif self.is_individualbiss: contact_person_info = { "contact_name": self.contactName, "contact_phone_no": self.phoneNumber, "contact_card_no": self.contactCardNo } auth_identity_info = { "identity_type": "IND_BIZ", "certificate_type": "BUSINESS_CERT", "certificate_info": { "cert_no": self.organizationcode, "cert_image": server.upload_image_from_oss(self.organizationImg.url).get("media_id", ""), "merchant_name": self.organizationName, "legal_person_name": self.legalName, "register_address": self.organizationAddr, "effect_time": self.organizationStart, "expire_time": self.organizationEnd } } legal_person_info = { "card_type": "RESIDENT", "person_name": self.legalName, "card_no": self.legalCardNo, "effect_time": self.legalStart, "expire_time": self.legalEnd, "card_front_img": server.upload_image_from_oss(self.legalImgFront.url).get("media_id", ""), "card_back_img": server.upload_image_from_oss(self.legalImgBack.url).get("media_id", "") } else: contact_person_info = { "contact_name": self.contactName, "contact_phone_no": self.phoneNumber, "contact_card_no": self.contactCardNo } auth_identity_info = { "identity_type": "IND_BIZ", "certificate_type": "REGISTER_CERT", "certificate_info": { "cert_type": self.certType, "cert_no": self.certNo, "cert_image": server.upload_image_from_oss(self.certImg.url).get("media_id", ""), "merchant_name": self.certName, "legal_person_name": self.legalName, "register_address": self.certAddr, "effect_time": self.certStart, "expire_time": self.certEnd } } legal_person_info = { "card_type": "RESIDENT", "person_name": self.legalName, "card_no": self.legalCardNo, "effect_time": self.legalStart, "expire_time": self.legalEnd, "card_front_img": server.upload_image_from_oss(self.legalImgFront.url).get("media_id", ""), "card_back_img": server.upload_image_from_oss(self.legalImgBack.url).get("media_id", "") } employer_letter_img = server.upload_image_from_oss(self.certificateFile.url).get("media_id", "") data["employer_letter_img"] = employer_letter_img data["contact_person_info"] = contact_person_info data["auth_identity_info"] = auth_identity_info data["legal_person_info"] = legal_person_info return data def update_sub_merchant(self, **kwargs): self.subAliMerchantId = kwargs["subAliMerchantId"] self.subMerchantId = kwargs["subMerchantId"] return self.save() def get_help_info(self): return { # 帮助按钮的链接 "helpHtml": "http://mp.weixin.qq.com/s?__biz=MzU2NDQ1MTM2NQ==&mid=2247483688&idx=1&sn=d4f935020d8051d7af1236019a76eae3&chksm=fc4b8062cb3c0974b47b75036012e01a28ba88172f91f3f63abbb23d177a25526671ae1d77e1&scene=18#wechat_redirect", # 帮助的文字 或提示信息 "helpMessage": self.get_help_message() } def get_help_message(self): return u"您的实名申请已经通过审核,请点击下方按钮前往确认实名意愿" def get_merchant_info(self): """ 获取商户的信息 """ data = { # 商户号 "merchantNo": self.customerNum, # 商户的状态 "status": self.status, # 提交资料的时间 "created": self.dateTimeAdded, # 联系人 "contactName": self.contactName, # 联系电话 "contactPhone": self.phoneNumber, # 登录账号: "regEmail": self.phoneNumber, # 数据的更新时间 "updated": self.dateTimeUpdated } return data @property def is_wechat_submit(self): return self.wxSource.applymentId @property def is_ali_submit(self): """ 阿里的 暂时都视为已经提交 """ return True def create_app(self): return JDOpenPayApp.get_or_create_by_merchant(self)