def auto_cancle_order(omids): for omid in omids: from planet.control.COrder import COrder order_main = OrderMain.query.filter( OrderMain.isdelete == False, OrderMain.OMstatus == OrderMainStatus.wait_pay.value, OrderMain.OMid == omid).first() if not order_main: current_app.logger.info('订单已支付或已取消') return current_app.logger.info('订单自动取消{}'.format(dict(order_main))) corder = COrder() corder._cancle(order_main)
def auto_confirm_order(): """已签收7天自动确认收货, 在物流跟踪上已经签收, 但是用户没有手动签收的订单""" from planet.models import OrderLogistics from planet.control.COrder import COrder cfs = ConfigSettings() auto_confirm_day = int(cfs.get_item('order_auto', 'auto_confirm_day')) time_now = datetime.now() corder = COrder() order_mains = OrderMain.query.filter( OrderMain.isdelete == False, OrderMain.OMstatus == OrderMainStatus.wait_recv.value, OrderLogistics.OMid == OrderMain.OMid, OrderLogistics.isdelete == False, OrderLogistics.OLsignStatus == LogisticsSignStatus.already_signed.value, OrderLogistics.updatetime <= time_now - timedelta(days=auto_confirm_day)).all() current_app.logger.info('自动确认收货, 共{}个订单'.format(len(order_mains))) for order_main in order_mains: with db.auto_commit(): order_main = corder._confirm(order_main=order_main)
def auto_complete_order(self): data = parameter_required(('omno', )) omno = data.get('omno') with db.auto_commit(): corder = COrder() order_main = OrderMain.query.filter( OrderMain.OMno == omno, OrderMain.isdelete == False, OrderMain.OMstatus == OrderMainStatus.wait_comment.value, ).first_("该订单不存在或不是待收货状态") current_app.logger.info("订单OMid: {} 开始运行自动完成任务".format( order_main.OMid)) order_parts = OrderPart.query.filter_by_( OMid=order_main.OMid).all() # 主单下所有副单 current_app.logger.info("该订单下有 {} 个副单".format(len(order_parts))) for order_part in order_parts: current_app.logger.info("副单OPid {} ".format(order_part.OPid)) user = User.query.filter_by(USid=order_main.USid, isdelete=False).first_("订单用户不存在") try: current_app.logger.info("开始进行佣金到账") corder._fresh_commsion_into_count(order_part) # 佣金到账 except Exception as e: current_app.logger.error("佣金到账出错: {}".format(e)) current_app.logger.info("佣金到账结束") try: current_app.logger.info("开始进行销售量统计") corder._tosalesvolume(order_main.OMtrueMount, user.USid) # 销售额统计 except Exception as e: current_app.logger.error("销售量统计出错: {}".format(e)) usname, usheader = user.USname, user.USheader # 创建评价 evaluation_dict = { 'OEid': str(uuid.uuid1()), 'USid': order_main.USid, 'USname': usname, 'USheader': usheader, 'OPid': order_part.OPid, 'OMid': order_main.OMid, 'PRid': order_part.PRid, 'SKUattriteDetail': order_part.SKUattriteDetail, 'OEtext': '此用户没有填写评价。', 'OEscore': 5, } db.session.add(OrderEvaluation.create(evaluation_dict)) # 更改商品评分 try: product_info = Products.query.filter_by_( PRid=order_part.PRid).first_("商品不存在") scores = [ oe.OEscore for oe in OrderEvaluation.query.filter( OrderEvaluation.PRid == product_info.PRid, OrderEvaluation.isdelete == False).all() ] average_score = round(((float(sum(scores)) + float(5.0)) / (len(scores) + 1)) * 2) Products.query.filter_by(PRid=order_part.PRid).update( {'PRaverageScore': average_score}) except Exception as e: current_app.logger.info( "更改商品评分失败, 商品可能已被删除;Update Product Score ERROR :{}". format(e)) # 物流同步更改状态 ol = OrderLogistics.query.filter( OrderLogistics.OMid == order_part.OMid, OrderLogistics.isdelete == False, OrderLogistics.OLsignStatus != LogisticsSignStatus.already_signed.value).update( {'OLsignStatus': LogisticsSignStatus.already_signed.value}, synchronize_session=False) if ol: current_app.logger.info("订单 OMid: {} 存在物流,提前确认收货".format( order_main.OMid)) # 更改主单状态 order_main.update({'OMstatus': OrderMainStatus.ready.value}) db.session.add(order_main) current_app.logger.info("订单自动完成任务结束") return Success('更改成功', dict(OMid=order_main.OMid))
def auto_evaluate(): """超时自动评价订单""" try: cfs = ConfigSettings() limit_time = cfs.get_item('order_auto', 'auto_evaluate_day') # limit_time = 7 time_now = datetime.now() with db.auto_commit(): s_list = list() current_app.logger.info( ">>>>>> 开始检测超过{0}天未评价的商品订单 <<<<<<".format(limit_time)) from planet.control.COrder import COrder corder = COrder() count = 0 wait_comment_order_mains = OrderMain.query.filter( OrderMain.isdelete == False, OrderMain.OMstatus == OrderMainStatus.wait_comment.value, # OrderMain.OMfrom.in_( # [OrderFrom.carts.value, OrderFrom.product_info.value]), OrderMain.updatetime <= time_now - timedelta(days=int(limit_time))) # 所有超过天数 待评价 的商品订单 complete_comment_order_mains = OrderMain.query.join( OrderLogistics, OrderLogistics.OMid == OrderMain.OMid, ).filter( OrderMain.isdelete == False, OrderMain.OMstatus == OrderMainStatus.complete_comment.value, OrderLogistics.isdelete == False, OrderLogistics.OLsignStatus == LogisticsSignStatus.already_signed.value, OrderLogistics.updatetime <= time_now - timedelta(days=int(limit_time))) # 所有已评价的订单 order_mains = wait_comment_order_mains.union( complete_comment_order_mains).all() if not order_mains: current_app.logger.info( ">>>>>> 没有超过{0}天未评价的商品订单 <<<<<<".format(limit_time)) else: for order_main in order_mains: order_parts = OrderPart.query.filter_by_( OMid=order_main.OMid).all() # 主单下所有副单 for order_part in order_parts: if order_part.OPisinORA is True: continue user = User.query.filter_by(USid=order_main.USid, isdelete=False).first() exist_evaluation = OrderEvaluation.query.filter_by_( OPid=order_part.OPid).first() if exist_evaluation: current_app.logger.info( ">>>>> 该副单已存在评价, OPid : {}, OMid : {}, OMstatus : {}" .format(order_part.OPid, order_part.OMid, order_main.OMstatus)) corder._fresh_commsion_into_count( order_part) # 佣金到账 if user: # 防止因用户不存在,进入下个方法报错停止 corder._tosalesvolume(order_main.OMtrueMount, user.USid) # 销售额统计 continue # 已评价的订单只进行销售量统计、佣金到账,跳过下面的评价步骤 ol = OrderLogistics.query.filter_by( OMid=order_part.OMid, isdelete=False).first() if not ol or ol.OLsignStatus != LogisticsSignStatus.already_signed.value: continue corder._fresh_commsion_into_count(order_part) # 佣金到账 if user and order_main.OMfrom != OrderFrom.trial_commodity.value: usname, usheader = user.USname, user.USheader corder._tosalesvolume(order_main.OMtrueMount, user.USid) # 销售额统计 else: usname, usheader = '神秘的客官', '' evaluation_dict = { 'OEid': str(uuid.uuid1()), 'USid': order_main.USid, 'USname': usname, 'USheader': usheader, 'OPid': order_part.OPid, 'OMid': order_main.OMid, 'PRid': order_part.PRid, 'SKUattriteDetail': order_part.SKUattriteDetail, 'OEtext': '此用户没有填写评价。', 'OEscore': 5, } evaluation_instance = OrderEvaluation.create( evaluation_dict) s_list.append(evaluation_instance) count += 1 current_app.logger.info( ">>>>>> 评价第{0}条,OPid :{1} <<<<<<".format( str(count), str(order_part.OPid))) # 商品总体评分变化 try: product_info = Products.query.filter_by_( PRid=order_part.PRid).first_("商品不存在") scores = [ oe.OEscore for oe in OrderEvaluation.query.filter( OrderEvaluation.PRid == product_info.PRid, OrderEvaluation.isdelete == False).all() ] average_score = round( ((float(sum(scores)) + float(5.0)) / (len(scores) + 1)) * 2) Products.query.filter_by( PRid=order_part.PRid).update( {'PRaverageScore': average_score}) except Exception as e: current_app.logger.info( "更改商品评分失败, 商品可能已被删除;Update Product Score ERROR :{}" .format(e)) # 更改主单状态为已完成 change_status = OrderMain.query.filter_by_( OMid=order_main.OMid).update( {'OMstatus': OrderMainStatus.ready.value}) if change_status: current_app.logger.info( ">>>>>> 主单状态更改成功 OMid : {} <<<<<<".format( str(order_main.OMid))) else: current_app.logger.info( ">>>>>> 主单状态更改失败 OMid : {} <<<<<<".format( str(order_main.OMid))) if s_list: db.session.add_all(s_list) current_app.logger.info( ">>>>>> 自动评价任务结束,共更改{}条数据 <<<<<<".format(count)) except Exception as err: current_app.logger.error(">>>>>> 自动评价任务出错 : {} <<<<<<".format(err))
def event_expired_revert(): """过期活动商品返还库存""" current_app.logger.error('>>> 活动商品到期返回库存检测 <<< ') from planet.control.COrder import COrder today = date.today() try: with db.auto_commit(): # 新人首单 fresh_man_products = FreshManFirstProduct.query.join( FreshManFirstApply, FreshManFirstApply.FMFAid == FreshManFirstProduct.FMFAid).filter_( FreshManFirstApply.FMFAstatus == ApplyStatus.agree.value, FreshManFirstApply.AgreeStartime < today, FreshManFirstApply.AgreeEndtime < today, FreshManFirstApply.isdelete == False, FreshManFirstProduct.isdelete == False, Products.PRid == FreshManFirstProduct.PRid, Products.isdelete == False, ).all() # 已经到期的新人首单活动 current_app.logger.info('>>> 到期的新人首单有 {} 个 <<< '.format( len(fresh_man_products))) for fresh_man_pr in fresh_man_products: # 到期后状态改为已下架 current_app.logger.info(' 过期新人首单进行下架 >> FMFAid : {} '.format( fresh_man_pr.FMFAid)) FreshManFirstApply.query.filter( FreshManFirstApply.FMFAid == fresh_man_pr.FMFAid, FreshManFirstApply.AgreeStartime < today, FreshManFirstApply.AgreeEndtime < today, ).update({'FMFAstatus': ApplyStatus.shelves.value}) fresh_man_skus = FreshManFirstSku.query.filter_by_( FMFPid=fresh_man_pr.FMFPid).all() for fresh_man_sku in fresh_man_skus: # 加库存 current_app.logger.info(' 恢复库存的新人首单SKUid >> {} '.format( fresh_man_sku.SKUid)) COrder()._update_stock(fresh_man_sku.FMFPstock, skuid=fresh_man_sku.SKUid) # 猜数字 guess_num_products = GuessNumAwardProduct.query.join( GuessNumAwardApply, GuessNumAwardApply.GNAAid == GuessNumAwardProduct.GNAAid).filter( GuessNumAwardApply.isdelete == False, GuessNumAwardProduct.isdelete == False, GuessNumAwardApply.GNAAstatus == ApplyStatus.agree.value, GuessNumAwardApply.AgreeStartime < today, GuessNumAwardApply.AgreeEndtime < today, Products.PRid == GuessNumAwardProduct.PRid, Products.isdelete == False, ).all() # # 已经到期的猜数字活动 current_app.logger.info('>>> 到期的猜数字有 {} 个 <<< '.format( len(guess_num_products))) for guess_num_pr in guess_num_products: # 到期后状态改为已下架 current_app.logger.info(' 过期猜数字进行下架 >> GNAAid : {} '.format( guess_num_pr.GNAAid)) GuessNumAwardApply.query.filter( GuessNumAwardApply.GNAAid == guess_num_pr.GNAAid, GuessNumAwardApply.AgreeStartime < today, GuessNumAwardApply.AgreeEndtime < today, ).update({'GNAAstatus': ApplyStatus.shelves.value}) gna_skus = GuessNumAwardSku.query.filter_by_( GNAPid=guess_num_pr.GNAPid).all() for gna_sku in gna_skus: # 加库存 current_app.logger.info(' 恢复库存的猜数字SKUid >> {} '.format( gna_sku.SKUid)) COrder()._update_stock(gna_sku.SKUstock, skuid=gna_sku.SKUid) # 魔术礼盒 magic_box_applys = MagicBoxApply.query.filter( MagicBoxApply.isdelete == False, MagicBoxApply.MBAstatus == ApplyStatus.agree.value, MagicBoxApply.AgreeStartime < today, MagicBoxApply.AgreeEndtime < today, ).all() current_app.logger.info('>>> 到期的魔术礼盒有 {} 个 <<< '.format( len(magic_box_applys))) for magic_box_apply in magic_box_applys: other_apply_info = MagicBoxApply.query.filter( MagicBoxApply.isdelete == False, MagicBoxApply.MBAid != magic_box_apply.MBAid, MagicBoxApply.MBAstatus.in_([ ApplyStatus.wait_check.value, ApplyStatus.agree.value ]), MagicBoxApply.OSid == magic_box_apply.OSid, MagicBoxApply.AgreeEndtime >= today, ).first() # 是否存在同用库存还没到期的 if other_apply_info: current_app.logger.info( ' MBAid "{}" 存在同批次库存还在上架或审核状态,跳过'.format( magic_box_apply.MBAid)) continue current_app.logger.info(' 过期魔术礼盒进行下架 >> MBAid : {} '.format( magic_box_apply.MBAid)) magic_box_apply.MBAstatus = ApplyStatus.shelves.value # 改为已下架 try: out_stock = OutStock.query.filter( OutStock.isdelete == False, OutStock.OSid == magic_box_apply.OSid).first() current_app.logger.info(' 恢复库存的魔盒SKUid >> {} '.format( magic_box_apply.SKUid)) COrder()._update_stock(out_stock.OSnum, skuid=magic_box_apply.SKUid) out_stock.OSnum = 0 except Exception as err: current_app.logger.error( 'MBAid "{}" , 魔盒库存单出错 >> {}'.format( magic_box_apply.MBAid, err)) # 试用商品 trialcommoditys = TrialCommodity.query.filter( TrialCommodity.TCstatus == TrialCommodityStatus.upper.value, TrialCommodity.AgreeStartTime < today, TrialCommodity.AgreeEndTime < today, TrialCommodity.isdelete == False).all() current_app.logger.info('>>> 到期的试用商品有 {} 个 <<< '.format( len(trialcommoditys))) for trialcommodity in trialcommoditys: current_app.logger.info(' 过期试用商品进行下架 >> TCid : {} '.format( trialcommodity.TCid)) trialcommodity.update( {'TCstatus': TrialCommodityStatus.reject.value}) # 试用商品不占用普通商品库存 except Exception as e: current_app.logger.error('活动商品到期返回库存出错 >>> {}'.format(e)) current_app.logger.info('--> 活动商品到期返回库存检测任务结束 <-- ')
def __init__(self): self.corder = COrder()
def __init__(self): self.strade = STrade() self.corder = COrder()
class CRefund(object): def __init__(self): self.strade = STrade() self.corder = COrder() @token_required def create(self): data = parameter_required(('orareason', 'oraproductstatus')) opid = data.get('opid') omid = data.get('omid') if opid and omid: raise ParamsError('omid,opid只能存在一个') usid = request.user.id if opid: # 单个商品售后 self._order_part_refund(opid, usid, data) elif omid: # 主单售后 self._order_main_refund(omid, usid, data) else: raise ParamsError('须指定主单或副单') return Success('申请成功, 等待答复') @token_required def cancle(self): """撤销""" data = parameter_required(('oraid', )) oraid = data.get('oraid') with db.auto_commit(): order_refund_apply = OrderRefundApply.query.filter_by({ 'isdelete': False, 'ORAid': oraid, "USid": request.user.id, 'ORAstatus': ApplyStatus.wait_check.value }).first_('售后已处理') order_refund_apply.update({'ORAstatus': ApplyStatus.cancle.value}) db.session.add(order_refund_apply) # 修改主单或副单售后状态 if order_refund_apply.OPid: OrderPart.query.filter_by({ 'OPid': order_refund_apply.OPid }).update({'OPisinORA': False}) if order_refund_apply.OMid: OrderMain.query.filter_by({ 'OMid': order_refund_apply.OMid }).update({"OMinRefund": False}) # 对应退货流水表改为已取消 OrderRefund.query.filter(OrderRefund.ORAid == oraid, OrderRefund.isdelete == False).update({ 'ORstatus': OrderRefundOrstatus.cancle.value }) return Success('撤销成功') @token_required def create_dispute_type(self): """添加内置纠纷类型""" data = parameter_required(('diname', 'ditype', 'disort')) diname = data.get('diname') ditype = data.get('ditype') try: DisputeTypeType(ditype) disort = int(data.get('disort')) except Exception as e: raise ParamsError('ditype错误') with self.strade.auto_commit() as s: diid = str(uuid.uuid1()) dispute_type_dict = { 'DIid': diid, 'DIname': diname, 'DItype': ditype, 'DIsort': disort } dispute_type_instance = DisputeType.create(dispute_type_dict) s.add(dispute_type_instance) return Success('创建成功', data={'diid': diid}) def list_dispute_type(self): """获取纠纷类型""" data = parameter_required() ditype = data.get('type') or None order_refund_types = DisputeType.query.filter_by_({ 'DItype': ditype }).order_by(DisputeType.DIsort).all() return Success(data=order_refund_types) @token_required def agree_apply(self): """同意退款""" data = parameter_required(('oraid', 'agree')) oraid = data.get('oraid') agree = data.get('agree') with self.strade.auto_commit() as s: s_list = [] refund_apply_instance = s.query(OrderRefundApply).filter_by_({ 'ORAid': oraid, 'ORAstatus': ApplyStatus.wait_check.value }).first_('申请已处理或不存在') refund_apply_instance.ORAcheckTime = datetime.now() # 获取订单 if refund_apply_instance.OMid: order_main_instance = s.query(OrderMain).filter_by({ 'OMid': refund_apply_instance.OMid }).first() else: order_part_instance = s.query(OrderPart).filter( OrderPart.OPid == refund_apply_instance.OPid).first() order_main_instance = s.query(OrderMain).filter_by({ 'OMid': order_part_instance.OMid }).first() if agree is True: refund_apply_instance.ORAstatus = ApplyStatus.agree.value if refund_apply_instance.ORAstate == OrderRefundORAstate.only_money.value: # 仅退款 # 退款流水表 order_pay_instance = s.query(OrderPay).filter( OrderPay.isdelete == False, OrderPay.OPayno == order_main_instance.OPayno, OrderPay.OPayType.notin_([ PayType.mixedpay.value, PayType.integralpay.value ])).first() refund_flow_instance = OrderRefundFlow.create({ 'ORFid': str(uuid.uuid1()), 'ORAid': oraid, 'ORAmount': refund_apply_instance.ORAmount, 'OPayno': order_main_instance.OPayno, 'OPayType': order_pay_instance.OPayType, }) s_list.append(refund_flow_instance) mount = refund_apply_instance.ORAmount # todo 退款金额需要改正 old_total_fee = order_pay_instance.OPayMount if API_HOST != 'https://www.bigxingxing.com': mount = 0.01 old_total_fee = 0.01 current_app.logger.info('正在退款中 {} '.format( refund_apply_instance.ORAmount)) self._refund_to_user( # 执行退款, 待测试 out_trade_no=order_main_instance.OPayno, out_request_no=oraid, mount=mount, opaytype=order_pay_instance.OPayType, old_total_fee=old_total_fee) msg = '已同意, 正在退款' # 佣金退 if refund_apply_instance.OPid: self._cancle_commision(order_part=order_part_instance) if refund_apply_instance.OMid: self._cancle_commision(order_main=order_main_instance) # 减少商品相应销量 refund_order_parts = OrderPart.query.filter( OrderPart.OMid == order_main_instance.OMid, OrderPart.isdelete == False).all() current_app.logger.info('退款的副单数有{}个'.format( len(refund_order_parts))) for reop in refund_order_parts: res = Products.query.filter_by(PRid=reop.PRid).update({ 'PRsalesValue': Products.PRsalesValue - reop.OPnum }) if res: current_app.logger.info('退货商品id{} 销量减少{}'.format( reop.PRid, reop.OPnum)) # 月销量更新 ProductMonthSaleValue.query.filter( ProductMonthSaleValue.PRid == reop.PRid, ProductMonthSaleValue.isdelete == False, extract('year', ProductMonthSaleValue.createtime) == reop.createtime.year, extract('month', ProductMonthSaleValue.createtime) == reop.createtime.month, ).update( { 'PMSVnum': ProductMonthSaleValue.PMSVnum - reop.OPnum, }, synchronize_session=False) if refund_apply_instance.ORAstate == OrderRefundORAstate.goods_money.value: # 退货退款 # 取消原来的退货表, (主要是因为因为可能因撤销为未完全删除) old_order_refund = OrderRefund.query.filter( OrderRefund.isdelete == False, OrderRefund.ORAid == oraid).update( {'ORstatus': OrderRefundOrstatus.cancle.value}) # 写入退换货表 orrecvname = data.get('orrecvname') orrecvphone = validate_arg('^1\d{10}$', data.get('orrecvphone', ''), '输入合法的手机号码') orrecvaddress = data.get('orrecvaddress') try: assert orrecvname and orrecvphone and orrecvaddress except Exception as e: raise ParamsError('请填写必要的收货信息') order_refund_dict = { 'ORid': str(uuid.uuid1()), 'OMid': refund_apply_instance.OMid, 'OPid': refund_apply_instance.OPid, 'ORAid': oraid, 'ORrecvname': orrecvname, 'ORrecvphone': orrecvphone, 'ORrecvaddress': orrecvaddress, } order_refund_instance = OrderRefund.create( order_refund_dict) s_list.append(order_refund_instance) msg = '已同意, 等待买家发货' refund_apply_instance.ORAstatus = ApplyStatus.agree.value else: refund_apply_instance.ORAstatus = ApplyStatus.reject.value if refund_apply_instance.OMid: order_main_instance.OMinRefund = False db.session.add(order_main_instance) db.session.add( OrderRefundNotes.create({ 'ORNid': str(uuid.uuid1()), 'OMid': refund_apply_instance.OMid, 'UserName': request.user.username, 'USid': request.user.id, 'ORNaction': -1, # 拒绝 'ORNabo': data.get('oracheckreason') })) else: order_part_instance.OPisinORA = False db.session.add(order_part_instance) db.session.add( OrderRefundNotes.create({ 'ORNid': str(uuid.uuid1()), 'OPid': order_part_instance.OPid, 'UserName': request.user.username, 'USid': request.user.id, 'ORNaction': -1, # 拒绝 'ORNabo': data.get('oracheckreason') })) msg = '拒绝成功' refund_apply_instance.ORAcheckReason = data.get('oracheckreason') refund_apply_instance.ORAcheckTime = datetime.now() refund_apply_instance.ORAcheckUser = request.user.id s_list.append(refund_apply_instance) s.add_all(s_list) return Success(msg) @token_required def back_confirm_refund(self): """执行退款退款中的最后一步, 退款""" form = RefundConfirmForm().valid_data() oraid = form.oraid.data agree = form.agree.data with db.auto_commit(): refund_apply_instance = OrderRefundApply.query.filter( OrderRefundApply.isdelete == False, OrderRefundApply.ORAid == oraid, OrderRefundApply.ORAstatus == ApplyStatus.agree.value, OrderRefundApply.ORAstate == OrderRefundORAstate.goods_money.value).first_('对应的退货申请不存在或未同意') if refund_apply_instance.OMid: order_main_instance = OrderMain.query.filter_by({ 'OMid': refund_apply_instance.OMid }).first() else: order_part_instance = OrderPart.query.filter( OrderPart.OPid == refund_apply_instance.OPid).first() order_main_instance = OrderMain.query.filter_by({ 'OMid': order_part_instance.OMid }).first() order_refund = OrderRefund.query.filter( OrderRefund.isdelete == False, OrderRefund.ORstatus == OrderRefundOrstatus.ready_recv.value, # 确认收货后执行退款 OrderRefund.ORAid == oraid).first_('请确认收货后退款') if agree is True: order_pay_instance = OrderPay.query.filter( OrderPay.isdelete == False, OrderPay.OPayno == order_main_instance.OPayno, OrderPay.OPayType.notin_( [PayType.integralpay.value, PayType.mixedpay.value])).first() order_refund.ORstatus = OrderRefundOrstatus.ready_refund.value db.session.add(order_refund) # TODO 执行退款 mount = refund_apply_instance.ORAmount # todo 退款金额需要改正 old_total_fee = order_pay_instance.OPayMount refund_flow_instance = OrderRefundFlow.create({ 'ORFid': str(uuid.uuid1()), 'ORAid': oraid, 'ORAmount': refund_apply_instance.ORAmount, 'OPayno': order_main_instance.OPayno, 'OPayType': order_pay_instance.OPayType, }) db.session.add(refund_flow_instance) if API_HOST != 'https://www.bigxingxing.com': mount = 0.01 old_total_fee = 0.01 self._refund_to_user( # 执行退款, 待测试 out_trade_no=order_main_instance.OPayno, out_request_no=oraid, mount=mount, opaytype=order_pay_instance.OPayType, old_total_fee=old_total_fee) msg = '已同意, 正在退款' # 减去对应商品的销量 refund_order_parts = OrderPart.query.filter( OrderPart.OMid == order_main_instance.OMid, OrderPart.isdelete == False).all() current_app.logger.info('退货退款的副单数有{}个'.format( len(refund_order_parts))) for reop in refund_order_parts: res = Products.query.filter_by(PRid=reop.PRid).update( {'PRsalesValue': Products.PRsalesValue - reop.OPnum}) if res: current_app.logger.info('退货商品id{} 销量减少{}'.format( reop.PRid, reop.OPnum)) # 月销量更新 ProductMonthSaleValue.query.filter( ProductMonthSaleValue.PRid == reop.PRid, ProductMonthSaleValue.isdelete == False, extract('year', ProductMonthSaleValue.createtime) == reop.createtime.year, extract('month', ProductMonthSaleValue.createtime) == reop.createtime.month, ).update( { 'PMSVnum': ProductMonthSaleValue.PMSVnum - reop.OPnum, }, synchronize_session=False) elif agree is False: order_refund.ORstatus = OrderRefundOrstatus.reject.value db.session.add(order_refund) msg = '已拒绝' else: raise ParamsError('agree 参数错误') return Success(msg) @token_required def back_confirm_recv(self): """后台确认收货""" form = RefundConfirmRecvForm().valid_data() oraid = form.oraid.data with db.auto_commit(): OrderRefundApply.query.filter( OrderRefundApply.isdelete == False, OrderRefundApply.ORAid == oraid, OrderRefundApply.ORAstatus == ApplyStatus.agree.value, OrderRefundApply.ORAstate == OrderRefundORAstate.goods_money.value).first_('对应的退货申请不存在或未同意') order_refund = OrderRefund.query.filter( OrderRefund.isdelete == False, OrderRefund.ORstatus >= OrderRefundOrstatus.wait_recv.value, # 确认收货后执行退款 OrderRefund.ORAid == oraid).first_('未发货') order_refund.ORstatus = OrderRefundOrstatus.ready_recv.value db.session.add(order_refund) msg = '已收货' return Success(msg) @token_required def send(self): """买家发货""" form = RefundSendForm().valid_data() oraid = form.oraid.data orlogisticcompany = form.orlogisticcompany.data orlogisticsn = form.orlogisticsn.data with self.strade.auto_commit() as s: # 判断 s.query(LogisticsCompnay).filter_by_({ 'LCcode': orlogisticcompany }).first_('物流公司不存在') order_refund_instance = s.query(OrderRefund).filter_by_({ 'ORAid': oraid }).first_('申请未同意或不存在') if order_refund_instance.ORstatus > OrderRefundOrstatus.wait_send.value: raise StatusError('重复发货') # 写入退货表 order_refund_instance.update({ 'ORlogisticCompany': orlogisticcompany, 'ORlogisticsn': orlogisticsn, 'ORstatus': OrderRefundOrstatus.wait_recv.value, }) s.add(order_refund_instance) return Success('发货成功') @token_required def refund_query(self): """查询退款结果""" # todo 查询退款结果 @staticmethod def _generic_no(): """生成退款号""" return str(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))) + \ str(time.time()).replace('.', '')[-7:] + str(random.randint(1000, 9999)) def _order_part_refund(self, opid, usid, data): with self.strade.auto_commit() as s: s_list = [] # 副单 order_part = s.query(OrderPart).filter( OrderPart.OPid == opid, OrderPart.isdelete == False).first_('不存在的订单详情') # 删除原来的 OrderRefundNotes.query.filter( OrderRefundNotes.isdelete == False, OrderRefundNotes.OPid == order_part.OPid).delete_() # 所在主单的副单个数 order_part_count = OrderPart.query.filter_by_({ 'OMid': order_part.OMid }).count() current_app.logger.info( '当前副单所在主单有 {} 个商品'.format(order_part_count)) if order_part_count == 1: # 如果只有一个副单, 则改为申请主单售后 current_app.logger.info('改为主单售后') return self._order_main_refund(order_part.OMid, usid, data) # 副单售后 if order_part.OPisinORA is True: cancled_apply = OrderRefundApply.query.filter_by_({ 'ORAstatus': ApplyStatus.cancle.value, 'OPid': opid }).first() if not cancled_apply: raise DumpliError('重复申请') # 删除之前已经撤销的售后 cancled_apply.isdelete = True s_list.append(cancled_apply) # 主单售后状态 omid = order_part.OMid order_main = s.query(OrderMain).filter_( OrderMain.OMid == omid, OrderMain.OMstatus.notin_([ OrderMainStatus.wait_pay.value, OrderMainStatus.cancle.value, OrderMainStatus.ready.value, ]), OrderMain.USid == usid).first_('不存在的订单') if order_main.OMinRefund == True: raise DumpliError('主订单已在售后中, 请勿重复申请') if order_main.OMfrom == OrderFrom.integral_store.value: raise StatusError('星币商城订单暂不支持退换货,如有问题请及时联系客服') elif order_main.OMfrom == OrderFrom.integral_store.value: raise StatusError('试用商品订单暂不支持退换货,如有问题请及时联系客服') apply = OrderRefundApply.query.filter( OrderRefundApply.OPid == opid, OrderRefundApply.isdelete == False, OrderRefundApply.ORAstatus != ApplyStatus.reject.value).first() if apply and apply.ORAstatus != ApplyStatus.cancle.value: raise DumpliError('订单已在售后中, 请勿重复申请') elif apply: current_app.logger.info('删除原来副单售后申请') apply.isdelete = True s_list.append(apply) # 不改变主单的状态 # order_main.OMinRefund = True # 主单状态 # s_list.append(order_main) order_part.OPisinORA = True # 附单状态 s_list.append(order_part) # 申请参数校验 oraproductstatus = data.get('oraproductstatus') ORAproductStatus(oraproductstatus) oramount = data.get('oramount') if oramount: oramount = Decimal(str((oramount))) if not oramount or oramount > order_part.OPsubTrueTotal: # todo 组合支付时OPsubTrueTotal,扣除星币抵扣的钱 raise ParamsError('退款金额不正确') oraddtionvoucher = data.get('oraddtionvoucher') if oraddtionvoucher and isinstance(oraddtionvoucher, list): oraddtionvoucher = oraddtionvoucher else: oraddtionvoucher = None oraaddtion = data.get('oraaddtion') orastate = data.get('orastate', OrderRefundORAstate.goods_money.value) try: OrderRefundORAstate(orastate) except Exception as e: raise ParamsError('orastate参数错误') # 添加申请表 order_refund_apply_dict = { 'ORAid': str(uuid.uuid1()), # 'OMid': omid, 'ORAsn': self._generic_no(), 'OPid': opid, 'USid': usid, 'ORAmount': oramount, 'ORaddtionVoucher': oraddtionvoucher, 'ORAaddtion': oraaddtion, 'ORAreason': data.get('orareason'), 'ORAproductStatus': oraproductstatus, 'ORAstate': orastate, } order_refund_apply_instance = OrderRefundApply.create( order_refund_apply_dict) s_list.append(order_refund_apply_instance) s.add_all(s_list) current_app.logger.info( 'the order_part refund apply id(oraid) is {}'.format( order_refund_apply_dict['ORAid'])) def _order_main_refund(self, omid, usid, data): with self.strade.auto_commit() as s: s_list = [] OrderRefundNotes.query.filter( OrderRefundNotes.isdelete == False, OrderRefundNotes.OMid == omid).delete_() order_main = s.query(OrderMain).filter_( OrderMain.OMid == omid, OrderMain.OMstatus.notin_([ OrderMainStatus.wait_pay.value, OrderMainStatus.cancle.value, OrderMainStatus.ready.value, ]), OrderMain.USid == usid).first_('不存在的订单') if order_main.OMinRefund is True: raise DumpliError('已经在售后中') if order_main.OMfrom == OrderFrom.integral_store.value: raise StatusError('星币商城订单暂不支持退换货,如有问题请及时联系客服') elif order_main.OMfrom == OrderFrom.trial_commodity.value: raise StatusError('试用商品订单暂不支持退换货,如有问题请及时联系客服') elif order_main.OMfrom == OrderFrom.guess_group.value: # 拼团竞猜申请退款时 guess_record = GuessRecord.query.filter( GuessRecord.isdelete == False, GuessRecord.OMid == order_main.OMid, GuessRecord.GRstatus == GuessRecordStatus.valid.value).first() if guess_record: current_app.logger.info('拼团订单申请售后,GRid {}'.format( guess_record.GRid)) guess_record.GRstatus = GuessRecordStatus.invalid.value # 拼团记录改为失效 guess_group = GuessGroup.query.filter( GuessGroup.isdelete == False, GuessGroup.GGid == guess_record.GGid).first() if guess_group and guess_group.GGstatus in ( GuessGroupStatus.pending.value, GuessGroupStatus.waiting.value): if guess_group.USid == order_main.USid: current_app.logger.info( '拼团GGid {} ;发起人申请售后'.format(guess_group.GGid)) guess_group.GGstatus = GuessGroupStatus.failed.value # 如果是拼团发起人,该团直接拼团失败 # 退还其余两人押金 grs = GuessRecord.query.filter( GuessRecord.isdelete == False, GuessRecord.USid != order_main.USid, GuessRecord.GGid == guess_group.GGid, GuessRecord.GRstatus == GuessRecordStatus.valid.value).all() for gr in grs: # gr.GRstatus = GuessRecordStatus.invalid.value current_app.logger.info('退还参与者 {} 的押金'.format( gr.USid)) order_part = OrderPart.query.filter_by_( OMid=gr.OMid).first() # 参与者的副单 tem_order_main = OrderMain.query.filter_by_( OMid=gr.OMid).first() # 参与者主单 self.corder._cancle( tem_order_main) # 参与者主单改为取消 # 参与者退还押金 price = order_part.OPsubTrueTotal user_commision_dict = { 'UCid': str(uuid.uuid1()), 'UCcommission': Decimal(price).quantize(Decimal('0.00')), 'USid': tem_order_main.USid, 'UCstatus': UserCommissionStatus.in_account.value, 'UCtype': UserCommissionType.group_refund.value, 'PRtitle': f'[拼团押金]{order_part.PRtitle}', 'SKUpic': order_part.PRmainpic, 'OMid': order_part.OMid, 'OPid': order_part.OPid } db.session.add( UserCommission.create(user_commision_dict)) user_wallet = UserWallet.query.filter_by_( USid=tem_order_main.USid).first() if user_wallet: user_wallet.UWbalance = Decimal( str(user_wallet.UWbalance or 0)) + Decimal(str(price)) user_wallet.UWtotal = Decimal( str(user_wallet.UWtotal or 0)) + Decimal(str(price)) user_wallet.UWcash = Decimal( str(user_wallet.UWcash or 0)) + Decimal(str(price)) db.session.add(user_wallet) else: user_wallet_instance = UserWallet.create({ 'UWid': str(uuid.uuid1()), 'USid': tem_order_main.USid, 'UWbalance': Decimal(price).quantize( Decimal('0.00')), 'UWtotal': Decimal(price).quantize( Decimal('0.00')), 'UWcash': Decimal(price).quantize( Decimal('0.00')), # 'UWexpect': user_commision.UCcommission, 'CommisionFor': ApplyFrom.user.value }) db.session.add(user_wallet_instance) else: if guess_group.GGstatus == GuessGroupStatus.waiting.value: current_app.logger.info('拼团等待开奖中,改为正在拼') guess_group.GGstatus = GuessGroupStatus.pending.value # 之前的申请 apply = OrderRefundApply.query.filter( OrderRefundApply.isdelete == False, OrderRefundApply.OMid == order_main.OMid, OrderRefundApply.ORAstatus.notin_([ ApplyStatus.reject.value, ApplyStatus.cancle.value, ]), ).first() if apply: raise DumpliError('订单已在售后中, 请勿重复申请') if apply: apply.isdelete = True s_list.append(apply) # 申请主单售后, 所有的副单不可以有在未撤销的售后状态或未被拒绝 order_parts_in_refund = OrderPart.query.filter_by_({ 'OMid': omid, 'OPisinORA': True }).all() for order_part in order_parts_in_refund: part_apply = OrderRefundApply.query.filter_by_({ 'OPid': order_part.OPid }).first() # if not cancled_apply: # raise DumpliError('订单中有商品已在售后中, 请勿重复申请') if part_apply and part_apply.ORAstatus != ApplyStatus.cancle.value: raise DumpliError('订单中有商品已在售后中, 请勿重复申请') elif part_apply: part_apply.isdelete = True s_list.append(part_apply) order_main.OMinRefund = True # 主单状态 s_list.append(order_main) # 申请参数校验 oraproductstatus = int(data.get('oraproductstatus')) # 是否已经收到货 ORAproductStatus(oraproductstatus) orastate = int( data.get('orastate', OrderRefundORAstate.goods_money.value)) try: OrderRefundORAstate(orastate) except Exception as e: raise ParamsError('orastate参数错误') oramount = data.get('oramount') if oramount: oramount = Decimal(str(oramount)) if not oramount or oramount > order_main.OMtrueMount: raise ParamsError('oramount退款金额不正确') # 不改变副单的状态 # order_parts = s.query(OrderPart).filter_by_({'OMid': omid}).all() # for order_part in order_parts: # order_part.OPisinORA = True # 附单状态 # s_list.append(order_part) # 添加申请表 oraddtionvoucher = data.get('oraddtionvoucher') oraaddtion = data.get('oraaddtion') order_refund_apply_dict = { 'ORAid': str(uuid.uuid1()), 'OMid': omid, 'ORAsn': self._generic_no(), 'USid': usid, 'ORAmount': oramount, 'ORaddtionVoucher': oraddtionvoucher, 'ORAaddtion': oraaddtion, 'ORAreason': data.get('orareason'), 'ORAproductStatus': oraproductstatus, 'ORAstate': orastate, } order_refund_apply_instance = OrderRefundApply.create( order_refund_apply_dict) s_list.append(order_refund_apply_instance) s.add_all(s_list) current_app.logger.info( 'the order_main refund apply id(oraid) is {}'.format( order_refund_apply_dict['ORAid'])) def _refund_to_user(self, out_trade_no, out_request_no, mount, opaytype, old_total_fee=None): """ 执行退款 mount 单位元 old_total_fee 单位元 out_request_no :return: """ if opaytype == PayType.wechat_pay.value: # 微信 mount = int(mount * 100) old_total_fee = int(Decimal(str(old_total_fee)) * 100) current_app.logger.info( 'the total fee to refund cent is {}'.format(mount)) result = wx_pay.refund( out_trade_no=out_trade_no, out_refund_no=out_request_no, total_fee=old_total_fee, # 原支付的金额 refund_fee=mount # 退款的金额 ) else: # 支付宝 result = alipay.api_alipay_trade_refund( out_trade_no=out_trade_no, out_request_no=out_request_no, refund_amount=mount) if result["code"] != "10000": raise ApiError('退款错误') return result def _cancle_commision(self, *args, **kwargs): order_main = kwargs.get('order_main') order_part = kwargs.get('order_part') if order_main: if order_main.OMfrom == OrderFrom.fresh_man.value: user_commision = UserCommission.query.filter( UserCommission.OMid == order_main.OMid, UserCommission.isdelete == False).first() if user_commision: current_app.logger.info( '检测到有新人首单退货。订单id是 {}, 用户id是 {}'.format( order_main.OMid, user_commision.USid)) fresh_man_join_count = FreshManJoinFlow.query.filter( FreshManJoinFlow.isdelete == False, FreshManJoinFlow.UPid == user_commision.USid, FreshManJoinFlow.OMid == OrderMain.OMid, OrderMain.OMstatus >= OrderMainStatus.wait_send.value, OrderMain.OMinRefund == False, OrderMain.isdelete == False).count() current_app.logger.info( '当前用户已分享的有效新人首单商品订单有 {}'.format(fresh_man_join_count)) # 获取其前三个有效的新人首单 fresh_man_join_all = FreshManJoinFlow.query.filter( FreshManJoinFlow.isdelete == False, FreshManJoinFlow.UPid == user_commision.USid, FreshManJoinFlow.OMid == OrderMain.OMid, OrderMain.OMstatus >= OrderMainStatus.wait_send.value, OrderMain.OMinRefund == False, OrderMain.isdelete == False).order_by( FreshManJoinFlow.createtime.asc()).limit(3) # 邀请人新品佣金修改 user_order_main = OrderMain.query.filter( OrderMain.isdelete == False, OrderMain.USid == user_commision.USid, OrderMain.OMfrom == OrderFrom.fresh_man.value, OrderMain.OMstatus > OrderMainStatus.wait_pay.value, ).first() user_fresh_order_price = user_order_main.OMtrueMount first = 20 second = 30 third = 50 commissions = 0 if fresh_man_join_all: for fresh_man_count, fresh_man in enumerate( fresh_man_join_all, start=1): if commissions < user_fresh_order_price: reward = fresh_man.OMprice if fresh_man_count == 1: reward = reward * (first / 100) elif fresh_man_count == 2: reward = reward * (second / 100) elif fresh_man_count == 3: reward = reward * (third / 100) else: break if reward + commissions > user_fresh_order_price: reward = user_fresh_order_price - commissions if reward: if fresh_man_count <= 2: UserCommission.query.filter( UserCommission.isdelete == False, UserCommission.USid == fresh_man.UPid, UserCommission.OMid == fresh_man.OMid, UserCommission.UCstatus == UserCommissionStatus.preview.value ).update({'UCcommission': reward}) else: user_main_order = OrderMain.query.filter( OrderMain.isdelete == False, OrderMain.OMid == fresh_man.OMid, ).first() user_order_status = user_main_order.OMstatus if user_order_status == OrderMainStatus.ready.value: status = UserCommissionStatus.in_account.value else: status = UserCommissionStatus.preview.value user_commision_dict = { 'UCid': str(uuid.uuid1()), 'OMid': user_main_order.OMid, 'UCcommission': reward, 'USid': user_main_order.USid, 'UCtype': UserCommissionType.fresh_man.value, 'UCstatus': status } db.session.add( UserCommission.create( user_commision_dict)) UserCommission.query.filter( UserCommission.isdelete == False, UserCommission.USid == order_main.USid, UserCommission.UCtype == UserCommissionType.fresh_man.value, UserCommission.UCstatus == UserCommissionStatus.preview).update({ 'UCcommission': 0, 'isdelete': True }) return order_parts = OrderPart.query.filter( OrderPart.isdelete == False, OrderPart.OMid == order_main.OMid).all() for order_part in order_parts: self._cancle_commision(order_part=order_part) # 如果是分享者 elif order_part: user_commision = UserCommission.query.filter( UserCommission.isdelete == False, UserCommission.OPid == order_part.OPid, UserCommission.UCstatus == UserCommissionStatus.preview.value).update( {'UCstatus': UserCommissionStatus.error.value}) current_app.logger.info( '失效了{}个佣金到账(包括供应商到账, 平台到账)'.format(user_commision)) # todo 售后物流