|
@@ -8,8 +8,8 @@ from django.conf import settings
|
|
|
|
|
|
from apps.exceptions import CustomError
|
|
|
from apps.account.models import Branch
|
|
|
-from apps.customer.models import Customer
|
|
|
-from util.wechatpay import WechatPay, WeChatResponse
|
|
|
+from apps.customer.models import Customer, CustomerWechat
|
|
|
+from util.wechatpay import WechatPay, WeChatResponse, SplitAccountFuc
|
|
|
|
|
|
|
|
|
class Activity(models.Model):
|
|
@@ -67,6 +67,248 @@ class Activity(models.Model):
|
|
|
return instance
|
|
|
|
|
|
|
|
|
+class SplitAccount(models.Model):
|
|
|
+ WAIT = 1
|
|
|
+ PROCESSING = 2
|
|
|
+ FINISHED = 3
|
|
|
+ STATUS_CHOICES = (
|
|
|
+ (WAIT, u'待分账'),
|
|
|
+ (PROCESSING, u'处理中'),
|
|
|
+ (FINISHED, u'分账完成'),
|
|
|
+ )
|
|
|
+
|
|
|
+ branch = models.ForeignKey(Branch, verbose_name=u"门店", on_delete=models.PROTECT, editable=False)
|
|
|
+ no = models.CharField(max_length=64, verbose_name=u"单号")
|
|
|
+ create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now)
|
|
|
+ status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"分账状态", default=WAIT)
|
|
|
+ amount = models.BigIntegerField(verbose_name=u"分账金额", null=True) # 单位分
|
|
|
+ order_id = models.CharField(max_length=100, verbose_name=u"微信分账单号", null=True, editable=False) # 微信分账单号,微信支付系统返回的唯一标识
|
|
|
+
|
|
|
+ class Meta:
|
|
|
+ db_table = "split_account"
|
|
|
+ verbose_name = u"分账"
|
|
|
+ ordering = ('-id',)
|
|
|
+ index_together = (
|
|
|
+ 'create_time',
|
|
|
+ 'status',
|
|
|
+ )
|
|
|
+ unique_together = (
|
|
|
+ 'no',
|
|
|
+ )
|
|
|
+ default_permissions = ()
|
|
|
+
|
|
|
+
|
|
|
+ def unfreezeAccount(self):
|
|
|
+ # 解冻剩余资金 如果由于客户或其他原因 无法完成分账 就手动解除资金冻结
|
|
|
+ pass
|
|
|
+
|
|
|
+ def handSplitAccont(self, spd, spr, pay):
|
|
|
+ '''手动申请分账(在自动申请分账失败后 手动申请分账)'''
|
|
|
+ if spd.status == SplitAccountDetail.SUCCESS:
|
|
|
+ raise CustomError(u'该分账已成功,禁止重复申请!')
|
|
|
+ appid = ''
|
|
|
+ mchid = ''
|
|
|
+ private_key = ''
|
|
|
+ cert_serial_no = ''
|
|
|
+ apiv3_key = ''
|
|
|
+ spc = SplitAccountFuc(appid, mchid, private_key, cert_serial_no, apiv3_key, cert_dir=None, proxy=None)
|
|
|
+ # 状态是"待分账" 的查询分账
|
|
|
+ if spd.status == SplitAccountDetail.PENDING:
|
|
|
+ self.splictAccountQuery(spc, pay.no, self.no, spd)
|
|
|
+
|
|
|
+ if spd.status == SplitAccountDetail.SUCCESS:
|
|
|
+ raise CustomError(u'该分账已成功!')
|
|
|
+
|
|
|
+ if spd.status == SplitAccountDetail.PENDING:
|
|
|
+ raise CustomError(u'该分账正在处理!')
|
|
|
+ # 添加分账接收人
|
|
|
+ self.splictAccountAddReceiver(spc, spr)
|
|
|
+ # 分账申请
|
|
|
+ receivers = [{'account': spd.account, 'amount': spd.amount, 'description': "支付推荐佣金"}]
|
|
|
+ success, data = spc.splitaccount_order(pay.no, self.no, receivers)
|
|
|
+ if not success:
|
|
|
+ raise CustomError(u'分账申请失败!')
|
|
|
+ # 分账请求成功 结果不一定成功
|
|
|
+ self.order_id = data['order_id']
|
|
|
+ if data['state'] == 'PROCESSING':
|
|
|
+ self.status = SplitAccount.PROCESSING
|
|
|
+ if data['state'] == 'FINISHED':
|
|
|
+ self.status = SplitAccount.FINISHED
|
|
|
+ self.save()
|
|
|
+ for item in data['receivers']:
|
|
|
+ # 现在只对一个推荐人分账
|
|
|
+ if item['account'] == spd.account:
|
|
|
+ if item['result'] == 'PENDING':
|
|
|
+ spd.status = SplitAccountDetail.PENDING
|
|
|
+ elif item['result'] == 'SUCCESS':
|
|
|
+ spd.status = SplitAccountDetail.SUCCESS
|
|
|
+ elif item['result'] == 'CLOSED':
|
|
|
+ spd.status = SplitAccountDetail.CLOSED
|
|
|
+ spd.fail_reason = item['fail_reason']
|
|
|
+ spd.create_time = item['create_time']
|
|
|
+ spd.finish_time = item['finish_time']
|
|
|
+ spd.detail_no = item['detail_id']
|
|
|
+ spd.save()
|
|
|
+
|
|
|
+ def splictAccountAddReceiver(self, split_account_func, spr):
|
|
|
+ '''添加分账接收人'''
|
|
|
+ if spr.status != SplitAccountReceiver.ADD:
|
|
|
+ add = split_account_func.splitaccount_addreceiver(spr.account)
|
|
|
+ if not add:
|
|
|
+ raise CustomError(u'添加分账接收方失败!')
|
|
|
+ spr.status = SplitAccountReceiver.ADD
|
|
|
+ spr.save()
|
|
|
+
|
|
|
+ def splictAccountQuery(self, split_account_func, transaction_id, out_order_no, detail):
|
|
|
+ '''查询分账结果'''
|
|
|
+ success, data = split_account_func.splitaccount_orderquery(transaction_id, out_order_no)
|
|
|
+ if not success:
|
|
|
+ raise CustomError(u'[%s]查询分账结果失败!' % out_order_no)
|
|
|
+ if data['state'] == 'PROCESSING':
|
|
|
+ self.status = SplitAccount.PROCESSING
|
|
|
+ if data['state'] == 'FINISHED':
|
|
|
+ self.status = SplitAccount.FINISHED
|
|
|
+ self.save()
|
|
|
+ for item in data['receivers']:
|
|
|
+ if detail and detail.account == item['account']:
|
|
|
+ if item['result'] == 'SUCCESS':
|
|
|
+ detail.status = SplitAccountDetail.SUCCESS
|
|
|
+ elif item['result'] == 'CLOSED':
|
|
|
+ detail.status = SplitAccountDetail.CLOSED
|
|
|
+ detail.fail_reason = item['fail_reason']
|
|
|
+ detail.create_time = item['create_time']
|
|
|
+ detail.finish_time = item['finish_time']
|
|
|
+ detail.detail_no = item['detail_id']
|
|
|
+ detail.save()
|
|
|
+
|
|
|
+ def splitAccount(self, spd, spr, pay):
|
|
|
+ if spd.status != SplitAccountDetail.DEFAULT:
|
|
|
+ return
|
|
|
+ appid = ''
|
|
|
+ mchid = ''
|
|
|
+ private_key = ''
|
|
|
+ cert_serial_no = ''
|
|
|
+ apiv3_key = ''
|
|
|
+ spc = SplitAccountFuc(appid, mchid, private_key, cert_serial_no, apiv3_key, cert_dir=None, proxy=None)
|
|
|
+
|
|
|
+ if spr.status != SplitAccountReceiver.ADD:
|
|
|
+ add = spc.splitaccount_addreceiver(spr.account)
|
|
|
+ if not add:
|
|
|
+ # 添加分账接收方失败 不再继续
|
|
|
+ return
|
|
|
+ spr.status = SplitAccountReceiver.ADD
|
|
|
+ spr.save()
|
|
|
+
|
|
|
+ receivers = [{'account': spd.account, 'amount': spd.amount, 'description': "支付推荐佣金"}]
|
|
|
+ success, data = spc.splitaccount_order(pay.no, self.no, receivers)
|
|
|
+ if not success:
|
|
|
+ # 分账请求失败 不再继续
|
|
|
+ return
|
|
|
+ # 分账请求成功 结果不一定成功
|
|
|
+ self.order_id = data['order_id']
|
|
|
+ if data['state'] == 'PROCESSING':
|
|
|
+ self.status = SplitAccount.PROCESSING
|
|
|
+ if data['state'] == 'FINISHED':
|
|
|
+ self.status = SplitAccount.FINISHED
|
|
|
+ self.save()
|
|
|
+ for item in data['receivers']:
|
|
|
+ # 现在只对一个推荐人分账
|
|
|
+ if item['account'] == spd.account:
|
|
|
+ if item['result'] == 'PENDING':
|
|
|
+ spd.status = SplitAccountDetail.PENDING
|
|
|
+ elif item['result'] == 'SUCCESS':
|
|
|
+ spd.status = SplitAccountDetail.SUCCESS
|
|
|
+ elif item['result'] == 'CLOSED':
|
|
|
+ spd.status = SplitAccountDetail.CLOSED
|
|
|
+ spd.fail_reason = item['fail_reason']
|
|
|
+ spd.create_time = item['create_time']
|
|
|
+ spd.finish_time = item['finish_time']
|
|
|
+ spd.detail_no = item['detail_id']
|
|
|
+ spd.save()
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def _addnew(branch, order_id, rebate, customer):
|
|
|
+ if rebate <= 0:
|
|
|
+ return ''
|
|
|
+ customer_wechat = CustomerWechat.objects.filter(customer=customer).first()
|
|
|
+ if not customer_wechat:
|
|
|
+ return ''
|
|
|
+
|
|
|
+ no = "FZ" + timezone.now().strftime('%y%m%d%H%M%S') + str(order_id)
|
|
|
+ instance = SplitAccount.objects.create(
|
|
|
+ branch=branch,
|
|
|
+ no=no,
|
|
|
+ status=SplitAccount.WAIT,
|
|
|
+ amount=rebate
|
|
|
+ )
|
|
|
+
|
|
|
+ detail = SplitAccountDetail.objects.create(
|
|
|
+ main=instance,
|
|
|
+ customer=customer,
|
|
|
+ account=customer_wechat.openid,
|
|
|
+ amount=rebate
|
|
|
+ )
|
|
|
+
|
|
|
+ receiver = SplitAccountReceiver.objects.filter(account=detail.account).first()
|
|
|
+ if not receiver:
|
|
|
+ SplitAccountReceiver.objects.create(
|
|
|
+ account=detail.account
|
|
|
+ )
|
|
|
+ return instance, detail, receiver
|
|
|
+
|
|
|
+
|
|
|
+class SplitAccountDetail(models.Model):
|
|
|
+ DEFAULT = 0
|
|
|
+ PENDING = 1
|
|
|
+ SUCCESS = 2
|
|
|
+ CLOSED = 3
|
|
|
+ STATUS_CHOICES = (
|
|
|
+ (DEFAULT, u'未处理'),
|
|
|
+ (PENDING, u'待分账'),
|
|
|
+ (SUCCESS, u'分账成功'),
|
|
|
+ (CLOSED, u'已关闭'),
|
|
|
+ )
|
|
|
+
|
|
|
+ main = models.ForeignKey(SplitAccount, verbose_name=u'分账单', on_delete=models.PROTECT, editable=False)
|
|
|
+ customer = models.ForeignKey(Customer, verbose_name=u'客户', on_delete=models.PROTECT, editable=False)
|
|
|
+ account = models.CharField(max_length=100, verbose_name=u'接收账户') # 接受方的openid
|
|
|
+ amount = models.BigIntegerField(verbose_name=u'分账金额') # 单位是分
|
|
|
+ status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"分账结果", default=DEFAULT)
|
|
|
+ fail_reason = models.CharField(max_length=1000, verbose_name=u"分账失败原因", null=True, blank=True)
|
|
|
+ create_time = models.DateTimeField(verbose_name=u"分账创建时间", null=True, blank=True)
|
|
|
+ finish_time = models.DateTimeField(verbose_name=u"分账完成时间", null=True, blank=True)
|
|
|
+ detail_no = models.CharField(verbose_name=u'分账明细单号', max_length=100, null=True, editable=False)
|
|
|
+
|
|
|
+ class Meta:
|
|
|
+ db_table = "split_account_detail"
|
|
|
+ verbose_name = u"分账详细"
|
|
|
+ ordering = ('-id',)
|
|
|
+ index_together = ('status',)
|
|
|
+ default_permissions = ()
|
|
|
+
|
|
|
+
|
|
|
+class SplitAccountReceiver(models.Model):
|
|
|
+ UN_ADD = 1
|
|
|
+ ADD = 2
|
|
|
+ DELETE = 3
|
|
|
+ STATUS_CHOICES = (
|
|
|
+ (UN_ADD, u'待添加'),
|
|
|
+ (ADD, u'已添加'),
|
|
|
+ (DELETE, u'已删除'),
|
|
|
+ )
|
|
|
+
|
|
|
+ account = models.CharField(max_length=100, verbose_name=u'接收账户') # 接受方的openid
|
|
|
+ status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"状态", default=UN_ADD)
|
|
|
+ create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now)
|
|
|
+
|
|
|
+ class Meta:
|
|
|
+ db_table = "split_account_receiver"
|
|
|
+ verbose_name = u"分账接收人"
|
|
|
+ ordering = ('-id',)
|
|
|
+ index_together = ('account', 'status', )
|
|
|
+ default_permissions = ()
|
|
|
+
|
|
|
+
|
|
|
class Pay(models.Model):
|
|
|
|
|
|
WAIT = 1
|
|
@@ -83,8 +325,9 @@ class Pay(models.Model):
|
|
|
create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now)
|
|
|
customer = models.ForeignKey(Customer, verbose_name=u'客户', on_delete=models.PROTECT)
|
|
|
status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"支付状态")
|
|
|
- precreate_amount = models.BigIntegerField(verbose_name=u"预支付金额")
|
|
|
- amount = models.BigIntegerField(verbose_name=u"实际支付金额", null=True)
|
|
|
+ profit_sharing = models.CharField(max_length=10, verbose_name=u"是否分账", default="N")
|
|
|
+ precreate_amount = models.BigIntegerField(verbose_name=u"预支付金额") # 单位分
|
|
|
+ amount = models.BigIntegerField(verbose_name=u"实际支付金额", null=True) # 单位分
|
|
|
|
|
|
class Meta:
|
|
|
db_table = "pay"
|
|
@@ -124,12 +367,12 @@ class Pay(models.Model):
|
|
|
return instance
|
|
|
|
|
|
@staticmethod
|
|
|
- def wechatPay(app, branch, customer, amount, openid):
|
|
|
- instance = Pay._addnew(branch, customer, amount)
|
|
|
+ def wechatPay(app, branch, customer, amount, openid, profit_sharing):
|
|
|
+ instance = Pay._addnew(branch, customer, amount, profit_sharing)
|
|
|
return instance, instance._wechatUnifiedOrder(app, openid)
|
|
|
|
|
|
@staticmethod
|
|
|
- def _addnew(branch, customer, amount):
|
|
|
+ def _addnew(branch, customer, amount, profit_sharing):
|
|
|
if amount <= 0:
|
|
|
raise CustomError(u'无效的付款金额!')
|
|
|
|
|
@@ -138,18 +381,26 @@ class Pay(models.Model):
|
|
|
branch=branch,
|
|
|
no=no,
|
|
|
customer=customer,
|
|
|
- type=type,
|
|
|
status=Pay.WAIT,
|
|
|
- precreate_amount=amount
|
|
|
+ precreate_amount=amount,
|
|
|
+ profit_sharing=profit_sharing
|
|
|
)
|
|
|
return instance
|
|
|
|
|
|
def _wechatUnifiedOrder(self, app, openid):
|
|
|
wechatpay = WechatPay(app.authorizer_appid, app.agent_num, app.agent_key)
|
|
|
- wechatpay.unifiedOrder(self.no, self.precreate_amount, openid)
|
|
|
+ wechatpay.unifiedOrder(self.no, self.precreate_amount, openid, self.profit_sharing)
|
|
|
data = wechatpay.getAppString()
|
|
|
return data
|
|
|
|
|
|
+ def split_account(self):
|
|
|
+ order = Order.objects.filter(pay=self).first()
|
|
|
+ if order and self.status == Pay.CONFIRM and self.profit_sharing == "Y":
|
|
|
+ sp, spd, spr = SplitAccount._addnew(self.branch, self.id, self.rebate, self.recommend_member)
|
|
|
+ order.splitaccount = sp
|
|
|
+ order.save()
|
|
|
+ sp.splitAccount(spd, spr, self)
|
|
|
+
|
|
|
|
|
|
class Order(models.Model):
|
|
|
DEFAULT = 0
|
|
@@ -163,15 +414,16 @@ class Order(models.Model):
|
|
|
branch = models.ForeignKey(Branch, verbose_name=u"门店", on_delete=models.PROTECT, editable=False)
|
|
|
activity = models.ForeignKey(Activity, verbose_name=u"活动", on_delete=models.PROTECT)
|
|
|
pay = models.ForeignKey(Pay, verbose_name='支付信息', on_delete=models.PROTECT, null=True)
|
|
|
+ splitaccount = models.ForeignKey(SplitAccount, verbose_name='分账信息', on_delete=models.PROTECT, null=True)
|
|
|
member = models.ForeignKey(Customer, verbose_name=u"会员", on_delete=models.PROTECT, editable=False)
|
|
|
- amount = models.FloatField(verbose_name=u"费用", default=0)
|
|
|
+ amount = models.BigIntegerField(verbose_name=u"费用", default=0) # 单位分
|
|
|
status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"状态", default=DEFAULT, editable=False)
|
|
|
model = models.CharField(max_length=200, verbose_name=u"车型", null=True, blank=True)
|
|
|
tel = models.CharField(max_length=100, verbose_name=u"电话", null=True, blank=True)
|
|
|
number = models.CharField(max_length=50, verbose_name=u"车牌号", null=True, blank=True)
|
|
|
name = models.CharField(max_length=50, verbose_name=u"姓名", null=True, blank=True)
|
|
|
recommend_member = models.ForeignKey(Customer, verbose_name=u"推荐人", related_name='recommend_member_ref_customer', on_delete=models.PROTECT, null=True, blank=True, editable=False)
|
|
|
- rebate = models.FloatField(verbose_name=u"返利", default=0)
|
|
|
+ rebate = models.BigIntegerField(verbose_name=u"返利", default=0) # 单位分
|
|
|
create_time = models.DateTimeField(verbose_name=u"添加时间", auto_now_add=True, editable=False)
|
|
|
delete = models.BooleanField(verbose_name=u"删除", default=False)
|
|
|
|
|
@@ -191,16 +443,22 @@ class Order(models.Model):
|
|
|
total_fee = checkRexponse.orderquery(pay_no)
|
|
|
if int(total_fee) == int(self.amount):
|
|
|
wechatpay = WechatPay(app.authorizer_appid, app.agent_num, app.agent_key)
|
|
|
- data = wechatpay.unifiedOrder(openid, pay_no, self.amount)
|
|
|
+ data = wechatpay.unifiedOrder(openid, pay_no, self.amount, self.pay.profit_sharing)
|
|
|
return data
|
|
|
self.pay.payClosed()
|
|
|
|
|
|
- pay, data = Pay.wechatPay(app, self.branch, self.member, self.amount, openid)
|
|
|
+ profit_sharing = "N"
|
|
|
+ if self.rebate > 0 and self.recommend_member:
|
|
|
+ profit_sharing = "Y"
|
|
|
+ pay, data = Pay.wechatPay(app, self.branch, self.member, self.amount, openid, profit_sharing)
|
|
|
self.pay = pay
|
|
|
self.save()
|
|
|
return data
|
|
|
|
|
|
def orderPayConfirm(self, amount):
|
|
|
+ # 在这进行分账 先去查分账接收人的状态 如果没有就创建一条记录 然后添加分账接收人 然后分账
|
|
|
+ # 如果有且状态是已添加 就直接分账
|
|
|
+ # 如果有且状态是待添加或已删除 就先添加分账接收人 然后分账
|
|
|
self.status = Order.FINISH
|
|
|
self.amount = amount
|
|
|
self.save()
|