|
@@ -3,6 +3,7 @@
|
|
|
|
|
|
import base64
|
|
import base64
|
|
import datetime
|
|
import datetime
|
|
|
|
+import hashlib
|
|
import logging
|
|
import logging
|
|
import os
|
|
import os
|
|
from importlib import import_module
|
|
from importlib import import_module
|
|
@@ -10,17 +11,20 @@ from importlib import import_module
|
|
import simplejson as json
|
|
import simplejson as json
|
|
from django.conf import settings
|
|
from django.conf import settings
|
|
from django.core.cache import cache
|
|
from django.core.cache import cache
|
|
|
|
+from django.utils.functional import cached_property
|
|
from django.utils.module_loading import import_string
|
|
from django.utils.module_loading import import_string
|
|
from mongoengine import StringField, DateTimeField, EmbeddedDocument, DictField, BooleanField, DynamicField, ListField, \
|
|
from mongoengine import StringField, DateTimeField, EmbeddedDocument, DictField, BooleanField, DynamicField, ListField, \
|
|
- IntField, LazyReferenceField, ObjectIdField, DynamicDocument, EmbeddedDocumentField
|
|
|
|
|
|
+ IntField, LazyReferenceField, ObjectIdField, DynamicDocument, EmbeddedDocumentField, GenericLazyReferenceField
|
|
from typing import List, cast, TYPE_CHECKING
|
|
from typing import List, cast, TYPE_CHECKING
|
|
|
|
|
|
from apilib.monetary import RMB
|
|
from apilib.monetary import RMB
|
|
|
|
+from apilib.systypes import IterConstant
|
|
from apilib.utils import flatten
|
|
from apilib.utils import flatten
|
|
from apilib.utils_json import json_loads, json_dumps
|
|
from apilib.utils_json import json_loads, json_dumps
|
|
from apilib.utils_string import encrypt_display
|
|
from apilib.utils_string import encrypt_display
|
|
from apilib.utils_sys import ThreadLock
|
|
from apilib.utils_sys import ThreadLock
|
|
from apps import serviceCache
|
|
from apps import serviceCache
|
|
|
|
+from apps.web.common.transaction import OrderNoMaker, OrderMainType, OtherOrderSubType
|
|
from apps.web.constant import Const, PARTITION_ROLE
|
|
from apps.web.constant import Const, PARTITION_ROLE
|
|
from apps.web.core import PayAppType, APP_KEY_DELIMITER, ROLE
|
|
from apps.web.core import PayAppType, APP_KEY_DELIMITER, ROLE
|
|
from apps.web.core.db import Searchable
|
|
from apps.web.core.db import Searchable
|
|
@@ -1512,6 +1516,131 @@ class AliApp(PayAppBase):
|
|
|
|
|
|
return getattr(self, '__client__')
|
|
return getattr(self, '__client__')
|
|
|
|
|
|
|
|
+ @property
|
|
|
|
+ def withdraw_payer_info(self):
|
|
|
|
+ return None
|
|
|
|
+
|
|
|
|
+ def withdraw_product_code(self, bank):
|
|
|
|
+ if bank:
|
|
|
|
+ return 'TRANS_BANKCARD_NO_PWD'
|
|
|
|
+ else:
|
|
|
|
+ return 'TRANS_ACCOUNT_NO_PWD'
|
|
|
|
+
|
|
|
|
+ def withdraw_biz_scene(self, bank):
|
|
|
|
+ return 'DIRECT_TRANSFER'
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class AliFundAccountBookApp(PayAppBase):
|
|
|
|
+ """
|
|
|
|
+ 阿里资金转账APP
|
|
|
|
+ """
|
|
|
|
+
|
|
|
|
+ appid = StringField(verbose_name = u'资金记账本id', required = True, null = False)
|
|
|
|
+ agreementNo = StringField(verbose_name = u'协议编号', required = True, null = False)
|
|
|
|
+
|
|
|
|
+ certNo = StringField(verbose_name = u'企业营业执照认证号')
|
|
|
|
+
|
|
|
|
+ merchantUserId = StringField(verbose_name = u'外部商户系统会员的唯一标识;创建记账本的幂等字段')
|
|
|
|
+ merchantUserType = StringField(verbose_name = u'外部商户用户类型,固定值')
|
|
|
|
+ sceneCode = StringField(verbose_name = u'资金记账本的业务场景')
|
|
|
|
+
|
|
|
|
+ cardInfo = DictField(verbose_name = u'虚拟银行卡信息')
|
|
|
|
+
|
|
|
|
+ search_fields = ('appid', 'name', 'remarks')
|
|
|
|
+
|
|
|
|
+ meta = {
|
|
|
|
+ 'indexes': [
|
|
|
|
+ {
|
|
|
|
+ 'fields': ['appid'], 'unique': True
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
|
|
+ 'collection': 'ali_fund_account_book',
|
|
|
|
+ 'db_alias': 'default'
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ def __repr__(self):
|
|
|
|
+ return '<AliFundAccountBookApp appid={}>'.format(self.appid)
|
|
|
|
+
|
|
|
|
+ @classmethod
|
|
|
|
+ def make_user_id(cls, external_agreement_no, cert_no):
|
|
|
|
+ return '{}{}'.format(external_agreement_no, cert_no)
|
|
|
|
+
|
|
|
|
+ @classmethod
|
|
|
|
+ def apply(cls, signModel):
|
|
|
|
+ # type: (AliUserAgreementSign)->AliFundAccountBookApp
|
|
|
|
+
|
|
|
|
+ return cls(
|
|
|
|
+ agentNo = signModel.cooperAppId,
|
|
|
|
+ merchantUserId = cls.make_user_id(signModel.externalAgreementNo, signModel.attachParas['certNo']),
|
|
|
|
+ merchantUserType = 'BUSINESS_ORGANIZATION',
|
|
|
|
+ sceneCode = 'SATF_FUND_BOOK',
|
|
|
|
+ agreementNo = signModel.agreementNo,
|
|
|
|
+ certNo = signModel.attachParas['certNo']
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ @property
|
|
|
|
+ def __valid_check__(self):
|
|
|
|
+ if not self.appid or not self.agreementNo:
|
|
|
|
+ return False
|
|
|
|
+ else:
|
|
|
|
+ return True
|
|
|
|
+
|
|
|
|
+ @cached_property
|
|
|
|
+ def ISVApp(self):
|
|
|
|
+ return AliApp.objects(appid = self.agentNo).first()
|
|
|
|
+
|
|
|
|
+ @property
|
|
|
|
+ def support_withdraw(self):
|
|
|
|
+ return self.ISVApp.supportWithdraw
|
|
|
|
+
|
|
|
|
+ @property
|
|
|
|
+ def support_withdraw_bank(self):
|
|
|
|
+ return self.ISVApp.supportWithdrawBank
|
|
|
|
+
|
|
|
|
+ @property
|
|
|
|
+ def withdraw_payer_info(self):
|
|
|
|
+ return {
|
|
|
|
+ 'identity_type': 'ACCOUNT_BOOK_ID',
|
|
|
|
+ 'identity': self.appid,
|
|
|
|
+ 'ext_info': json.dumps({
|
|
|
|
+ 'agreement_no': self.agreementNo
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ def withdraw_product_code(self, bank):
|
|
|
|
+ return 'SINGLE_TRANSFER_NO_PWD'
|
|
|
|
+
|
|
|
|
+ def withdraw_biz_scene(self, bank):
|
|
|
|
+ return 'ENTRUST_TRANSFER'
|
|
|
|
+
|
|
|
|
+ def new_withdraw_gateway(self, gateway_version = None):
|
|
|
|
+ from apps.web.core.payment.ali import AliPayWithdrawGateway
|
|
|
|
+ return AliPayWithdrawGateway(self)
|
|
|
|
+
|
|
|
|
+ @property
|
|
|
|
+ def pay_app_type(self):
|
|
|
|
+ return PayAppType.ALIPAY_FUND_BOOK
|
|
|
|
+
|
|
|
|
+ @property
|
|
|
|
+ def __gateway_key__(self):
|
|
|
|
+ _ = [
|
|
|
|
+ self.occupantId,
|
|
|
|
+ self.appid,
|
|
|
|
+ self.occupant.role
|
|
|
|
+ ]
|
|
|
|
+ return APP_KEY_DELIMITER.join(_)
|
|
|
|
+
|
|
|
|
+ @property
|
|
|
|
+ def client(self):
|
|
|
|
+ if hasattr(self, '__client__'):
|
|
|
|
+ return getattr(self, '__client__')
|
|
|
|
+
|
|
|
|
+ _client = self.ISVApp.client
|
|
|
|
+ setattr(self, '__client__', _client)
|
|
|
|
+
|
|
|
|
+ return _client
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
class PlatformAppBase(PayAppBase):
|
|
class PlatformAppBase(PayAppBase):
|
|
"""
|
|
"""
|
|
@@ -1778,9 +1907,13 @@ class WithdrawEntity(EmbeddedDocument):
|
|
wechatWithdrawApp = LazyReferenceField(document_type = WechatPayApp, default = None)
|
|
wechatWithdrawApp = LazyReferenceField(document_type = WechatPayApp, default = None)
|
|
alipayWithdrawApp = LazyReferenceField(document_type = AliApp, default = None)
|
|
alipayWithdrawApp = LazyReferenceField(document_type = AliApp, default = None)
|
|
|
|
|
|
|
|
+ aliWithdrawApp = GenericLazyReferenceField(choices = [AliApp, AliFundAccountBookApp], default = None)
|
|
|
|
+
|
|
@property
|
|
@property
|
|
def alipay_app(self):
|
|
def alipay_app(self):
|
|
- if self.alipayWithdrawApp:
|
|
|
|
|
|
+ if self.aliWithdrawApp:
|
|
|
|
+ return self.aliWithdrawApp.fetch()
|
|
|
|
+ elif self.alipayWithdrawApp:
|
|
return self.alipayWithdrawApp.fetch()
|
|
return self.alipayWithdrawApp.fetch()
|
|
else:
|
|
else:
|
|
return None
|
|
return None
|
|
@@ -2257,51 +2390,55 @@ class DriverEventer(DynamicDocument):
|
|
return eval('eventer_module.builder(device_adapter)')
|
|
return eval('eventer_module.builder(device_adapter)')
|
|
|
|
|
|
|
|
|
|
-class CustomerPayRelation(Searchable):
|
|
|
|
|
|
+class AliUserAgreementSign(Searchable):
|
|
"""
|
|
"""
|
|
- app 和使用者的关联表
|
|
|
|
- 为 多对多的关系
|
|
|
|
|
|
+ 阿里用户签约
|
|
"""
|
|
"""
|
|
- ownerId = StringField(verbose_name=u"持有者ID")
|
|
|
|
- ownerRole = StringField(verbose_name=u"持有者角色")
|
|
|
|
|
|
|
|
- appId = StringField(verbose_name=u"app的ID")
|
|
|
|
- appType = StringField(verbose_name=u"支付APP的种类")
|
|
|
|
|
|
+ class SignStatus(IterConstant):
|
|
|
|
+ INIT = 'INIT'
|
|
|
|
+ TEMP = 'TEMP'
|
|
|
|
+ NORMAL = 'NORMAL'
|
|
|
|
+ STOP = 'STOP'
|
|
|
|
+
|
|
|
|
+ externalAgreementNo = StringField(verbose_name = u"商户传入的协议编号")
|
|
|
|
+ agreementNo = StringField(verbose_name = u"签约号")
|
|
|
|
+
|
|
|
|
+ personalProductCode = StringField(verbose_name = u'个人产品码')
|
|
|
|
+ signScene = StringField(verbose_name = u'场景码')
|
|
|
|
+ accessParams = DictField(verbose_name = u'端类型')
|
|
|
|
+ productCode = StringField(verbose_name = u"商家签约的产品码")
|
|
|
|
|
|
- active = BooleanField(verbose_name=u"是否处于使用状态", default=False)
|
|
|
|
- isDelete = BooleanField(verbose_name=u"是否已经删除", default=False)
|
|
|
|
|
|
+ thirdPartyType = StringField(verbose_name = u"商家类型")
|
|
|
|
+
|
|
|
|
+ externalLogonId = StringField(verbose_name = u"用户在商户网站的登录账号,用于在签约页面展示,如果为空,则不展示")
|
|
|
|
+
|
|
|
|
+ dateTimeAdded = DateTimeField(verbose_name = u"创建时间")
|
|
|
|
+ signTime = DateTimeField(verbose_name = u"创建时间")
|
|
|
|
+
|
|
|
|
+ attachParas = DictField(verbose_name = u'签约完成后操作所需要的参数')
|
|
|
|
+
|
|
|
|
+ cooperAppId = StringField(verbose_name = u'合作单位APPID')
|
|
|
|
+
|
|
|
|
+ meta = {"collection": "ali_user_agreement_sign", "db_alias": "default"}
|
|
|
|
|
|
@classmethod
|
|
@classmethod
|
|
- def add_relation(cls, customer, app):
|
|
|
|
- rel = cls.objects.filter(ownerId=str(customer.id), appId=str(app.id))
|
|
|
|
- if not rel:
|
|
|
|
- rel = cls()
|
|
|
|
- rel.ownerId = str(customer.id)
|
|
|
|
- rel.ownerRole = str(customer.role)
|
|
|
|
- rel.appId = str(app.id)
|
|
|
|
- rel.appType = str(app.__class__.__name__)
|
|
|
|
- return rel.save()
|
|
|
|
- else:
|
|
|
|
- return rel
|
|
|
|
-
|
|
|
|
- def active_app(self):
|
|
|
|
- """
|
|
|
|
- 激活app 使之处于可用状态
|
|
|
|
- """
|
|
|
|
- self.active = True
|
|
|
|
- return self.save()
|
|
|
|
-
|
|
|
|
- def deactive_app(self):
|
|
|
|
- """
|
|
|
|
- 关闭app 使之处于不可用状态
|
|
|
|
- """
|
|
|
|
- self.active = False
|
|
|
|
- return self.save()
|
|
|
|
-
|
|
|
|
- def delete_relation(self):
|
|
|
|
- """
|
|
|
|
- 删除app
|
|
|
|
- """
|
|
|
|
- app = self.deactive_app()
|
|
|
|
- app.isDelete = True
|
|
|
|
- return app.save()
|
|
|
|
|
|
+ def issue(cls, cooperAppId, external_agreement_no, external_logon_id, attach):
|
|
|
|
+ return cls(
|
|
|
|
+ cooperAppId = cooperAppId,
|
|
|
|
+ externalAgreementNo = external_agreement_no,
|
|
|
|
+ personalProductCode = 'FUND_SAFT_SIGN_WITHHOLDING_P',
|
|
|
|
+ signScene = 'INDUSTRY|SATF_ACC',
|
|
|
|
+ accessParams = {"channel": "QRCODE"},
|
|
|
|
+ productCode = 'FUND_SAFT_SIGN_WITHHOLDING',
|
|
|
|
+ thirdPartyType = 'PARTNER',
|
|
|
|
+ externalLogonId = external_logon_id,
|
|
|
|
+ attachParas = attach).save()
|
|
|
|
+
|
|
|
|
+ @classmethod
|
|
|
|
+ def makeNo(cls, external_logon_id):
|
|
|
|
+ identifier = hashlib.md5(external_logon_id.encode()).hexdigest().upper()
|
|
|
|
+ return OrderNoMaker.make_order_no_32(
|
|
|
|
+ identifier, OrderMainType.OTHER, OtherOrderSubType.ALI_USER_AGREEMENT_SIG)
|
|
|
|
+
|
|
|
|
+
|