def _pay_detail(self, body, mount_price, opayno, openid): body = re.sub("[\s+\.\!\/_,$%^*(+\"\'\-_]+|[+——!,。?、~@#¥%……&*()]+", '', body) current_app.logger.info('get mount price {}'.format(mount_price)) mount_price = 0.01 if API_HOST != 'https://planet.sanbinit.cn' else mount_price # todo 测试域名下来之后配置 current_app.logger.info('openid is {}, out_trade_no is {} '.format(openid, opayno)) # 微信支付的单位是'分', 支付宝使用的单位是'元' try: body = body[:16] + '...' current_app.logger.info('body is {}, wechatpay'.format(body)) wechat_pay_dict = { 'body': body, 'out_trade_no': opayno, 'total_fee': int(mount_price * 100), 'attach': 'attach', 'spbill_create_ip': request.remote_addr } if not openid: raise StatusError('用户未使用微信登录') # wechat_pay_dict.update(dict(trade_type="JSAPI", openid=openid)) wechat_pay_dict.update({ 'trade_type': 'JSAPI', 'openid': openid }) raw = self.wx_pay.jsapi(**wechat_pay_dict) except WeixinPayError as e: raise SystemError('微信支付异常: {}'.format('.'.join(e.args))) return raw
def _pay_to_bankcard(self, cn): """ 付款到银行卡号 :param cn: :return: """ try: enc_bank_no = self._to_encrypt(cn.CNcardNo) enc_true_name = self._to_encrypt(cn.CNcardName) bank_code = WexinBankCode(cn.CNbankName).zh_value except Exception as e: current_app.logger.error('提现到银行卡,参数加密出错:{}'.format(e)) raise ParamsError('服务器繁忙,请稍后再试') try: result = self.wx_pay.pay_individual_to_card( partner_trade_no=self.wx_pay.nonce_str, enc_bank_no=enc_bank_no, enc_true_name=enc_true_name, bank_code=bank_code, amount=int(Decimal(cn.CNcashNum).quantize(Decimal('0.00')) * 100) ) current_app.logger.info('微信提现到银行卡, response: {}'.format(request)) except Exception as e: current_app.logger.error('微信提现返回错误:{}'.format(e)) raise StatusError('微信商户平台: {}'.format(e)) return result
def product_verified(self): """商品核销""" data = parameter_required('param') param = data.get('param') try: omid, secret_usid = str(param).split('&') if not omid.startswith('omid'): raise ValueError except ValueError: raise ParamsError('该二维码无效') current_app.logger.info('omid: {}, secret_usid: {}'.format(omid, secret_usid)) omid = str(omid).split('=')[-1] secret_usid = str(secret_usid).split('=')[-1] current_app.logger.info('splited, omid: {}, secret_usid: {}'.format(omid, secret_usid)) if not omid or not secret_usid: raise StatusError('该试用码无效') ticket_usid = self.cuser._base_decode(secret_usid) ticket_user = User.query.filter(User.isdelete == false(), User.USid == ticket_usid).first_('无效试用码') om = OrderMain.query.filter(OrderMain.isdelete == false(), OrderMain.OMid == omid).first_('订单状态异常') if om.OMstatus != OrderStatus.has_won.value: current_app.logger.error('om status: {}'.format(om.TSOstatus)) raise StatusError('提示:该二维码已被核销过') pr = Product.query.filter(Product.PRid == om.PRid).first() if pr.PRtimeLimeted and (pr.PRuseStartTime <= datetime.now() <= pr.PRuseEndTime): raise StatusError('当前时间不在该券有效使用时间内') user = User.query.join(ProductVerifier, ProductVerifier.PVphone == User.UStelephone ).join(Product, Product.SUid == ProductVerifier.SUid ).filter(User.isdelete == false(), User.USid == getattr(request, 'user').id, ProductVerifier.SUid == pr.SUid ).first_('请确认您是否拥有该券的核销权限') with db.auto_commit(): # 订单改状态 om.update({'OMstatus': OrderStatus.completed.value}) db.session.add(om) # 核销记录 tvr = ProductVerifiedRecord.create({'PVRid': str(uuid.uuid1()), 'ownerId': ticket_user.USid, 'VerifierId': user.USid, 'OMid': om.OMid, 'param': param}) db.session.add(tvr) return Success('二维码验证成功', data=tvr.PVRid)
def _check_time(self, time_model, fmt='%Y/%m/%d'): if isinstance(time_model, datetime): return time_model.strftime(fmt) else: try: return datetime.strptime(str(time_model), '%Y-%m-%d %H:%M:%S').strftime(fmt) except: current_app.logger.error('时间转换错误') raise StatusError('系统异常,请联系客服解决')
def img_check(filepath, msg='图片'): """ 图片校验 :param msg: msg :param filepath: 完整的绝对路径 :return: """ try: filesize = os.path.getsize(filepath) except FileNotFoundError: current_app.logger.error('FileNotFoundError: {}'.format(filepath)) raise StatusError('服务器繁忙, 请稍后再试') current_app.logger.info('size {} MB'.format( round(filesize / 1048576, 2))) if filesize > 1024 * 1024: current_app.logger.info( 'content size out of limit, path :{}'.format(filepath)) # 图片太大 from PIL import Image img = Image.open(filepath) x, y = img.size x_ = 750 y_ = int(y * (x / x_)) if y_ > 1000: y_ = 1000 time_now = datetime.now() year = str(time_now.year) month = str(time_now.month) day = str(time_now.day) tmp_path = os.path.join(current_app.config['BASEDIR'], 'img', 'temp', year, month, day) if not os.path.isdir(tmp_path): os.makedirs(tmp_path) tmp_path = os.path.join(tmp_path, os.path.basename(filepath)) img.resize((x_, y_), Image.LANCZOS).save(tmp_path) filepath = tmp_path current_app.logger.info('compressed size {} MB, path :{}'.format( round(os.path.getsize(filepath) / 1048576, 2), filepath)) try: check_result = mp_miniprogram.img_sec_check(filepath) current_app.logger.info(check_result) except WeixinMPError as e: current_app.logger.info('error is {}'.format(e)) current_app.logger.error('傻逼在发黄色图片 usid = {}'.format( getattr(request, 'user').id)) raise ParamsError('{}可能存在违法违规等不良信息,请检查后重试'.format(msg))
def pay_to_user(self, cn): """ 付款到用户微信零钱 :return: """ user = User.query.filter_by_(USid=cn.USid).first_("提现用户状态异常,请检查后重试") try: result = self.wx_pay.pay_individual( partner_trade_no=self.wx_pay.nonce_str, openid=user.USopenid2, amount=int(Decimal(cn.CNcashNum).quantize(Decimal('0.00')) * 100), desc="优惠下沙-零钱转出", spbill_create_ip=self.wx_pay.remote_addr ) current_app.logger.info('微信提现到零钱, response: {}'.format(request)) except Exception as e: current_app.logger.error('微信提现返回错误:{}'.format(e)) raise StatusError('微信商户平台: {}'.format(e)) return result
def set_verifier(self): form = SetVerifier().valid_data() if is_admin(): suid = form.suid.data assert suid, '供应商未指定' elif is_supplizer(): suid = request.user.id else: raise AuthorityError() sup = Supplizer.query.filter( Supplizer.isdelete == false(), Supplizer.SUstatus == UserStatus.usual.value, Supplizer.SUid == suid).first_('供应商状态异常') if sup.SUgrade != SupplizerGrade.ticket.value: raise StatusError('仅虚拟商品供应商可设置核销员') phone_list = form.phone_list.data tvid_list = [] instence_list = [] phone_list = {}.fromkeys(phone_list).keys() with db.auto_commit(): for phone in phone_list: User.query.filter( User.isdelete == false(), User.UStelephone == phone).first_(f'没有手机号为 {phone} 用户 ') tv = ProductVerifier.query.filter_by(SUid=suid, PVphone=phone).first() if not tv: tv = ProductVerifier.create({ 'PVid': str(uuid.uuid1()), 'SUid': suid, 'PVphone': phone }) instence_list.append(tv) tvid_list.append(tv.PVid) db.session.add_all(instence_list) # 删除无效的 ProductVerifier.query.filter( ProductVerifier.isdelete == false(), ProductVerifier.SUid == suid, ProductVerifier.PVid.notin_(tvid_list)).delete_( synchronize_session=False) return Success('修改成功', data=suid)
def pay(self): """购买""" data = parameter_required() prid, ompaytype = data.get('prid'), data.get('ompaytype') try: ompaytype = PayType(int(ompaytype)).value except (ValueError, AttributeError, TypeError): raise ParamsError('支付方式错误') # if not is_user(): # raise AuthorityError user = self._current_user('请重新登录') opayno = self._opayno() now = datetime.now() product = Product.query.filter(Product.PRid == prid, Product.PRstatus == ProductStatus.active.value, Product.isdelete == false()).first_('商品已下架') if product.PRtimeLimeted: starttime = self._check_time(product.PRissueStartTime) endtime = self._check_time(product.PRissueEndTime) if starttime and now < starttime: raise StatusError('商品未到发放时间') if endtime and now > endtime: raise StatusError('商品已过发放时间') trade = self._query_traded(prid, user.USid) # 直购不限制 redirect = False omid = str(uuid.uuid1()) with db.auto_commit(): if ompaytype == PayType.cash.value: # 直购 mount_price = Decimal(product.PRtruePrice) if mount_price == Decimal('0'): redirect = True trade = False elif ompaytype == PayType.scorepay.value: # 活跃分 # if not user.USrealname: # 暂时除去实名验证 # raise StatusError('用户未进行信用认证') if not product.PRtimeLimeted: raise StatusError('活跃分支持限时商品') mount_price = 0 redirect = True else: raise StatusError('支付方式错误') if trade: raise StatusError('您已申请成功,请在“我的 - 我的试用”中查看') omdict = { "OMid": omid, "OMno": self._generic_omno(), "OPayno": opayno, "USid": user.USid, "PRid": prid, "OMmount": product.PRlinePrice, "OMtrueMount": mount_price, "OMpayType": ompaytype, "PRcreateId": product.CreatorId, "PRname": product.PRname, "PRimg": product.PRimg, "OPnum": 1, # 目前没有添加数量 } if ompaytype == PayType.cash.value: user_subcommision = UserSubCommission.query.filter(UserSubCommission.USid == user.USid, UserSubCommission.isdelete == 0)\ .first() user_super_level = user_subcommision.USCsuperlevel if user_super_level == 3: pass elif user_super_level == 2: omdict.setdefault('UPperid3', user_subcommision.USCsupper3) elif user_super_level == 1: omdict.setdefault('UPperid2', user_subcommision.USCsupper2) omdict.setdefault('UPperid3', user_subcommision.USCsupper3) else: omdict.setdefault('UPperid', user_subcommision.USCsupper1) omdict.setdefault('UPperid2', user_subcommision.USCsupper2) omdict.setdefault('UPperid3', user_subcommision.USCsupper3) if data.get('shareid'): omdict.setdefault('UPshareid', data.get('shareid')) # 极差分佣暂时不需要 # omdict.setdefault('USCommission1', user.USCommission1) # omdict.setdefault('USCommission2', user.USCommission2) # omdict.setdefault('USCommission3', user.USCommission3) om = OrderMain.create(omdict) # product.PRnum -= 1 # 商品库存修改 # 0618 fix 非商品逻辑,不能改库存数 # 月销量 修改或新增 today = datetime.now() month_sale_instance = ProductMonthSaleValue.query.filter( ProductMonthSaleValue.isdelete == false(), ProductMonthSaleValue.PRid == product.PRid, extract('month', ProductMonthSaleValue.createtime) == today.month, extract('year', ProductMonthSaleValue.createtime) == today.year, ).first() if not month_sale_instance: month_sale_instance = ProductMonthSaleValue.create({'PMSVid': str(uuid.uuid1()), 'PRid': prid, 'PMSVnum': 1, 'PMSVfakenum': 1 }) else: month_sale_instance.update({'PMSVnum': ProductMonthSaleValue.PMSVnum + 1, 'PMSVfakenum': ProductMonthSaleValue.PMSVfakenum + 1}) db.session.add(month_sale_instance) db.session.add(product) db.session.add(om) body = product.PRname[:16] + '...' openid = user.USopenid1 # 直购订单 不付款 5秒后 自动取消 if not product.PRtimeLimeted: # add_async_task(auto_cancle_order, now + timedelta(minutes=1), (omid,), conn_id='autocancle{}'.format(omid)) auto_cancle_order.apply_async(args=(omid,), countdown=5, expires=10, queue='high_priority') pay_args = self._add_pay_detail(opayno=opayno, body=body, mount_price=mount_price, openid=openid, opayType=ompaytype, redirect=redirect) response = { 'pay_type': 'wechat_pay', 'opaytype': ompaytype, # 'tscode': tscode_list, 'args': pay_args, 'redirect': redirect } current_app.logger.info('response = {}'.format(response)) return Success(data=response)
def level_commisions(cls): commision = cls.query.filter(cls.isdelete == False).first() if commision: level_commision = json.loads(commision.Levelcommision) return level_commision raise StatusError('项目需要初始化')
def devide_rate_baseline(cls): commision = cls.query.filter(cls.isdelete == False).first() if commision: level_commision = json.loads(commision.Levelcommision) return level_commision[-1] raise StatusError('项目需要初始化')
def update_product(self): """编辑商品""" if is_admin(): product_from = ProductFrom.platform.value elif is_supplizer(): product_from = ProductFrom.supplizer.value else: raise AuthorityError('当前用户无权进行该操作') data = parameter_required('prid') product = Product.query.filter(Product.isdelete == false(), Product.PRid == data.get('prid')).first_('未找到该商品信息') if Product.query.filter(Product.isdelete == false(), Product.PRname == data.get('prname'), Product.PRid != Product.PRid, Product.PRstatus != ProductStatus.over.value).first(): raise ParamsError('该商品名已存在') approval_flag = 0 with db.auto_commit(): if data.get('delete'): if product.PRstatus == ProductStatus.active.value: raise ParamsError('无法直接删除正在发放中的商品') if OrderMain.query.filter(OrderMain.isdelete == false(), OrderMain.OMstatus > OrderStatus.not_won.value, OrderMain.PRid == product.PRid).first(): raise StatusError('暂时无法直接删除已产生购买记录的商品') product.update({'isdelete': True}) # 取消异步任务 cancel_async_task('start_product{}'.format(product.PRid)) cancel_async_task('end_product{}'.format(product.PRid)) self.base_admin.create_action(AdminActionS.delete.value, 'Product', product.PRid) # 同时将正在进行的审批流改为取消 self.base_approval.cancel_approval(product.PRid, request.user.id) elif data.get('interrupt'): if product.PRstatus > ProductStatus.active.value: raise StatusError('该状态下无法中止') product.update({'PRstatus': ProductStatus.interrupt.value}) cancel_async_task('start_product{}'.format(product.PRid)) cancel_async_task('end_product{}'.format(product.PRid)) self.base_admin.create_action(AdminActionS.update.value, 'Product', product.PRid) # 同时将正在进行的审批流改为取消 self.base_approval.cancel_approval(product.PRid, request.user.id) else: approval_flag = 1 if product.PRstatus < ProductStatus.interrupt.value: raise ParamsError('仅可编辑已中止发放或已结束的商品') product_dict = self._validate_ticket_param(data) product_dict.update({'PRname': data.get('prname'), 'PRimg': data.get('primg'), 'PRdetails': data.get('prdetails'), # 'PRstatus': ProductStatus.ready.value if product_dict.get( # 'PRtimeLimeted') else ProductStatus.active.value, 'PRstatus': ProductStatus.pending.value }) self.base_approval.cancel_approval(product.PRid, request.user.id) # 同时将正在进行的审批流改为取消 if product.PRstatus == ProductStatus.interrupt.value: # 中止的情况 current_app.logger.info('edit interrupt ticket') product.update(product_dict, null='not') else: # 已结束的情况,重新发起 current_app.logger.info('edit ended ticket') product_dict.update({'PRid': str(uuid.uuid1()), 'CreatorId': getattr(request, 'user').id, 'CreatorType': getattr(request, 'user').model}) product = Product.create(product_dict) cancel_async_task('start_product{}'.format(product.PRid)) cancel_async_task('end_product{}'.format(product.PRid)) self.base_admin.create_action(AdminActionS.insert.value, 'Product', product.PRid) db.session.add(product) if approval_flag: self.base_approval.create_approval('toshelves', request.user.id, product.PRid, product_from) return Success('编辑成功', data={'prid': product.PRid})