private void calculateShipping(FulfillmentGroup fulfillmentGroup) {
    if (!isValidModuleForService(fulfillmentGroup.getService()) && !isDefaultModule()) {
      LOG.info(
          "fulfillment group ("
              + fulfillmentGroup.getId()
              + ") with a service type of ("
              + fulfillmentGroup.getService()
              + ") is not valid for this module service type ("
              + getServiceName()
              + ")");
      return;
    }
    if (fulfillmentGroup.getFulfillmentGroupItems().size() == 0) {
      LOG.warn(
          "fulfillment group ("
              + fulfillmentGroup.getId()
              + ") does not contain any fulfillment group items. Unable to price banded shipping");
      fulfillmentGroup.setShippingPrice(
          BroadleafCurrencyUtils.getMoney(
              BigDecimal.ZERO, fulfillmentGroup.getOrder().getCurrency()));
      fulfillmentGroup.setSaleShippingPrice(
          BroadleafCurrencyUtils.getMoney(
              BigDecimal.ZERO, fulfillmentGroup.getOrder().getCurrency()));
      fulfillmentGroup.setRetailShippingPrice(
          BroadleafCurrencyUtils.getMoney(
              BigDecimal.ZERO, fulfillmentGroup.getOrder().getCurrency()));
      return;
    }
    Address address = fulfillmentGroup.getAddress();
    String state =
        (address != null && address.getState() != null)
            ? address.getState().getAbbreviation()
            : null;
    BigDecimal retailTotal = new BigDecimal(0);
    String feeType = feeTypeMapping.get(fulfillmentGroup.getMethod());
    String feeSubType =
        ((feeSubTypeMapping.get(state) == null)
            ? feeSubTypeMapping.get("ALL")
            : feeSubTypeMapping.get(state));

    for (FulfillmentGroupItem fulfillmentGroupItem : fulfillmentGroup.getFulfillmentGroupItems()) {
      BigDecimal price =
          (fulfillmentGroupItem.getRetailPrice() != null)
              ? fulfillmentGroupItem
                  .getRetailPrice()
                  .getAmount()
                  .multiply(BigDecimal.valueOf(fulfillmentGroupItem.getQuantity()))
              : null;
      if (price == null) {
        price =
            fulfillmentGroupItem
                .getOrderItem()
                .getRetailPrice()
                .getAmount()
                .multiply(BigDecimal.valueOf(fulfillmentGroupItem.getQuantity()));
      }
      retailTotal = retailTotal.add(price);
    }

    ShippingRate sr =
        shippingRateService.readShippingRateByFeeTypesUnityQty(feeType, feeSubType, retailTotal);
    if (sr == null) {
      throw new NotImplementedException(
          "Shipping rate " + fulfillmentGroup.getMethod() + " not supported");
    }
    BigDecimal shippingPrice = new BigDecimal(0);
    if (sr.getBandResultPercent().compareTo(0) > 0) {
      BigDecimal percent = new BigDecimal(sr.getBandResultPercent() / 100);
      shippingPrice = retailTotal.multiply(percent);
    } else {
      shippingPrice = sr.getBandResultQuantity();
    }
    fulfillmentGroup.setShippingPrice(
        BroadleafCurrencyUtils.getMoney(shippingPrice, fulfillmentGroup.getOrder().getCurrency()));
    fulfillmentGroup.setSaleShippingPrice(fulfillmentGroup.getShippingPrice());
    fulfillmentGroup.setRetailShippingPrice(fulfillmentGroup.getSaleShippingPrice());
  }
  @Test(groups = {"testSuccessfulCyberSourceCCModulePayment"})
  @Rollback(false)
  public void testSuccessfulCyberSourceCCModulePayment() throws Exception {
    if (serviceManager.getMerchantId().equals("?")) {
      return;
    }

    /*
     * authorize
     */
    CyberSourceCreditCardModule module = new CyberSourceCreditCardModule();
    module.setServiceManager(serviceManager);

    Money amount = new Money(81.46);
    PaymentInfo paymentInfo = new PaymentInfoImpl();
    paymentInfo.setAmount(amount);
    Address address = new AddressImpl();
    address.setAddressLine1("1295 Charleston Road");
    address.setCity("Mountain View");
    address.setCountry(
        new CountryImpl() {
          @Override
          public String getAbbreviation() {
            return "US";
          }
        });
    address.setFirstName("John");
    address.setLastName("Doe");
    address.setPostalCode("94043");
    address.setState(
        new StateImpl() {
          @Override
          public String getAbbreviation() {
            return "CA";
          }
        });
    paymentInfo.setAddress(address);
    paymentInfo.setCustomerIpAddress("10.7.111.111");
    Order order = new OrderImpl();
    order.setEmailAddress("*****@*****.**");
    paymentInfo.setOrder(order);
    Referenced referenced = createCreditCardPaymentInfo("4111111111111111", 12, 2020, null);
    PaymentContext context =
        new PaymentContextImpl(amount, amount, paymentInfo, referenced, "test");

    PaymentResponseItem responseItem = module.authorize(context);
    assert (responseItem.getAmountPaid().equals(amount));

    /*
     * debit
     */
    paymentInfo
        .getAdditionalFields()
        .put("requestId", responseItem.getAdditionalFields().get("requestId"));
    paymentInfo
        .getAdditionalFields()
        .put("requestToken", responseItem.getAdditionalFields().get("requestToken"));

    PaymentResponseItem responseItem2 = module.debit(context);
    assert (responseItem2.getAmountPaid().equals(amount));

    /*
     * authorize and debit
     */
    PaymentResponseItem responseItem3 = module.authorizeAndDebit(context);
    assert (responseItem3.getAmountPaid().equals(amount));

    /*
     * credit
     */
    paymentInfo
        .getAdditionalFields()
        .put("requestId", responseItem3.getAdditionalFields().get("requestId"));
    paymentInfo
        .getAdditionalFields()
        .put("requestToken", responseItem3.getAdditionalFields().get("requestToken"));

    PaymentResponseItem responseItem4 = module.credit(context);
    assert (responseItem4.getAmountPaid().equals(amount));

    /*
     * void
     */
    // TODO void does not seem to work in the CyberSource test environment
    /*PaymentResponseItem responseItem5 = module.authorizeAndDebit(context);
    paymentInfo.getAdditionalFields().put("requestId", responseItem5.getAdditionalFields().get("requestId"));
    paymentInfo.getAdditionalFields().put("requestToken", responseItem5.getAdditionalFields().get("requestToken"));

    PaymentResponseItem responseItem6 = module.voidPayment(context);
    assert(responseItem6.getTransactionSuccess());
    assert(responseItem6.getAmountPaid().equals(amount));*/

    /*
     * auth reverse
     */
    PaymentResponseItem responseItem5 = module.authorize(context);

    paymentInfo
        .getAdditionalFields()
        .put("requestId", responseItem5.getAdditionalFields().get("requestId"));
    paymentInfo
        .getAdditionalFields()
        .put("requestToken", responseItem5.getAdditionalFields().get("requestToken"));

    PaymentResponseItem responseItem6 = module.reverseAuthorize(context);
    assert (responseItem6.getAmountPaid().equals(amount));
  }