models.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. # coding=utf-8
  2. from django.db import models
  3. from django.conf import settings
  4. from django.utils import timezone
  5. from django.db.models import F
  6. from apps.option.models import Option
  7. from apps.config.models import Config
  8. from apps.commodity.models import Commodity
  9. from apps.customer.models import Customer, CustomerAddress, SuperiorDistributor
  10. from utils.exceptions import CustomError
  11. from utils.wechatpay import WechatPay, WeChatResponse
  12. class Pay(models.Model):
  13. WAIT = 1
  14. PAY = 2
  15. UNDO = 3
  16. STATUS_CHOICES = (
  17. (WAIT, u'待付款'),
  18. (PAY, u'已付款'),
  19. (UNDO, u'已取消'),
  20. )
  21. no = models.CharField(max_length=64, verbose_name=u"单号")
  22. status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u'状态', default=WAIT)
  23. precreate_amount = models.BigIntegerField(verbose_name=u"预支付金额")
  24. amount = models.BigIntegerField(verbose_name=u"支付金额", null=True)
  25. transaction_id = models.CharField(max_length=100, verbose_name=u"微信支付订单号", null=True)
  26. customer = models.ForeignKey(Customer, verbose_name=u'下单人', related_name='pay_customer', on_delete=models.PROTECT)
  27. create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now)
  28. class Meta:
  29. db_table = "pay"
  30. verbose_name = u"支付信息"
  31. ordering = ('-id',)
  32. index_together = (
  33. 'create_time',
  34. 'status',
  35. )
  36. unique_together = (
  37. 'no',
  38. )
  39. default_permissions = ()
  40. @staticmethod
  41. def wechatPay(amount, customer, appid, openid):
  42. instance = Pay._addnew(amount, customer)
  43. return instance, instance._wechatUnifiedOrder(appid, openid)
  44. @staticmethod
  45. def _addnew(amount, customer):
  46. if amount <= 0:
  47. raise CustomError(u'无效的付款金额!')
  48. pay_no = '{}{}'.format(timezone.now().strftime('%y%m%d%H%M%S'), str(customer.id))
  49. pay = Pay.objects.create(no=pay_no, status=Pay.WAIT, precreate_amount=amount, customer=customer)
  50. return pay
  51. def _wechatUnifiedOrder(self, appid, openid):
  52. wechatpay = WechatPay(appid)
  53. wechatpay.unifiedOrder(self.no, self.precreate_amount, openid)
  54. data = wechatpay.getAppString()
  55. return data
  56. @staticmethod
  57. def getByNo(no):
  58. instance = Pay.objects.filter(no=no).first()
  59. if not instance:
  60. raise CustomError(u'未找到相应的支付单!')
  61. return instance
  62. def payClosed(self):
  63. if self.status != Pay.WAIT:
  64. return
  65. self.status = Pay.UNDO
  66. self.save()
  67. def payConfirm(self, amount, transaction_id):
  68. if self.status != Pay.WAIT:
  69. return
  70. self.status = Pay.PAY
  71. self.amount = amount
  72. self.transaction_id = transaction_id
  73. self.save()
  74. order = Order.objects.filter(pay=self).first()
  75. if order:
  76. order.orderPayConfirm()
  77. class ShoppingCart(models.Model):
  78. commodity_details = models.ForeignKey(Commodity, verbose_name=u'产品明细', on_delete=models.PROTECT)
  79. quantity = models.PositiveIntegerField(verbose_name=u'数量', default=1)
  80. create_time = models.DateTimeField(verbose_name=u'创建时间', auto_now_add=True)
  81. customer = models.ForeignKey(Customer, related_name='shopping_cart_customer', verbose_name=u"下单人", on_delete=models.PROTECT, editable=False)
  82. class Meta:
  83. db_table = 'shopping_cart'
  84. verbose_name = u'购物车'
  85. ordering = ['-id', ]
  86. default_permissions = ()
  87. class Order(models.Model):
  88. WAIT_PAY = 0
  89. WAIT_DISPATCH = 1
  90. CONFIRM_DISPATCH = 2
  91. CANCEL = 3
  92. STATUS_CHOICES = (
  93. (WAIT_PAY, u'待付款'),
  94. (WAIT_DISPATCH, u'待发货'),
  95. (CONFIRM_DISPATCH, u'已发货'),
  96. (CANCEL, u'已取消'),
  97. )
  98. no = models.CharField(max_length=50, verbose_name=u'订单号', editable=False, null=True, blank=True)
  99. pay = models.ForeignKey(Pay, verbose_name=u'支付信息', on_delete=models.PROTECT, null=True, editable=False)
  100. total_count = models.IntegerField(verbose_name=u'总数量', default=0, editable=False)
  101. total_amount = models.BigIntegerField(verbose_name=u'总金额', default=0, editable=False)
  102. total_point = models.IntegerField(verbose_name=u'总积分', default=0, editable=False)
  103. status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, verbose_name=u"订单状态", default=WAIT_PAY)
  104. notes = models.CharField(max_length=500, verbose_name=u"备注", null=True, blank=True)
  105. customer = models.ForeignKey(Customer, verbose_name=u'创建人', editable=False, on_delete=models.PROTECT)
  106. create_time = models.DateTimeField(verbose_name=u"创建时间", default=timezone.now, editable=False)
  107. cancel_reason = models.CharField(max_length=100, verbose_name=u"取消原因", null=True, blank=True)
  108. cancel_user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='order_cancel_user', verbose_name=u"取消人", on_delete=models.PROTECT, null=True, blank=True)
  109. cancel_time = models.DateTimeField(verbose_name=u"取消时间", null=True, blank=True)
  110. address = models.ForeignKey(CustomerAddress, verbose_name=u'收货地址', related_name='order_address', null=True, blank=True, on_delete=models.PROTECT)
  111. name = models.CharField(verbose_name=u'收货人', max_length=20, null=True, blank=True)
  112. tel = models.CharField(verbose_name=u'收货电话', max_length=15, null=True, blank=True)
  113. user_address = models.CharField(verbose_name=u'详细地址', max_length=200, null=True, blank=True)
  114. express_no = models.CharField(max_length=50, verbose_name=u'快递单号', null=True, blank=True)
  115. express_company = models.ForeignKey(Option, verbose_name=u'快递公司', on_delete=models.PROTECT, null=True, blank=True)
  116. dispatch_time = models.DateTimeField(verbose_name=u'发货时间', null=True, blank=True)
  117. dispatch_user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='order_dispatch_user', verbose_name=u"发货人", on_delete=models.PROTECT, null=True, blank=True)
  118. class Meta:
  119. db_table = "order"
  120. verbose_name = u"客户订单"
  121. ordering = ('-id',)
  122. index_together = ('status', 'create_time', 'no', )
  123. default_permissions = ()
  124. permissions = []
  125. def generateNo(self):
  126. '''
  127. 生成订单的订单号(注意:该函数最后没有 save 要在调用该函数后save )
  128. :return:
  129. '''
  130. no = '{}{}{:0>4}'.format('XCX', timezone.now().strftime('%Y%m%d'), self.id)
  131. self.no = no
  132. def set_order_adderss(self, address_id):
  133. '''
  134. 下单时保存用户选择的收货地址(注意:该函数最后没有 save 要在调用该函数后save )
  135. :param address_id: 收货地址id
  136. :return:
  137. '''
  138. address = CustomerAddress.objects.filter(id=address_id).first()
  139. if not address:
  140. raise CustomError(u'请选择正确的收货地址!')
  141. if address.delete:
  142. raise CustomError(u'该收货地址已删除,请选择重新选择收货地址!')
  143. self.address = address
  144. self.name = address.name
  145. self.tel = address.tel
  146. self.user_address = address.get_address()
  147. def set_order_detail(self, details):
  148. '''
  149. 下单时保存选择的商品明细(注意:该函数最后没有 save 要在调用该函数后save )
  150. :param details: 商品明细
  151. :return:
  152. '''
  153. total_count = total_amount = total_point = 0
  154. create_data = []
  155. for item in details:
  156. commodity = Commodity.objects.filter(id=item['id']).first()
  157. if not commodity:
  158. raise CustomError(u'您选择的商品不存在,请刷新后重新选择!')
  159. if commodity.delete:
  160. raise CustomError(u'商品【{}】已下架!'.format(commodity.name))
  161. if commodity.status != settings.ONLINE:
  162. raise CustomError(u'商品【{}】已下架!'.format(commodity.name))
  163. try:
  164. count = int(item['count'])
  165. except:
  166. raise CustomError(u'商品数量错误,请重新选择!')
  167. if count <= 0:
  168. raise CustomError(u'商品数量错误,请重新选择!')
  169. amount = point_amount = 0
  170. if commodity.type == Commodity.POINT:
  171. point_amount = commodity.point_price * count
  172. elif commodity.type == Commodity.CASH:
  173. amount = commodity.price * count
  174. else:
  175. continue
  176. d = OrderDetails(
  177. order=self,
  178. commodity=commodity,
  179. price=commodity.price,
  180. point=commodity.point_price,
  181. count=count,
  182. amount=amount,
  183. point_amount=point_amount
  184. )
  185. create_data.append(d)
  186. total_point += point_amount
  187. total_amount += amount
  188. total_count += count
  189. OrderDetails.objects.bulk_create(create_data)
  190. self.total_count = total_count
  191. self.total_amount = total_amount
  192. self.total_point = total_point
  193. def pointConfirm(self):
  194. '''
  195. 积分兑换 确认兑换成功 当只购买了积分商品的时候 使用本函数确认 有现金商品的时候使用pay下边的确认函数确认
  196. 注意 order最后没有save() 在调用该函数后order要save()
  197. :return:
  198. '''
  199. if self.status != Order.WAIT_PAY:
  200. return
  201. self.status = Order.WAIT_DISPATCH
  202. commodity_id = Config.get_commodity()
  203. # 这一点儿不能用这个 不然 数据customer数据重新保存了 积分那一块儿的就不行了
  204. customer = Customer.objects.filter(id=self.customer.id).first()
  205. detail = OrderDetails.objects.filter(order=self)
  206. for item in detail:
  207. commodity = item.commodity
  208. commodity.total_sales += item.count
  209. commodity.save()
  210. if not commodity_id:
  211. continue
  212. if commodity.id != commodity_id:
  213. continue
  214. if customer.is_distributor:
  215. continue
  216. customer.is_distributor = True
  217. customer.total_point += self.total_point
  218. customer.success_count += 1
  219. customer.save()
  220. def orderPay(self, openid, appid):
  221. if self.status != Order.WAIT_PAY:
  222. raise CustomError(u'订单费待付款状态,禁止付款!')
  223. if self.pay:
  224. pay_no = self.pay.no
  225. # 先查询订单状态
  226. checkRexponse = WeChatResponse(appid)
  227. total_fee = checkRexponse.OrderQuery(pay_no)
  228. if int(total_fee) == int(self.total_amount):
  229. wechatpay = WechatPay(appid)
  230. wechatpay.unifiedOrder(pay_no, self.total_amount, openid)
  231. data = wechatpay.getAppString()
  232. return data
  233. self.pay.payClosed()
  234. def orderPayConfirm(self):
  235. self.status = Order.WAIT_DISPATCH
  236. self.save()
  237. # 购买指定的商品 成为分销商
  238. commodity_id = Config.get_commodity()
  239. point_rule = Config.get_value(Config.KEY_POINT_RULE)
  240. customer = Customer.objects.filter(id=self.customer.id).first()
  241. detail = OrderDetails.objects.filter(order=self)
  242. for item in detail:
  243. commodity = item.commodity
  244. commodity.total_sales += item.count
  245. commodity.save()
  246. if not commodity_id:
  247. continue
  248. if commodity.id != commodity_id:
  249. continue
  250. if customer.is_distributor:
  251. continue
  252. customer.is_distributor = True
  253. customer.success_count += 1
  254. customer.total_amount += self.total_amount
  255. customer.total_point += self.total_point
  256. customer.save()
  257. class OrderDetails(models.Model):
  258. order = models.ForeignKey(Order, verbose_name=u'订单', on_delete=models.PROTECT)
  259. commodity = models.ForeignKey(Commodity, verbose_name=u'商品', on_delete=models.PROTECT)
  260. price = models.BigIntegerField(verbose_name=u'价格', null=True, default=0)
  261. point = models.IntegerField(verbose_name=u'积分', null=True, default=0)
  262. count = models.IntegerField(verbose_name=u'数量', null=True, default=0)
  263. amount = models.BigIntegerField(verbose_name=u'总金额', null=True, default=0)
  264. point_amount = models.IntegerField(verbose_name=u'总积分', null=True, default=0)
  265. class Meta:
  266. db_table = u'order_details'
  267. verbose_name = u'订单明细'
  268. ordering = ('-id', )
  269. default_permissions = ()
  270. permissions = []