Pay Renewal Dues

using System;
using System.Collections.Generic;
using System.Linq;
using Asi.Soa.ClientServices;
using Asi.Soa.Commerce.DataContracts;
using Asi.Soa.Commerce.ServiceContracts;
using Asi.Soa.Core.DataContracts;
using Asi.Soa.Core.ServiceContracts;
using Asi.Soa.Membership.DataContracts;

public void PayRenewalDuesExample()
{
  // Initialize entity and cart managers, party ID that will be joining and renewing
  EntityManager entityManager = new EntityManager();

  string partyId = "18052"; // Brian Murphy

  CartManager joinCartManager = new CartManager(entityManager, partyId);

  // Get membership fees item, set item quantities and construct order line using helper method
  var findResultsData =
    entityManager.Find(
    new QueryData(ItemData.EntityTypeName)
    .AddCriteria(new CriteriaData("ItemCode",
                                  OperationData.Equal, "REGULAR_MEMBERSHIP_FEES"))).Result;
            
  ItemData item = findResultsData[0] as ItemData;

  Dictionary<string, int> quantities = new Dictionary<string, int>
  {
    {"REGULAR_MEMBERSHIP_FEES/REG", 1},
    {"REGULAR_MEMBERSHIP_FEES/PAC", 1},
    {"REGULAR_MEMBERSHIP_FEES/NORTH", 1}
  };

  OrderLineData joinOrderLine = ConstructOrderLine(item, quantities);

  // Add line to cart manager, and add payment based off of order total
  joinCartManager.AddLine(joinOrderLine);
  joinCartManager.Cart.ComboOrder.Payments = new RemittanceDataCollection
  {
    new RemittanceData
    {
      Amount = new MonetaryAmountData(
        joinCartManager.Cart.ComboOrder.Order.OrderTotal.Value.Amount,
        joinCartManager.Cart.ComboOrder.Order.Currency),
      PaymentMethod = new PaymentMethodData {PaymentMethodId = "Cash"}
    }
  };

  // Submit the cart
  joinCartManager.SubmitCart();

  // Need at least a one day offset from the join date to create a renewal billing
  DateTime tomorrow = AppTime.Now.Date.AddDays(1);
  DateTime effectiveDate = new DateTime(AppTime.Now.Year, AppTime.Now.Month, 1).AddMonths(1).AddYears(1);

  // Run membership fees billing cycle
  string billingCycle = "Regular Membership Fees";
  ILegacyBillingService billingService = Resolve<ILegacyBillingService>();

  LegacyBillingData runData = new LegacyBillingData
  {
    BillingCycleId = billingCycle,
    BillingRunName = $"{billingCycle} Test",
    IsRenewal = true,
    IndividualBillingPartyId = partyId,
    RunDate = tomorrow,
    EffectiveDate = effectiveDate
  };

  LegacyBillingResultsData billingRunResults = billingService.Run(runData);

  // Instantiate invoice ID, cart manager for renewal invoice, and find invoice by the ID
  string invoiceId = $"CASH:{partyId}:{billingRunResults.LegacyBillingDataUsedByService.BillingLogKey}";

  CartManager invoiceCartManager = new CartManager(entityManager, partyId);
  InvoiceData invoice = entityManager.FindByIdentity<InvoiceData>(invoiceId);

  invoiceCartManager.AddInvoice(invoice);

  // Instantiate membership manager and find Party by ID
  MembershipManager membershipManager = new MembershipManager(entityManager);
  PartyData party = membershipManager.FindPartyByPartyId(partyId);

  // Initialize order line from invoice, add it to the cart and create associated payment
  var orderLine =
    ComboOrderManager.GetOrderLineFromInvoice(invoice, invoiceCartManager.Cart.ComboOrder.Order, party,
                                              entityManager);

  invoiceCartManager.AddLine(orderLine);

  invoiceCartManager.Cart.ComboOrder.Payments = new RemittanceDataCollection
  {
    new RemittanceData
    {
      Amount = new MonetaryAmountData(
        invoiceCartManager.Cart.ComboOrder.Order.OrderTotal.Value.Amount,
        invoiceCartManager.Cart.ComboOrder.Order.Currency),
      PaymentMethod = new PaymentMethodData {PaymentMethodId = "Cash"}
    }
  };

  // Submit the cart
  invoiceCartManager.SubmitCart();
}

internal static OrderLineData ConstructOrderLine(ItemSummaryData item,
                                                 Dictionary<string, int> quantitiesOrdered)
{
  OrderLineData orderLine = new OrderLineData
  {
    Item = item
  };

  ItemSetItemData itemSet = item as ItemSetItemData;

  if (itemSet != null)
  {
    orderLine.ChildOrderLines = new OrderLineDataCollection();

    foreach (ItemSetComponentData component in itemSet.Components)
    {
      orderLine.ChildOrderLines.Add(ConstructOrderLine(component.Item, quantitiesOrdered));
    }

    if (orderLine.ChildOrderLines.Any(
      x => x.QuantityOrdered.HasValue && x.QuantityOrdered.Value.Amount > 0m))
    {
      orderLine.QuantityOrdered = new QuantityData(1m);
    }
  }
  else
  {
    int quantity;

    if (quantitiesOrdered.TryGetValue(item.ItemCode, out quantity))
    {
      orderLine.QuantityOrdered = new QuantityData(quantity);
    }
  }

  return orderLine;
}