models.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. #coding=utf-8
  2. import datetime
  3. from django.db import models
  4. from django.utils import timezone
  5. from django.conf import settings
  6. from apps.exceptions import CustomError
  7. from apps.account.models import Branch
  8. from apps.customer.models import Customer, CustomerWechat
  9. from util.wechatpay import WechatPay, WeChatResponse, SplitAccountFuc
  10. from util.format import Formater
  11. class Activity(models.Model):
  12. branch = models.ForeignKey(Branch, verbose_name=u"门店", on_delete=models.PROTECT)
  13. title = models.CharField(max_length=200, verbose_name=u"标题")
  14. describe = models.TextField(verbose_name=u'活动介绍', null=True, blank=True)
  15. pic = models.CharField(max_length=500,verbose_name=u'活动图片', null=True, blank=True)
  16. end_date = models.DateField(verbose_name=u"截止日期")
  17. # amount = models.FloatField(verbose_name=u"费用", default=0)
  18. # rebate = models.FloatField(verbose_name=u"返利", default=0)
  19. check_status = models.PositiveSmallIntegerField(choices=settings.CHECK_STATUS_CHOICES, verbose_name=u"审核", editable=False, default=settings.DEFAULT)
  20. branch_name = models.CharField(max_length=200, verbose_name=u"门店名称", null=True, blank=True)
  21. branch_tel = models.CharField(max_length=50, verbose_name=u"门店电话", null=True, blank=True)
  22. branch_address = models.CharField(max_length=200, verbose_name=u"门店地址", null=True, blank=True)
  23. required_signs = models.CharField(verbose_name=u'必填项', max_length=300, null=True, editable=False)
  24. create_time = models.DateTimeField(verbose_name=u"添加时间", auto_now_add=True, editable=False)
  25. wxapp_img = models.CharField(verbose_name=u'活动二维码', max_length=250, null=True)
  26. enabled = models.BooleanField(verbose_name=u"在用", default=True)
  27. delete = models.BooleanField(verbose_name=u"删除", default=False)
  28. @staticmethod
  29. def getById1(id):
  30. try:
  31. id = int(id)
  32. except:
  33. raise CustomError(u'无效的活动Id')
  34. instance = Activity.objects.filter(pk=id).first()
  35. if not instance:
  36. raise CustomError(u'未找到相应的活动')
  37. return instance
  38. class Meta:
  39. db_table = "activity"
  40. ordering = ['-id']
  41. verbose_name = u"活动管理"
  42. def checkStatus(self):
  43. if not self.enabled:
  44. raise CustomError(u'该活动已禁用!')
  45. if self.delete:
  46. raise CustomError(u'该活动已删除!')
  47. if self.check_status != settings.PASS:
  48. raise CustomError(u'该活动尚未生效!')
  49. now = datetime.datetime.date(timezone.now())
  50. if self.end_date and now > self.end_date:
  51. raise CustomError(u'该活动已过期!')
  52. @staticmethod
  53. def getById(id):
  54. try:
  55. id = int(id)
  56. except:
  57. raise CustomError(u'无效的活动ID')
  58. instance = Activity.objects.filter(pk=id, delete=False, enabled=True).first()
  59. if not instance:
  60. raise CustomError(u'未找到相应的活动')
  61. return instance
  62. class ActivityDetails(models.Model):
  63. main = models.ForeignKey(Activity, verbose_name=u"活动", on_delete=models.PROTECT)
  64. name = models.CharField(max_length=200, verbose_name=u"名称")
  65. amount = models.FloatField(verbose_name=u"费用", default=0)
  66. rebate = models.FloatField(verbose_name=u"返利", default=0)
  67. notes = models.CharField(max_length=200, verbose_name=u"备注", blank=True, null=True)
  68. delete = models.BooleanField(verbose_name=u"删除", default=False)
  69. class Meta:
  70. db_table = "activity_details"
  71. ordering = ['-id']
  72. verbose_name = u"活动明细"
  73. @staticmethod
  74. def getById1(id):
  75. try:
  76. id = int(id)
  77. except:
  78. raise CustomError(u'无效的活动明细Id')
  79. instance = ActivityDetails.objects.filter(pk=id).first()
  80. if not instance:
  81. raise CustomError(u'未找到相应的活动明细')
  82. return instance
  83. class SplitAccount(models.Model):
  84. WAIT = 1
  85. PROCESSING = 2
  86. FINISHED = 3
  87. STATUS_CHOICES = (
  88. (WAIT, u'待分账'),
  89. (PROCESSING, u'处理中'),
  90. (FINISHED, u'分账完成'),
  91. )
  92. branch = models.ForeignKey(Branch, verbose_name=u"门店", on_delete=models.PROTECT, editable=False)
  93. no = models.CharField(max_length=64, verbose_name=u"单号")
  94. create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now)
  95. status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"分账状态", default=WAIT)
  96. amount = models.BigIntegerField(verbose_name=u"分账金额", null=True) # 单位分
  97. order_id = models.CharField(max_length=100, verbose_name=u"微信分账单号", null=True, editable=False) # 微信分账单号,微信支付系统返回的唯一标识
  98. class Meta:
  99. db_table = "split_account"
  100. verbose_name = u"分账"
  101. ordering = ('-id',)
  102. index_together = (
  103. 'create_time',
  104. 'status',
  105. )
  106. unique_together = (
  107. 'no',
  108. )
  109. default_permissions = ()
  110. def unfreezeAccount(self):
  111. # 解冻剩余资金 默认资金冻结30天 如果由于客户或其他原因 无法完成分账 就手动解除资金冻结
  112. pass
  113. def handSplitAccont(self, spd, pay, app):
  114. '''手动申请分账(在自动申请分账失败后 手动申请分账)'''
  115. spc = SplitAccountFuc(app.authorizer_appid, app.agent_num, app.cert_serial_no, app.apiv3_key)
  116. # 状态是"待分账" 的查询分账 (状态是默认的怎么处理?没有申请过的 查询分账结果会报错--如果返回错误信息根据错误信息 如果没有发现该订单就重新申请 其他原因就不再申请)
  117. if spd.status == SplitAccountDetail.PENDING:
  118. self.splictAccountQuery(spc, pay.transaction_id, self.no, spd)
  119. if spd.status == SplitAccountDetail.SUCCESS:
  120. return
  121. if spd.status == SplitAccountDetail.PENDING:
  122. return
  123. spr = SplitAccountReceiver.objects.filter(account=spd.account).first()
  124. if not spr:
  125. spr = SplitAccountReceiver.objects.create(account=spd.account)
  126. # 添加分账接收人
  127. self.splictAccountAddReceiver(spc, spr)
  128. # 分账申请
  129. receivers = [{'account': spd.account, 'amount': spd.amount, 'description': "支付推荐佣金"}]
  130. result = spc.splitaccount_order(pay.transaction_id, self.no, receivers)
  131. # 分账请求成功 结果不一定成功
  132. self.order_id = result.get('order_id')
  133. if result.get('state') == 'PROCESSING':
  134. self.status = SplitAccount.PROCESSING
  135. if result.get('state') == 'FINISHED':
  136. self.status = SplitAccount.FINISHED
  137. self.save()
  138. for item in result.get('receivers'):
  139. # 现在只对一个推荐人分账
  140. if item['account'] == spd.account:
  141. if item['result'] == 'PENDING':
  142. spd.status = SplitAccountDetail.PENDING
  143. elif item['result'] == 'SUCCESS':
  144. spd.finish_time = datetime.datetime.strptime(item['finish_time'], "%Y-%m-%dT%H:%M:%S+08:00")
  145. spd.status = SplitAccountDetail.SUCCESS
  146. elif item['result'] == 'CLOSED':
  147. spd.status = SplitAccountDetail.CLOSED
  148. spd.fail_reason = item['fail_reason']
  149. spd.create_time = datetime.datetime.strptime(item['create_time'], "%Y-%m-%dT%H:%M:%S+08:00")
  150. spd.detail_no = item['detail_id']
  151. spd.save()
  152. def updateAccountSplit(self, spd, pay, app):
  153. spc = SplitAccountFuc(app.authorizer_appid, app.agent_num, app.cert_serial_no, app.apiv3_key)
  154. self.splictAccountQuery(spc, pay.transaction_id, self.no, spd)
  155. def splictAccountAddReceiver(self, split_account_func, spr):
  156. '''添加分账接收人'''
  157. if spr.status != SplitAccountReceiver.ADD:
  158. split_account_func.splitaccount_addreceiver(spr.account)
  159. spr.status = SplitAccountReceiver.ADD
  160. spr.save()
  161. def splictAccountQuery(self, split_account_func, transaction_id, out_order_no, detail):
  162. '''查询分账结果'''
  163. result = split_account_func.splitaccount_orderquery(transaction_id, out_order_no)
  164. if result.get('state') == 'PROCESSING':
  165. self.status = SplitAccount.PROCESSING
  166. if result.get('state') == 'FINISHED':
  167. self.status = SplitAccount.FINISHED
  168. self.save()
  169. for item in result.get('receivers'):
  170. if detail and detail.account == item['account']:
  171. if item['result'] == 'SUCCESS':
  172. detail.status = SplitAccountDetail.SUCCESS
  173. detail.finish_time = datetime.datetime.strptime(item['finish_time'], "%Y-%m-%dT%H:%M:%S+08:00")
  174. elif item['result'] == 'CLOSED':
  175. detail.status = SplitAccountDetail.CLOSED
  176. detail.fail_reason = item['fail_reason']
  177. detail.create_time = datetime.datetime.strptime(item['create_time'], "%Y-%m-%dT%H:%M:%S+08:00")
  178. detail.detail_no = item['detail_id']
  179. detail.save()
  180. def splitAccount(self, app, spd, spr, pay):
  181. '''自动分账 支付成功后自动分账'''
  182. if pay.status != Pay.CONFIRM:
  183. return
  184. if spd.status != SplitAccountDetail.DEFAULT:
  185. return
  186. spc = SplitAccountFuc(app.authorizer_appid, app.agent_num, app.cert_serial_no, app.apiv3_key)
  187. if spr.status != SplitAccountReceiver.ADD:
  188. spc.splitaccount_addreceiver(spr.account)
  189. spr.status = SplitAccountReceiver.ADD
  190. spr.save()
  191. receivers = [{'account': spd.account, 'amount': spd.amount, 'description': "支付推荐佣金"}]
  192. result = spc.splitaccount_order(pay.transaction_id, self.no, receivers)
  193. self.order_id = result.get('order_id')
  194. if result.get('state') == 'PROCESSING':
  195. self.status = SplitAccount.PROCESSING
  196. if result.get('state') == 'FINISHED':
  197. self.status = SplitAccount.FINISHED
  198. self.save()
  199. for item in result.get('receivers'):
  200. if item['account'] == spd.account:
  201. if item['result'] == 'PENDING':
  202. spd.status = SplitAccountDetail.PENDING
  203. elif item['result'] == 'SUCCESS':
  204. spd.status = SplitAccountDetail.SUCCESS
  205. spd.finish_time = datetime.datetime.strptime(item['finish_time'], "%Y-%m-%dT%H:%M:%S+08:00")
  206. elif item['result'] == 'CLOSED':
  207. spd.status = SplitAccountDetail.CLOSED
  208. spd.fail_reason = item['fail_reason']
  209. spd.create_time = datetime.datetime.strptime(item['create_time'], "%Y-%m-%dT%H:%M:%S+08:00")
  210. spd.detail_no = item['detail_id']
  211. spd.save()
  212. @staticmethod
  213. def _addnew(branch, order_id, rebate, customer):
  214. if rebate <= 0:
  215. return
  216. customer_wechat = CustomerWechat.objects.filter(customer=customer).first()
  217. if not customer_wechat:
  218. return
  219. no = "FZ" + timezone.now().strftime('%y%m%d%H%M%S') + str(order_id)
  220. instance = SplitAccount.objects.create(
  221. branch=branch,
  222. no=no,
  223. status=SplitAccount.WAIT,
  224. amount=rebate
  225. )
  226. detail = SplitAccountDetail.objects.create(
  227. main=instance,
  228. customer=customer,
  229. account=customer_wechat.openid,
  230. amount=rebate
  231. )
  232. receiver = SplitAccountReceiver.objects.filter(account=detail.account).first()
  233. if not receiver:
  234. receiver = SplitAccountReceiver.objects.create(
  235. account=detail.account
  236. )
  237. return instance, detail, receiver
  238. class SplitAccountDetail(models.Model):
  239. DEFAULT = 0
  240. PENDING = 1
  241. SUCCESS = 2
  242. CLOSED = 3
  243. STATUS_CHOICES = (
  244. (DEFAULT, u'未处理'),
  245. (PENDING, u'待分账'),
  246. (SUCCESS, u'分账成功'),
  247. (CLOSED, u'已关闭'),
  248. )
  249. main = models.ForeignKey(SplitAccount, verbose_name=u'分账单', on_delete=models.PROTECT, editable=False)
  250. customer = models.ForeignKey(Customer, verbose_name=u'客户', on_delete=models.PROTECT, editable=False)
  251. account = models.CharField(max_length=100, verbose_name=u'接收账户') # 接受方的openid
  252. amount = models.BigIntegerField(verbose_name=u'分账金额') # 单位是分
  253. status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"分账结果", default=DEFAULT)
  254. fail_reason = models.CharField(max_length=1000, verbose_name=u"分账失败原因", null=True, blank=True)
  255. create_time = models.DateTimeField(verbose_name=u"分账创建时间", null=True, blank=True)
  256. finish_time = models.DateTimeField(verbose_name=u"分账完成时间", null=True, blank=True)
  257. detail_no = models.CharField(verbose_name=u'分账明细单号', max_length=100, null=True, editable=False)
  258. class Meta:
  259. db_table = "split_account_detail"
  260. verbose_name = u"分账详细"
  261. ordering = ('-id',)
  262. index_together = ('status',)
  263. default_permissions = ()
  264. class SplitAccountReceiver(models.Model):
  265. UN_ADD = 1
  266. ADD = 2
  267. DELETE = 3
  268. STATUS_CHOICES = (
  269. (UN_ADD, u'待添加'),
  270. (ADD, u'已添加'),
  271. (DELETE, u'已删除'),
  272. )
  273. account = models.CharField(max_length=100, verbose_name=u'接收账户') # 接受方的openid
  274. status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"状态", default=UN_ADD)
  275. create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now)
  276. class Meta:
  277. db_table = "split_account_receiver"
  278. verbose_name = u"分账接收人"
  279. ordering = ('-id',)
  280. index_together = ('account', 'status', )
  281. unique_together = (
  282. 'account',
  283. )
  284. default_permissions = ()
  285. class Pay(models.Model):
  286. WAIT = 1
  287. CONFIRM = 2
  288. CLOSED = 3
  289. STATUS_CHOICES = (
  290. (WAIT, u'待付款'),
  291. (CONFIRM, u'已付款'),
  292. (CLOSED, u'已关闭'),
  293. )
  294. branch = models.ForeignKey(Branch, verbose_name=u"门店", on_delete=models.PROTECT, editable=False)
  295. no = models.CharField(max_length=64, verbose_name=u"单号")
  296. transaction_id = models.CharField(max_length=100, verbose_name=u"微信支付订单号", null=True)
  297. create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now)
  298. customer = models.ForeignKey(Customer, verbose_name=u'客户', on_delete=models.PROTECT)
  299. status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"支付状态")
  300. profit_sharing = models.CharField(max_length=10, verbose_name=u"是否分账", default="N")
  301. precreate_amount = models.BigIntegerField(verbose_name=u"预支付金额") # 单位分
  302. amount = models.BigIntegerField(verbose_name=u"实际支付金额", null=True) # 单位分
  303. class Meta:
  304. db_table = "pay"
  305. verbose_name = u"支付"
  306. ordering = ('-id',)
  307. index_together = (
  308. 'create_time',
  309. 'status',
  310. )
  311. unique_together = (
  312. 'no',
  313. )
  314. default_permissions = ()
  315. def payClosed(self):
  316. if self.status != Pay.WAIT:
  317. return
  318. self.status = Pay.CLOSED
  319. self.save()
  320. def payConfirm(self, amount, transaction_id):
  321. if self.status != Pay.WAIT:
  322. return
  323. self.status = Pay.CONFIRM
  324. self.amount = Formater.formatPrice(amount)
  325. self.transaction_id = transaction_id
  326. self.save()
  327. order = Order.objects.filter(pay=self).first()
  328. if order:
  329. order.orderPayConfirm(self.amount)
  330. @staticmethod
  331. def getByNo(no):
  332. instance = Pay.objects.filter(no=no).first()
  333. if not instance:
  334. raise CustomError(u'未找到相应的支付单!')
  335. return instance
  336. @staticmethod
  337. def wechatPay(app, branch, customer, amount, openid, profit_sharing):
  338. instance = Pay._addnew(branch, customer, amount, profit_sharing)
  339. return instance, instance._wechatUnifiedOrder(app, openid)
  340. @staticmethod
  341. def _addnew(branch, customer, amount, profit_sharing):
  342. if amount <= 0:
  343. raise CustomError(u'无效的付款金额!')
  344. no = timezone.now().strftime('%y%m%d%H%M%S') + str(customer.id)
  345. instance = Pay.objects.create(
  346. branch=branch,
  347. no=no,
  348. customer=customer,
  349. status=Pay.WAIT,
  350. precreate_amount=amount,
  351. profit_sharing=profit_sharing
  352. )
  353. return instance
  354. def _wechatUnifiedOrder(self, app, openid):
  355. wechatpay = WechatPay(app)
  356. wechatpay.unifiedOrder(self.no, self.precreate_amount, openid, self.profit_sharing)
  357. data = wechatpay.getAppString()
  358. return data
  359. def split_account(self, app):
  360. order = Order.objects.filter(pay=self).first()
  361. if order and order.rebate > 0 and order.recommend_member and self.status == Pay.CONFIRM and self.profit_sharing == "Y":
  362. sp, spd, spr = SplitAccount._addnew(self.branch, order.id, order.rebate, order.recommend_member)
  363. order.splitaccount = sp
  364. order.save()
  365. # sp.splitAccount(app, spd, spr, self)
  366. class Order(models.Model):
  367. DEFAULT = 0
  368. FINISH = 1
  369. FAIL = 2
  370. STATUS_CHOICES = (
  371. (DEFAULT, u'待付款'),
  372. (FINISH, u'已完成'),
  373. (FAIL, u'失败'),
  374. )
  375. branch = models.ForeignKey(Branch, verbose_name=u"门店", on_delete=models.PROTECT, editable=False)
  376. activity = models.ForeignKey(Activity, verbose_name=u"活动", on_delete=models.PROTECT)
  377. pay = models.ForeignKey(Pay, verbose_name='支付信息', on_delete=models.PROTECT, null=True)
  378. splitaccount = models.ForeignKey(SplitAccount, verbose_name='分账信息', on_delete=models.PROTECT, null=True)
  379. member = models.ForeignKey(Customer, verbose_name=u"会员", on_delete=models.PROTECT, editable=False)
  380. amount = models.BigIntegerField(verbose_name=u"费用", default=0) # 单位分
  381. status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"状态", default=DEFAULT, editable=False)
  382. model = models.CharField(max_length=200, verbose_name=u"车型", null=True, blank=True)
  383. tel = models.CharField(max_length=100, verbose_name=u"电话", null=True, blank=True)
  384. number = models.CharField(max_length=50, verbose_name=u"车牌号", null=True, blank=True)
  385. name = models.CharField(max_length=50, verbose_name=u"姓名", null=True, blank=True)
  386. recommend_member = models.ForeignKey(Customer, verbose_name=u"推荐人", related_name='recommend_member_ref_customer', on_delete=models.PROTECT, null=True, blank=True)
  387. rebate = models.BigIntegerField(verbose_name=u"返利", default=0) # 单位分
  388. create_time = models.DateTimeField(verbose_name=u"添加时间", auto_now_add=True, editable=False)
  389. delete = models.BooleanField(verbose_name=u"删除", default=False)
  390. class Meta:
  391. db_table = "order"
  392. ordering = ['-id']
  393. verbose_name = u"订单管理"
  394. def payOrder(self, openid, app):
  395. # 如果订单上的金额不等于活动金额 (比如下单没有支付,后来活动金额修改,现在活动金额不等于订单上活动金额) 还按下单时保存到额金额支付
  396. if self.status != Order.DEFAULT:
  397. raise CustomError(u'订单非代付款状态,禁止付款')
  398. if self.pay:
  399. pay_no = self.pay.no
  400. # 先查询订单状态
  401. checkRexponse = WeChatResponse(app.authorizer_appid, app.agent_num, app.agent_key)
  402. total_fee = checkRexponse.orderquery(pay_no)
  403. if int(total_fee) == int(self.amount):
  404. wechatpay = WechatPay(app)
  405. wechatpay.unifiedOrder(pay_no, self.amount, openid, self.pay.profit_sharing)
  406. data = wechatpay.getAppString()
  407. return data
  408. self.pay.payClosed()
  409. profit_sharing = "N"
  410. if self.rebate > 0 and self.recommend_member:
  411. profit_sharing = "Y"
  412. pay, data = Pay.wechatPay(app, self.branch, self.member, self.amount, openid, profit_sharing)
  413. self.pay = pay
  414. self.save()
  415. return data
  416. def orderPayConfirm(self, amount):
  417. # 在这进行分账 先去查分账接收人的状态 如果没有就创建一条记录 然后添加分账接收人 然后分账
  418. # 如果有且状态是已添加 就直接分账
  419. # 如果有且状态是待添加或已删除 就先添加分账接收人 然后分账
  420. self.status = Order.FINISH
  421. self.amount = amount
  422. self.save()
  423. coupons = ActivityCoupon.objects.filter(activity=self.activity, coupon__enabled=True)
  424. now = datetime.datetime.date(timezone.now())
  425. for item in coupons:
  426. coupon = item.coupon
  427. if coupon.off_type == Coupon.FIXED_DATE:
  428. end_date = coupon.end_date
  429. else:
  430. end_date = now + datetime.timedelta(days=coupon.end_days)
  431. MemberCoupon.objects.create(
  432. activity=self.activity,
  433. member=self.member,
  434. coupon=coupon,
  435. receive_date=now,
  436. end_date=end_date
  437. )
  438. class Coupon(models.Model):
  439. FIXED_DATE = 0
  440. RECEIVE_TIMING = 1
  441. OFF_TYPE_CHOICES = (
  442. (FIXED_DATE, u'固定日期'),
  443. (RECEIVE_TIMING, u'领取计时'),
  444. )
  445. branch = models.ForeignKey(Branch, verbose_name=u"门店", on_delete=models.PROTECT)
  446. name = models.CharField(max_length=200, verbose_name=u"名称")
  447. off_type = models.PositiveSmallIntegerField(choices=OFF_TYPE_CHOICES, verbose_name=u"核销方式", default=FIXED_DATE)
  448. end_date = models.DateField(verbose_name=u"截止日期", null=True, blank=True)
  449. end_days = models.IntegerField(verbose_name=u"截止天数", null=True, blank=True)
  450. create_time = models.DateTimeField(verbose_name=u"添加时间", auto_now_add=True, editable=False)
  451. enabled = models.BooleanField(verbose_name=u"在用", default=True)
  452. class Meta:
  453. db_table = "coupon"
  454. ordering = ['-id']
  455. verbose_name = u"优惠券"
  456. @staticmethod
  457. def getById(id):
  458. try:
  459. id = int(id)
  460. except:
  461. raise CustomError(u'无效的优惠券')
  462. instance = Coupon.objects.filter(pk=id).first()
  463. if not instance:
  464. raise CustomError(u'未找到相应的优惠券')
  465. return instance
  466. class MemberCoupon(models.Model):
  467. activity = models.ForeignKey(Activity, verbose_name=u"活动", on_delete=models.PROTECT)
  468. member = models.ForeignKey(Customer, verbose_name=u"会员", on_delete=models.PROTECT)
  469. coupon = models.ForeignKey(Coupon, verbose_name=u"优惠券", on_delete=models.PROTECT)
  470. receive_date = models.DateField(verbose_name=u"领取日期", null=True, blank=True)
  471. end_date = models.DateField(verbose_name=u"有效期至", null=True, blank=True)
  472. write_off = models.BooleanField(verbose_name=u"核销", default=False)
  473. write_off_time = models.DateTimeField(verbose_name=u"核销时间", editable=False, null=True, blank=True)
  474. class Meta:
  475. db_table = "member_coupon"
  476. ordering = ['-id']
  477. verbose_name = u"会员优惠券"
  478. def writeOff(self):
  479. now = datetime.datetime.date(timezone.now())
  480. if self.write_off:
  481. raise CustomError(u'该优惠券已核销,禁止重复使用!')
  482. if self.end_date and now > self.end_date:
  483. raise CustomError(u'该优惠券已过有效期,禁止使用!')
  484. self.write_off = True
  485. self.write_off_time = timezone.now()
  486. self.save()
  487. def cancelWriteOff(self):
  488. if not self.write_off:
  489. raise CustomError(u'该优惠券尚未核销,禁止撤销!')
  490. self.write_off = False
  491. self.write_off_time = None
  492. self.save()
  493. @staticmethod
  494. def getById(id):
  495. try:
  496. id = int(id)
  497. except:
  498. raise CustomError(u'无效的会员优惠券ID')
  499. instance = MemberCoupon.objects.filter(pk=id).first()
  500. if not instance:
  501. raise CustomError(u'未找到相应的会员优惠券')
  502. return instance
  503. class ActivityCoupon(models.Model):
  504. #activity = models.ForeignKey(Activity, verbose_name=u"活动", on_delete=models.PROTECT)
  505. main = models.ForeignKey(ActivityDetails, verbose_name=u"活动明细", on_delete=models.PROTECT)
  506. coupon = models.ForeignKey(Coupon, verbose_name=u"优惠券", on_delete=models.PROTECT)
  507. class Meta:
  508. db_table = "activity_coupon"
  509. ordering = ['-id']
  510. verbose_name = u"活动优惠券"