/** Found the valid prize group definition recursively. */ private PrizeGroup determinePrizeGroup(Merchant merchant) throws ApplicationException { if (Merchant.SUPER_MERCHANT_ID == merchant.getId()) { return null; } PrizeGroup prizeGroup = merchant.getPrizeGroup(); if (prizeGroup == null) { throw new ApplicationException( SystemException.CODE_MERCHANT_UNALLOWED_PAY, "No any prize group definition found of Merchant(" + merchant + "), System will simply reject this payout request."); } if (PrizeGroup.ALLOWTYPE_USEPARENT == prizeGroup.getAllowType()) { prizeGroup = this.determinePrizeGroup(merchant.getParentMerchant()); } else { if (logger.isDebugEnabled()) { logger.debug( "Use the payout-limit setting(max=" + prizeGroup.getMaxPayoutAmount() + ",min=" + prizeGroup.getMinPayoutAmount() + ") of merhcant(" + merchant + ") to verify payout limit."); } if (!prizeGroup.isPayoutAllowed()) { throw new ApplicationException( SystemException.CODE_MERCHANT_UNALLOWED_PAY, "Merchant(" + merchant + ") doesn't allow payout."); } } return prizeGroup; }
/** * If the payout-limit of current merchant is 'follow parent', TE should query its parent merchant * till find a parent merchant whose payout-limit isn't 'follow parent'. * * @return the PrizeGroup which will be applied at final. */ private PrizeGroup determinePrizeGroup(Context respCtx, Operator operator) throws ApplicationException { PrizeGroup prizeGroup = operator.getPrizeGroup(); if (prizeGroup == null) { throw new ApplicationException( SystemException.CODE_MERCHANT_UNALLOWED_PAY, "No any prize group definition found of Operator(" + operator + "), System will simply reject this payout request."); } if (PrizeGroup.ALLOWTYPE_USEPARENT == prizeGroup.getAllowType()) { // lookup prize group definition of operator's parent merchant Merchant leafMerchant = this.getMerchantDao().findById(Merchant.class, respCtx.getTransaction().getMerchantId()); if (leafMerchant == null) { throw new ApplicationException( SystemException.CODE_NO_MERCHANT, "can NOT find merhcant by id=" + respCtx.getTransaction().getMerchantId()); } prizeGroup = this.determinePrizeGroup(leafMerchant); } else { if (logger.isDebugEnabled()) { logger.debug( "Use the payout-limit setting(max=" + prizeGroup.getMaxPayoutAmount() + ",min=" + prizeGroup.getMinPayoutAmount() + ") of Operator(" + operator + ") to verify payout limit."); } } return prizeGroup; }
@Override public void allowPayout( Context respCtx, Game game, PayoutLevelAllowRequest[] levelAllowRequests, BigDecimal actualPayout) throws ApplicationException { // verify whether the game has been allocated MerchantCommission comm = this.getMerchantCommissionDao() .getByMerchantAndGame(respCtx.getTransaction().getMerchantId(), game.getId()); if (comm == null || !comm.isAllowPayout()) { throw new SystemException( SystemException.CODE_OPERATOR_PAYOUT_NOPRIVILEDGE, "operator(id=" + respCtx.getOperatorId() + ") has no priviledge to payout ticket of game '" + game.getId() + "', allocate the game to its merchant(id=" + respCtx.getTransaction().getMerchantId() + ") first."); } GameType gameType = GameType.fromType(game.getType()); // only need to check the prize group constraints of operator PrizeGroup prizeGroup = respCtx.getOperator().getPrizeGroup(); if (!prizeGroup.isPayoutAllowed()) { throw new ApplicationException( SystemException.CODE_MERCHANT_UNALLOWED_PAY, "Operator(" + respCtx.getOperator() + ") doesn't allow payout."); } // ** both conditions must be satisfied // by payout limit if (new BigDecimal("0").compareTo(actualPayout) != 0) { this.verifyPayoutByLimit(respCtx, actualPayout, respCtx.getOperator()); } // for odds and fix-prize game, no need to check prize level. if (!gameType.isFixedPrize()) { // by prize level if (levelAllowRequests != null) { for (PayoutLevelAllowRequest levelAllowRequest : levelAllowRequests) { this.verifyPayoutByLevel( respCtx, respCtx.getOperator(), levelAllowRequest.getRequestedPrizeLevels(), levelAllowRequest.getGameType(), levelAllowRequest.getPrizeGroupType()); } } } }
/** * When cash out, a merchant can only cashout a given max amount. * * @param respCtx The context of cashout transaction. * @param actualCashout The actual amount of cashout. * @throws ApplicationException when encounter any business exception. */ protected void allowDailyCashout(Context respCtx, BigDecimal actualCashout) throws ApplicationException { PrizeGroup cashoutGroup = respCtx.getOperator().getCashoutGroup(); if (cashoutGroup == null) { throw new ApplicationException( SystemException.CODE_MERCHANT_UNALLOWED_CASHOUT, "Operator(" + respCtx.getOperator() + ") can't perform cashout, no any cashout " + "group definition found."); } if (logger.isDebugEnabled()) { logger.debug( "Before cash out[dailyCashoutLevel: " + respCtx.getOperator().getDailyCashoutLevel() + ", dailyCashoutLimit: " + cashoutGroup.getDailyCashoutLimit() + ", cashoutAmount: " + actualCashout + "] of Operator( " + respCtx.getOperator() + ")."); } if (actualCashout .add(respCtx.getOperator().getDailyCashoutLevel()) .compareTo(cashoutGroup.getDailyCashoutLimit()) > 0) { throw new ApplicationException( SystemException.CODE_EXCEED_ALLOWED_MERCHANT_DAILY_CASHOUT_LIMIT, "Cash out amount(" + actualCashout + ") + current cashout level(" + respCtx.getOperator().getDailyCashoutLevel() + ") has exceeded allowed limit(" + cashoutGroup.getDailyCashoutLimit() + ") of Operator(" + respCtx.getOperator() + ")."); } }
/** * When cash out, system check the cashout-limit of the merchant. * * @param respCtx The context of cashout transaction. * @param actualCashout The actual amount of cashout. * @throws ApplicationException when encounter any business exception. */ protected void allowCashoutByLimit(Context respCtx, BigDecimal actualCashout) throws ApplicationException { PrizeGroup cashoutGroup = respCtx.getOperator().getCashoutGroup(); if (cashoutGroup == null) { throw new ApplicationException( SystemException.CODE_MERCHANT_UNALLOWED_CASHOUT, "Operator(" + respCtx.getOperator() + ") can't perform cashout, no any cashout group definition found."); } if (cashoutGroup.getMaxPayoutAmount() != null && cashoutGroup.getMaxPayoutAmount().compareTo(new BigDecimal("0")) >= 0) { if (actualCashout.compareTo(cashoutGroup.getMaxPayoutAmount()) > 0) { throw new ApplicationException( SystemException.CODE_MERCHANT_UNALLOWED_CASHOUT_SCOPE, "The prize actual amount(" + actualCashout + ") exceed the max " + "allowed cashout amount(" + cashoutGroup.getMaxPayoutAmount() + ") of the Operator(" + respCtx.getOperator() + ")."); } } if (cashoutGroup.getMinPayoutAmount() != null && cashoutGroup.getMinPayoutAmount().compareTo(new BigDecimal("0")) >= 0) { if (actualCashout.compareTo(cashoutGroup.getMinPayoutAmount()) < 0) { throw new ApplicationException( SystemException.CODE_MERCHANT_UNALLOWED_CASHOUT_SCOPE, "The prize actual amount(" + actualCashout + ") is less than min cashout amount(" + cashoutGroup.getMinPayoutAmount() + ") of Operator(" + respCtx.getOperator() + ")."); } } }
/** * When do payout/validation, system check the payout-limit of the merchant. A merchant maybe * follow its parent's payout-limit setting, system should handle this case. * * @param respCtx The context of current transaction. * @param actualPayout The actual amount of payout. * @param operator The operator who do payout. * @throws ApplicationException when encounter any business exception. */ private void verifyPayoutByLimit(Context respCtx, BigDecimal actualPayout, Operator operator) throws ApplicationException { PrizeGroup prizeGroup = this.determinePrizeGroup(respCtx, operator); if (PrizeGroup.ALLOWTYPE_UNLIMIT == prizeGroup.getAllowType()) { if (logger.isDebugEnabled()) { logger.debug("the prize group definition(" + prizeGroup.getId() + ") is no limited"); } return; } if (prizeGroup.getMaxPayoutAmount() != null && prizeGroup.getMaxPayoutAmount().compareTo(new BigDecimal("0")) >= 0) { if (actualPayout.compareTo(prizeGroup.getMaxPayoutAmount()) > 0) { throw new ApplicationException( SystemException.CODE_EXCEED_MAX_PAYOUT, "The prize actual amount(" + actualPayout + ") exceed the max " + "allowed payout amount(" + prizeGroup.getMaxPayoutAmount() + ")."); } } if (prizeGroup.getMinPayoutAmount() != null && prizeGroup.getMinPayoutAmount().compareTo(new BigDecimal("0")) >= 0) { if (actualPayout.compareTo(prizeGroup.getMinPayoutAmount()) < 0) { throw new ApplicationException( SystemException.CODE_EXCEED_MAX_PAYOUT, "The prize actual amount(" + actualPayout + ") is less than min " + "payout amount(" + prizeGroup.getMinPayoutAmount() + ")."); } } }