@Test
  public void shouldNotAllowUserToBecomeApprover() throws Exception {
    final B2BUnitModel unit = modelService.create(B2BUnitModel.class);
    unit.setUid("aUnit");

    final B2BCustomerModel customer = modelService.create(B2BCustomerModel.class);
    customer.setUid("test");
    customer.setName("test");
    customer.setEmail("*****@*****.**");

    final Set<PrincipalGroupModel> groups = new HashSet<PrincipalGroupModel>(customer.getGroups());
    groups.add(unit);
    customer.setGroups(groups);

    final Set<B2BCustomerModel> approvers = new HashSet<B2BCustomerModel>();
    approvers.add(customer);
    unit.setApprovers(approvers);

    try {
      modelService.save(unit);
    } catch (final ModelSavingException e) {
      Assert.assertTrue(
          e.getMessage().contains("error.b2bunit.approverNotMemberOfB2BApproverGroup"));
    }
  }
  @Test
  public void shouldStartApprovalProcessAndIgnoreInactiveCreditLimit() throws Exception {
    final String userId = "GC S HH";
    login(userId);

    // Set up credit limit data for test
    final B2BUnitModel unitLoggedIn = b2bUnitService.getUnitForUid("GC Sales Hamburg");
    final B2BCreditLimitModel creditLimitToUse =
        b2bUnitService.getParent(unitLoggedIn).getCreditLimit();
    creditLimitToUse.setActive(Boolean.TRUE);
    creditLimitToUse.setDateRange(B2BPeriodRange.DAY);
    creditLimitToUse.setDatePeriod(null);
    modelService.save(creditLimitToUse);

    // Credit Limit is active, so unit is returned
    final B2BUnitModel unitWithCreditLimit = b2bUnitService.getUnitWithCreditLimit(unitLoggedIn);
    Assert.assertNotNull(unitWithCreditLimit);

    // Update credit limit with past start/end dates as date range
    final B2BCreditLimitModel creditLimit = unitWithCreditLimit.getCreditLimit();
    creditLimit.setActive(Boolean.FALSE);

    modelService.save(creditLimit);

    // Create order which crosses credit limit
    final OrderModel order =
        createOrder(
            this.login("GC S HH"),
            140,
            OrderStatus.CREATED,
            productService.getProductForCode("testProduct0"));
    Assert.assertNotNull(order);

    final B2BApprovalProcessModel b2bApprovalProcessModel =
        getB2BApprovalProcessModelForOrder(order);

    // Process does not stop at waitProcessCreditLimit, so it should continue after waitProcess
    if (this.waitForProcessAction(b2bApprovalProcessModel.getCode(), "waitProcess", 20000)) {
      modelService.refresh(order);
      final Collection<WorkflowActionModel> actions =
          b2bWorkflowIntegrationService.getStartWorkflowActions(order.getWorkflow());
      Assert.assertEquals(1, actions.size());
      b2bWorkflowIntegrationService.approveWorkflowAction(actions.iterator().next());
    }

    // Credit limit is inactive, so unit is null
    final B2BUnitModel unitWithCreditLimitNull =
        b2bUnitService.getUnitWithCreditLimit(order.getUnit());
    Assert.assertNull(unitWithCreditLimitNull);

    // Process finishes and order placed above is approved - Order total is more than credit limit
    // amount, but
    // credit limit is inactive, so its ignored
    this.waitForProcessToEnd(b2bApprovalProcessModel.getCode(), 20000);
    this.modelService.refresh(order);
    this.modelService.refresh(b2bApprovalProcessModel);
    Assert.assertEquals(OrderStatus.APPROVED, order.getStatus());
    Assert.assertEquals(ProcessState.SUCCEEDED, b2bApprovalProcessModel.getProcessState());
  }
  @Test
  public void shouldStartApprovalProcessAndAssertApprovalFromMerchant() throws Exception {
    login("GC S HH");

    // Set up credit limit data for test
    final B2BUnitModel unitLoggedIn = b2bUnitService.getUnitForUid("GC Sales Hamburg");
    final B2BCreditLimitModel creditLimitToUse =
        b2bUnitService.getParent(unitLoggedIn).getCreditLimit();
    creditLimitToUse.setActive(Boolean.TRUE);
    creditLimitToUse.setDateRange(B2BPeriodRange.DAY);
    creditLimitToUse.setDatePeriod(null);
    modelService.save(creditLimitToUse);

    final OrderModel order =
        createOrder(
            this.login("GC S HH"),
            140,
            OrderStatus.CREATED,
            productService.getProductForCode("testProduct0"));
    Assert.assertNotNull(order);

    final B2BApprovalProcessModel b2bApprovalProcessModel =
        getB2BApprovalProcessModelForOrder(order);

    final B2BUnitModel unitWithCreditLimit = b2bUnitService.getUnitWithCreditLimit(order.getUnit());

    Assert.assertEquals("GC Sales DE", unitWithCreditLimit.getUid());

    if (this.waitForProcessAction(b2bApprovalProcessModel.getCode(), "waitProcess", 20000)) {
      modelService.refresh(order);
      final Collection<WorkflowActionModel> actions =
          b2bWorkflowIntegrationService.getStartWorkflowActions(order.getWorkflow());
      Assert.assertEquals(1, actions.size());
      b2bWorkflowIntegrationService.decideAction(
          actions.iterator().next(), B2BWorkflowIntegrationService.DECISIONCODES.APPROVE.name());
    }

    if (this.waitForProcessAction(
        b2bApprovalProcessModel.getCode(), "waitProcessCreditLimit", 20000)) {
      modelService.refresh(order);
      final Collection<WorkflowActionModel> actions =
          b2bWorkflowIntegrationService.getStartWorkflowActions(order.getWorkflow());
      Assert.assertEquals(1, actions.size());
      this.approveWorkflowAction(actions.iterator().next());
    }

    this.waitForProcessToEnd(b2bApprovalProcessModel.getCode(), 20000);
    this.modelService.refresh(order);
    this.modelService.refresh(b2bApprovalProcessModel);
    Assert.assertEquals(OrderStatus.APPROVED, order.getStatus());
    Assert.assertEquals(ProcessState.SUCCEEDED, b2bApprovalProcessModel.getProcessState());
  }
  @Test
  public void shouldTriggerCreditAlert() throws Exception {
    // Step 1 There should not be any template for Alert
    final EmployeeModel employeeModel = userService.getAdminUser();
    WorkflowTemplateModel workflowTemplateModel = null;
    try {
      workflowTemplateModel =
          workflowTemplateService.getWorkflowTemplateForCode("B2B-Alert-GC Acct Mgr");
    } catch (final UnknownIdentifierException uie) {
      // Do nothing
    }

    Assert.assertNull(workflowTemplateModel);

    /**
     * Create and order between 8000 - 10000 EUR for unit GC Sales DE Alert should be created for GC
     * Sales Rep
     */
    final OrderModel order = createOrder("GC Sales DE Boss", 900, OrderStatus.CREATED);
    Assert.assertNotNull(order);

    // Set up credit limit data for test so that it generates an Alert
    final B2BUnitModel unitLoggedIn = b2bUnitService.getUnitForUid("GC Sales DE");
    final B2BCreditLimitModel creditLimitToUse = unitLoggedIn.getCreditLimit();
    creditLimitToUse.setActive(Boolean.TRUE);
    creditLimitToUse.setDateRange(B2BPeriodRange.DAY);
    creditLimitToUse.setDatePeriod(null);
    creditLimitToUse.setAlertSentDate(null);
    modelService.save(creditLimitToUse);

    final B2BApprovalProcessModel b2bApprovalProcessModel =
        getB2BApprovalProcessModelForOrder(order);

    this.waitForProcessToEnd(b2bApprovalProcessModel.getCode(), 20000);
    this.modelService.refresh(order);
    this.modelService.refresh(b2bApprovalProcessModel);

    // verify that creditCheckAlert was sent - template and workflow should exist for an Alert
    workflowTemplateModel =
        workflowTemplateService.getWorkflowTemplateForCode("B2B-Alert-GC Acct Mgr");
    Assert.assertNotNull(workflowTemplateModel);
    final List<WorkflowModel> workflowModelList =
        newestWorkflowService.getWorkflowsForTemplateAndUser(workflowTemplateModel, employeeModel);
    Assert.assertTrue(CollectionUtils.isNotEmpty(workflowModelList));

    Assert.assertEquals(OrderStatus.APPROVED, order.getStatus());
    Assert.assertEquals(ProcessState.SUCCEEDED, b2bApprovalProcessModel.getProcessState());
  }
  /*
   * Tests that a change in the unit's active state triggers a warning message. Tests that the unitActive constraint
   * does not prevent the model from being saved.
   */
  @Ignore
  public void changeInActiveStateTriggersWarningMessage() {

    // test warning triggered when changing active state to false
    final B2BUnitModel unit = b2bUnitService.getUnitForUid("GC Sales UK");
    unit.setActive(Boolean.FALSE);
    modelService.save(unit);
    Set<HybrisConstraintViolation> constraintViolations = validationService.validate(unit);

    Assert.assertTrue(checkForB2BUnitActiveAnnotation(constraintViolations));
    Assert.assertFalse(unit.getActive().booleanValue());
    Assert.assertTrue(modelService.isUpToDate(unit));

    // test warning triggered when changing active state to true
    unit.setActive(Boolean.TRUE);
    modelService.save(unit);
    constraintViolations = validationService.validate(unit);

    Assert.assertTrue(checkForB2BUnitActiveAnnotation(constraintViolations));
    Assert.assertTrue(unit.getActive().booleanValue());
    Assert.assertTrue(modelService.isUpToDate(unit));
  }
  @Test
  public void shouldAllowUserToBecomeApprover() throws Exception {
    final B2BUnitModel unit = modelService.create(B2BUnitModel.class);
    unit.setUid("aUnit");

    final B2BCustomerModel customer = modelService.create(B2BCustomerModel.class);
    customer.setUid("test");
    customer.setName("test");
    customer.setEmail("*****@*****.**");

    final Set<PrincipalGroupModel> groups = new HashSet<PrincipalGroupModel>(customer.getGroups());
    final UserGroupModel b2bApproverGroup = userService.getUserGroupForUID("b2bapprovergroup");
    groups.add(unit);
    groups.add(b2bApproverGroup);
    customer.setGroups(groups);

    final Set<B2BCustomerModel> approvers = new HashSet<B2BCustomerModel>();
    approvers.add(customer);
    unit.setApprovers(approvers);

    modelService.save(unit);
    Assert.assertFalse(modelService.isNew(unit));
    modelService.remove(unit);
  }
  /** *** */
  private B2BUnitModel createB2BUnit() {
    final B2BUnitModel unit = new B2BUnitModel();
    unit.setName(DEFAULT_B2BUNIT_NAME);

    return unit;
  }
  @Test
  public void testPerform() {

    attachments = Arrays.asList(customer, b2BRegistrationModel);

    Mockito.doAnswer(
            new Answer<Object>() {
              @Override
              public Object answer(final InvocationOnMock invocation) {
                customers = new LinkedList<>();

                return null;
              }
            })
        .when(modelService)
        .remove(customer);

    Mockito.doAnswer(
            new Answer<Object>() {
              @Override
              public Object answer(final InvocationOnMock invocation) {
                customers = new ArrayList<CustomerModel>();
                customers.add(b2BCustomer);

                return null;
              }
            })
        .when(modelService)
        .save(b2BCustomer);

    Mockito.doAnswer(
            new Answer<Object>() {
              @Override
              public Object answer(final InvocationOnMock invocation) {
                attachments = new LinkedList<ItemModel>();
                attachments =
                    Arrays.asList(createB2BCustomerModel(customers.get(0)), b2BRegistrationModel);

                return null;
              }
            })
        .when(workflowAttachmentService)
        .addItems(any(WorkflowModel.class), any(attachments.getClass()));

    workflowAttachmentService.addItems(workflowActionModel.getWorkflow(), attachments);

    when(userService.getUserForUID(b2BRegistrationModel.getEmail(), CustomerModel.class))
        .thenReturn(customer);

    final List<ItemModel> customerAsList = new LinkedList<ItemModel>();
    customerAsList.add(customer);
    when(workflowAttachmentService.getAttachmentsForAction(
            workflowActionModel, CustomerModel.class.getName()))
        .thenReturn(customerAsList);

    final List<ItemModel> b2BRegistrationModelAsList = new LinkedList<ItemModel>();
    b2BRegistrationModelAsList.add(b2BRegistrationModel);
    when(workflowAttachmentService.getAttachmentsForAction(
            workflowActionModel, B2BRegistrationModel.class.getName()))
        .thenReturn(b2BRegistrationModelAsList);

    when(modelService.create(B2BCustomerModel.class)).thenReturn(b2BCustomer);

    final WorkflowModel workflowModel = new WorkflowModel();
    workflowModel.setActions(Arrays.asList(workflowActionModel));

    workflowActionModel.setWorkflow(workflowModel);

    final WorkflowDecisionModel decision =
        registrationApprovedAutomatedWorkflowTemplateJob.perform(workflowActionModel);

    assertEquals("The right decision shoule be returned", decision, workflowDecisionModel);

    assertTrue(
        "B2BCustomer should have been created", attachments.get(0) instanceof B2BCustomerModel);

    assertEquals(
        "B2BCustomer should have been assigned a B2BUnit",
        ((B2BCustomerModel) attachments.get(0)).getDefaultB2BUnit().getName(),
        b2bUnitModel.getName());

    assertTrue(
        "b2BRegistrationModel should still be in workflow attachment",
        attachments.get(1).getClass().getName().endsWith("B2BRegistrationModel"));
  }
  @Test
  @Ignore(
      "breaks in https://bamboo.hybris.com/download/HYBRISACCELERATORR-B2BACCELERATOR-BUILD, the test needs to be refactored.")
  public void shouldTriggerCreditAlertOnceForTimePeriod() throws Exception {
    /**
     * Create and order between 8000 - 10000 EUR for unit GC Sales DE Alert should be created for GC
     * Sales Rep
     */
    login("GC Sales DE Boss");

    final OrderModel order = createOrder("GC Sales DE Boss", 900, OrderStatus.CREATED);
    b2bCartService.removeSessionCart();
    Assert.assertNotNull(order);

    // Set up credit limit data for test - should not have alert sent date
    final B2BUnitModel unitLoggedIn = b2bUnitService.getUnitForUid("GC Sales DE");
    final B2BCreditLimitModel creditLimit = unitLoggedIn.getCreditLimit();
    creditLimit.setActive(Boolean.TRUE);
    creditLimit.setDateRange(B2BPeriodRange.DAY);
    creditLimit.setAmount(BigDecimal.valueOf(10000D));
    creditLimit.setAlertThreshold(BigDecimal.valueOf(8000D));
    creditLimit.setDatePeriod(null);
    creditLimit.setAlertSentDate(null);
    modelService.save(creditLimit);

    final B2BApprovalProcessModel b2bApprovalProcessModel =
        getB2BApprovalProcessModelForOrder(order);
    this.waitForProcessToEnd(b2bApprovalProcessModel.getCode(), 20000);
    this.modelService.refresh(order);
    this.modelService.refresh(b2bApprovalProcessModel);
    Assert.assertEquals(OrderStatus.APPROVED, order.getStatus());
    Assert.assertEquals(ProcessState.SUCCEEDED, b2bApprovalProcessModel.getProcessState());
    // Check Alert Sent Date exist now
    modelService.refresh(creditLimit);
    Assert.assertNotNull("AlertSendDate should have been set", creditLimit.getAlertSentDate());

    // create a second order 100 total against the same cost center which makes the orders total of
    // 9010 for the credit limit
    // the order still  exceeds Alert Limit (8000) but the total of all orders is below credit limit
    // (1000)

    final OrderModel order2 = createOrder("GC Sales DE Boss", 10, OrderStatus.CREATED);
    Assert.assertNotNull(order2);

    final B2BApprovalProcessModel b2bApprovalProcessModel2 =
        getB2BApprovalProcessModelForOrder(order2);
    this.waitForProcessToEnd(b2bApprovalProcessModel2.getCode(), 20000);
    this.modelService.refresh(order2);
    this.modelService.refresh(b2bApprovalProcessModel2);
    Assert.assertEquals(OrderStatus.APPROVED, order2.getStatus());
    Assert.assertEquals(ProcessState.SUCCEEDED, b2bApprovalProcessModel2.getProcessState());

    // Alert Sent Date was in past, so it's updated with Current Date
    modelService.refresh(creditLimit);

    Assert.assertNotNull("AlertSentDate should not be null", creditLimit.getAlertSentDate());
    Assert.assertTrue(
        String.format(
            "AlertSentDate %s shold be in the same day as %s",
            creditLimit.getAlertSentDate(), new Date()),
        DateUtils.isSameDay(creditLimit.getAlertSentDate(), new Date()));
  }