/** {@inheritDoc} */
  @Override
  public void run() {

    final Logger log = ShopCodeContext.getLog(this);

    final long start = System.currentTimeMillis();

    final Date lastModification = new Date(System.currentTimeMillis() - determineExpiryInMs());

    log.info("Look up all ShoppingCartStates not modified since {}", lastModification);

    final ResultsIterator<ShoppingCartState> abandoned =
        this.shoppingCartStateService.findByModificationPrior(lastModification);

    try {
      int count = 0;
      int removedOrders = 0;
      while (abandoned.hasNext()) {

        final ShoppingCartState scs = abandoned.next();

        final String guid = scs.getGuid();

        log.debug("Removing abandoned cart for {}, guid {}", scs.getCustomerEmail(), guid);
        this.shoppingCartStateService.delete(scs);
        log.debug("Removed abandoned cart for {}, guid {}", scs.getCustomerEmail(), guid);

        final CustomerOrder tempOrder = this.customerOrderService.findByGuid(guid);
        if (CustomerOrder.ORDER_STATUS_NONE.equals(tempOrder.getOrderStatus())) {
          log.debug("Removing temporary order for cart guid {}", guid);
          this.customerOrderService.delete(tempOrder);
          removedOrders++;
          log.debug("Removed temporary order for cart guid {}", guid);
        }

        if (++count % this.batchSize == 0) {
          // flush a batch of updates and release memory:
          shoppingCartStateService.getGenericDao().flush();
          shoppingCartStateService.getGenericDao().clear();
        }
      }

      log.info("Removed {} carts and {} temporary orders", count, removedOrders);

    } finally {
      try {
        abandoned.close();
      } catch (Exception exp) {
        log.error(
            "Processing abandoned baskets exception, error closing iterator: " + exp.getMessage(),
            exp);
      }
    }

    final long finish = System.currentTimeMillis();

    final long ms = (finish - start);

    log.info("Processing abandoned baskets ... completed in {}s", (ms > 0 ? ms / 1000 : 0));
  }
  @Test
  public void testHandlePaymentCallbackOutOfStock() throws Exception {
    Customer customer = createCustomer();
    ShoppingCart shoppingCart = getShoppingCart2(customer.getEmail());

    final ShoppingCartCommandFactory commands =
        ctx().getBean("shoppingCartCommandFactory", ShoppingCartCommandFactory.class);
    Map<String, String> param = new HashMap<String, String>();
    param = new HashMap<String, String>();
    param.put(ShoppingCartCommand.CMD_SETQTYSKU, "CC_TEST1");
    param.put(ShoppingCartCommand.CMD_SETQTYSKU_P_QTY, "20000.00");
    commands.execute(shoppingCart, (Map) param);

    CustomerOrder customerOrder = orderAssembler.assembleCustomerOrder(shoppingCart);
    customerOrder = deliveryAssembler.assembleCustomerOrder(customerOrder, shoppingCart, true);
    customerOrder.setPgLabel("testExtFormPaymentGatewayLabel");
    customerOrder = customerOrderService.create(customerOrder);
    assertEquals(
        "Order must be in ORDER_STATUS_NONE state",
        CustomerOrder.ORDER_STATUS_NONE,
        customerOrder.getOrderStatus());
    final String ordGuid = customerOrder.getCartGuid();
    ShopCodeContext.setShopCode(customerOrder.getShop().getCode());
    paymentCallBackHandlerFacade.handlePaymentCallback(
        new HashMap<String, String>() {
          {
            put(TestExtFormPaymentGatewayImpl.ORDER_GUID_PARAM_KEY, ordGuid);
            put(TestExtFormPaymentGatewayImpl.RESPONSE_CODE_PARAM_KEY, "1"); // 1 - means ok
          }
        },
        "testExtFormPaymentGatewayLabel");
    ShopCodeContext.clear();
    customerOrder = customerOrderService.findByGuid(customerOrder.getCartGuid());
    assertEquals(
        "Order must be in ORDER_STATUS_CANCELLED state", // because item is out of stock
        CustomerOrder.ORDER_STATUS_CANCELLED,
        customerOrder.getOrderStatus());

    final List<CustomerOrderPayment> payments =
        customerOrderPaymentService.findBy(customerOrder.getOrdernum(), null, null, null);
    assertNotNull(payments);
    assertEquals(payments.size(), 2);
    assertEquals(PaymentGateway.AUTH_CAPTURE, payments.get(0).getTransactionOperation());
    assertEquals("1", payments.get(0).getTransactionOperationResultCode());
    assertEquals(PaymentGateway.REFUND, payments.get(1).getTransactionOperation());
    assertEquals("1", payments.get(1).getTransactionOperationResultCode());
  }
  @Test
  public void testHandlePaymentCallbackEnoughStock() throws Exception {
    Customer customer = createCustomer();
    ShoppingCart shoppingCart = getShoppingCart2(customer.getEmail());
    CustomerOrder customerOrder = orderAssembler.assembleCustomerOrder(shoppingCart);
    customerOrder = deliveryAssembler.assembleCustomerOrder(customerOrder, shoppingCart, true);
    customerOrder.setPgLabel("testExtFormPaymentGatewayLabel");
    customerOrder = customerOrderService.create(customerOrder);
    assertEquals(
        "Order must be in ORDER_STATUS_NONE state",
        CustomerOrder.ORDER_STATUS_NONE,
        customerOrder.getOrderStatus());
    final String ordGuid = customerOrder.getCartGuid();
    ShopCodeContext.setShopCode(customerOrder.getShop().getCode());
    paymentCallBackHandlerFacade.handlePaymentCallback(
        new HashMap<String, String>() {
          {
            put(TestExtFormPaymentGatewayImpl.ORDER_GUID_PARAM_KEY, ordGuid);
            put(TestExtFormPaymentGatewayImpl.RESPONSE_CODE_PARAM_KEY, "1"); // 1 - means ok
          }
        },
        "testExtFormPaymentGatewayLabel");
    ShopCodeContext.clear();
    customerOrder = customerOrderService.findByGuid(customerOrder.getCartGuid());
    assertEquals(
        "Order must be in ORDER_STATUS_PARTIALLY_SHIPPED state", // because one of the delivery is
                                                                 // electronic delivery
        CustomerOrder.ORDER_STATUS_PARTIALLY_SHIPPED,
        customerOrder.getOrderStatus());

    final List<CustomerOrderPayment> payments =
        customerOrderPaymentService.findBy(customerOrder.getOrdernum(), null, null, null);
    assertNotNull(payments);
    assertEquals(payments.size(), 1);
    assertEquals(PaymentGateway.AUTH_CAPTURE, payments.get(0).getTransactionOperation());
    assertEquals("1", payments.get(0).getTransactionOperationResultCode());
  }
  /**
   * Construct payment form verification view, that shows deliveries, items in deliveries and
   * prices.
   *
   * @param id component id
   * @param orderGuid order guid
   */
  public ShoppingCartPaymentVerificationView(
      final String id, final String orderGuid, final boolean enableProductLinks) {
    super(id);

    final CustomerOrder customerOrder = checkoutServiceFacade.findByGuid(orderGuid);
    final Total grandTotal = checkoutServiceFacade.getOrderTotal(customerOrder);

    final String selectedLocale = getLocale().getLanguage();
    final Set<String> allPromos = checkoutServiceFacade.getOrderPromoCodes(customerOrder);
    for (final CustomerOrderDelivery delivery : customerOrder.getDelivery()) {
      allPromos.addAll(checkoutServiceFacade.getOrderShippingPromoCodes(delivery));
    }
    for (final CustomerOrderDet orderDet : customerOrder.getOrderDetail()) {
      allPromos.addAll(checkoutServiceFacade.getOrderItemPromoCodes(orderDet));
    }

    final String deliveryAddress = customerOrder.getShippingAddress();
    final String billingAddress = customerOrder.getBillingAddress();

    final Pair<String, String> imageSize =
        categoryServiceFacade.getThumbnailSizeConfig(0L, ShopCodeContext.getShopId());

    add(
        new ListView<CustomerOrderDelivery>(
            DELIVERY_LIST, new ArrayList<CustomerOrderDelivery>(customerOrder.getDelivery())) {

          @Override
          protected void populateItem(
              ListItem<CustomerOrderDelivery> customerOrderDeliveryListItem) {

            final CustomerOrderDelivery delivery = customerOrderDeliveryListItem.getModelObject();
            final CarrierSla sla = delivery.getCarrierSla();

            final String slaName =
                getI18NSupport()
                    .getFailoverModel(sla.getDisplayName(), sla.getName())
                    .getValue(selectedLocale);

            final List<CustomerOrderDeliveryDet> deliveryDet =
                new ArrayList<CustomerOrderDeliveryDet>(delivery.getDetail());

            final Total total =
                checkoutServiceFacade.getOrderDeliveryTotal(customerOrder, delivery);

            customerOrderDeliveryListItem
                .add(new Label(DELIVERY_CODE, delivery.getDeliveryNum()))
                .add(
                    new ListView<CustomerOrderDeliveryDet>(ITEM_LIST, deliveryDet) {

                      @Override
                      protected void populateItem(
                          ListItem<CustomerOrderDeliveryDet> customerOrderDeliveryDetListItem) {

                        final CustomerOrderDeliveryDet det =
                            customerOrderDeliveryDetListItem.getModelObject();

                        final ProductSkuDecorator productSkuDecorator =
                            getDecoratorFacade()
                                .decorate(
                                    productServiceFacade.getProductSkuBySkuCode(
                                        det.getProductSkuCode()),
                                    getWicketUtil().getHttpServletRequest().getContextPath(),
                                    true);

                        final String width = imageSize.getFirst();
                        final String height = imageSize.getSecond();

                        final String lang = getLocale().getLanguage();
                        final String defaultImageRelativePath =
                            productSkuDecorator.getDefaultImage(width, height, lang);

                        final BigDecimal itemTotal =
                            det.getPrice()
                                .multiply(det.getQty())
                                .setScale(Constants.DEFAULT_SCALE, BigDecimal.ROUND_HALF_UP);

                        final LinksSupport links = getWicketSupportFacade().links();

                        customerOrderDeliveryDetListItem
                            .add(
                                links
                                    .newProductSkuLink(ITEM_NAME_LINK, productSkuDecorator.getId())
                                    .add(
                                        new Label(
                                            ITEM_NAME_LINK_NAME,
                                            productSkuDecorator.getName(selectedLocale)))
                                    .setVisible(enableProductLinks))
                            .add(
                                new Label(ITEM_NAME, productSkuDecorator.getName(selectedLocale))
                                    .setVisible(!enableProductLinks))
                            .add(new Label(ITEM_CODE, det.getProductSkuCode()))
                            .add(new Label(ITEM_PRICE, det.getPrice().toString()))
                            .add(new Label(ITEM_QTY, det.getQty().toString()))
                            .add(new Label(ITEM_TOTAL, itemTotal.toString()))
                            .add(
                                new ContextImage(DEFAULT_IMAGE, defaultImageRelativePath)
                                    .add(
                                        new AttributeModifier(BaseComponent.HTML_WIDTH, width),
                                        new AttributeModifier(BaseComponent.HTML_HEIGHT, height)));
                      }
                    })
                .add(new Label(DELIVERY_SUB_TOTAL, total.getSubTotal().toString()))
                .add(new Label(DELIVERY_SUB_TOTAL_TAX, total.getSubTotalTax().toString()))
                .add(new Label(DELIVERY_SUB_TOTAL_AMOUNT, total.getSubTotalAmount().toString()))
                .add(new Label(DELIVERY_COST, total.getDeliveryCost().toString()))
                .add(new Label(DELIVERY_COST_TAX, total.getDeliveryTax().toString()))
                .add(new Label(DELIVERY_COST_AMOUNT, total.getDeliveryCostAmount().toString()))
                .add(new Label(DELIVERY_METHOD, slaName))
                .add(new Label(DELIVERY_ADDRESS, deliveryAddress));
          }
        });

    add(new Label(DELIVERY_GRAND_TOTAL, grandTotal.getTotal().toString()));
    add(new Label(BILLING_ADDRESS, billingAddress));
    add(new Label(DELIVERY_GRAND_TAX, grandTotal.getTotalTax().toString()));
    add(
        new PriceView(
            DELIVERY_GRAND_AMOUNT,
            new Pair<BigDecimal, BigDecimal>(
                grandTotal.getListTotalAmount(), grandTotal.getTotalAmount()),
            customerOrder.getCurrency(),
            StringUtils.join(allPromos, ", "),
            true,
            true));
  }