So I've been working on this project on and off for quite a while and have finally hit a crossroads. I have a custom controller and visualforce page I wrote to act as an input form. The form is supposed to build dynamically based on the frequency of related records and based on the user input should then
- create one new SIB_Invoice__c record and
- create one to many new Savings_Item_Billing_Event__c records
I've got every piece of my code to compile and run with no errors, but upon form submission the Savings_Item_Billing_Event__c
records have no values stored in the field CV_Billed__c
.
The input is done through multiple inputFields that are bound to a specific list item in a list of SOBjects.
Is this not allowed in Apex?
Posted below is my code with the line that is giving me trouble (**). I've changed the [globalIndex] to [0] a couple times and my first related record actually saves the value. Is this something I'm just going to have to do with Client-Side javascript?
Custom Controller
public class SIBInvoiceWizard {
//The account for which we will be generating an invoice.
public Account account {get; set;}
//All audits processing savings for this account.
public List<Location_Audits__c> auditsWithSavings {get; set;}
public SIB_Invoice__c invoice {get; set;}
public List<Opportunity> savingsItems {get; set;}
public List<Decimal> savingsItemAllocations {get; set;}
public List<Savings_Item_Billing_Event__c> billingEvents {get; set;}
public List<Decimal> allocationTotals {get; set;}
public Decimal invoiceTotalLabel {get; set;}
//Upon creation, initialize variables and fill lists.
public SIBInvoiceWizard(){
//Instantiate the account by querying the database for the specified ID
account = [SELECT ID, Name, Contingency_Fee__c FROM Account Where Id = :ApexPages.currentPage().getParameters().get('accId')];
//Instantiate the fill the list by querying the database for all audits and savings related to the account above.
auditsWithSavings = [SELECT Id, Name, Stage__c, Audit_Type__c,
(SELECT ID, Name, Savings_Source__c, Type, Amount, Monthly_Contract_Value__c, CV__c, CV_Total_Billed__c,
CV_Remaining__c, of_Months_Remaining__c, Recurrence_Type__c //Sub-query
FROM Opportunities__r
WHERE (StageName = 'Finalized Savings' OR StageName = 'Engagement Complete') AND CV_Remaining__c > 0)
FROM Location_Audits__c
WHERE Account__r.Id = :account.Id AND Stage__c = 'Audit Complete - Processing Savings'];
//Instantiate the Invoice and link it to the Account.
invoice = new SIB_Invoice__c();
invoice.Account__c = account.Id;
//Instantiate the lists for:
savingsItems = new List<Opportunity>(); //Cummulative list of savings items.
savingsItemAllocations = new List<Decimal>(); //List of allocation percentages that map to the savings items.
billingEvents = new List<Savings_Item_Billing_Event__c>(); //List of billingEvents that map to savings items.
allocationTotals = new List<Decimal>(); //List of totals used for calculation the allocation percentages.
for(Location_Audits__c audit : auditsWithSavings){
for(Opportunity savingsItem : audit.Opportunities__r){
savingsItems.add(savingsItem);
}
}
Integer Index = 0;
for(Opportunity savingsItem : savingsItems){
Savings_Item_Billing_Event__c newSIBE = new Savings_Item_Billing_Event__c();
newSIBE.Savings_Item__c = savingsItem.Id;
Index = Index + 1;
billingEvents.add(newSIBE);
}
//Need extra just because! Don't question it!
Savings_Item_Billing_Event__c newSIBE = new Savings_Item_Billing_Event__c();
billingEvents.add(newSIBE);
//Calculate the allocation totals for each audit category that will be used to calculate allocation percentages for each savings item.
for(Location_Audits__c audit : auditsWithSavings){
//Get the total variable recurring CV amount for further calculations.
Decimal allocationTotal = 0;
for(Opportunity savingsItem : audit.Opportunities__r){
if(savingsItem.Savings_Source__c == 'Generic VoIP Proposal' ||
savingsItem.Savings_Source__c == 'Plan Optimization' ||
savingsItem.Savings_Source__c == 'Rate Reduction' ||
savingsItem.Savings_Source__c == 'Service Standardization' ||
savingsItem.Savings_Source__c == 'Vendor Change' ||
savingsItem.Savings_Source__c == 'Vendor Consolidation'){
allocationTotal = allocationTotal + savingsItem.Amount;
}
}
allocationTotals.add(allocationTotal);
//Loop over all savingsItems again and assign allocation percentages.
for(Opportunity savingsItem : audit.Opportunities__r){
if(savingsItem.Savings_Source__c == 'Generic VoIP Proposal' ||
savingsItem.Savings_Source__c == 'Plan Optimization' ||
savingsItem.Savings_Source__c == 'Rate Reduction' ||
savingsItem.Savings_Source__c == 'Service Standardization' ||
savingsItem.Savings_Source__c == 'Vendor Change' ||
savingsItem.Savings_Source__c == 'Vendor Consolidation'){
Decimal allocationAmount = (savingsItem.Amount/allocationTotal) * 100;
allocationAmount = allocationAmount.setScale(0,RoundingMode.HALF_UP);
savingsItemAllocations.add(allocationAmount);
}
else{
savingsItemAllocations.add(100);
}
}
}
Integer allocationTotalsIndex = 0;
Integer billingEventIndex = 0;
Decimal amountPaid = 0.0;
invoiceTotalLabel = 0;
for(Location_Audits__c audit : auditsWithSavings){
for(Opportunity savingsItem : audit.Opportunities__r){
if(savingsItemAllocations[billingEventIndex] < 100){
Decimal defaultValue = (savingsItemAllocations[billingEventIndex]/100) * allocationTotals[allocationTotalsIndex];
//billingEvents[billingEventIndex].CV_Billed__c = defaultValue.setScale(2,RoundingMode.HALF_UP);
//invoiceTotalLabel = invoiceTotalLabel + billingEvents[billingEventIndex].CV_Billed__c;
//amountPaid = amountPaid + billingEvents[billingEventIndex].CV_Billed__c;
} else{
Decimal defaultValue = savingsItem.Amount * (account.Contingency_Fee__c/100);
//billingEvents[billingEventIndex].CV_Billed__c = defaultValue.setScale(2,RoundingMode.HALF_UP);
//invoiceTotalLabel = invoiceTotalLabel + billingEvents[billingEventIndex].CV_Billed__c;
//amountPaid = amountPaid + billingEvents[billingEventIndex].CV_Billed__c;
}
billingEventIndex = billingEventIndex + 1;
}
allocationTotalsIndex = allocationTotalsIndex + 1;
}
invoice.Amount_Paid__c = amountPaid;
}
//Called when the form is submitted.
public PageReference formSubmission(){
system.debug('Inside the submit method');
system.debug(savingsItems.size());
for(Savings_Item_Billing_Event__c be : billingEvents){
system.debug(be.Savings_Item__c);
system.debug(be.CV_Billed__c);
}
//Insert the created invoice into the database
insert invoice;
//Link each billingEvent created back to the newly inserted invoice, then insert the billing events.
for(Integer i = 0; i < billingEvents.size() - 1; i++){
billingEvents[i].Name = invoice.Name + '-' + '0' + (i);
billingEvents[i].SIB_Invoice__c = invoice.Id;
insert billingEvents[i];
}
//Create a new page reference for the invoice and redirect the user to the newly created invoice.
PageReference invoiceDetail = new PageReference('/'+invoice.Id);
invoiceDetail.setRedirect(true);
return invoiceDetail;
}
}
Custom Visualforce page
<apex:page controller="SIBInvoiceWizard" docType="html-5.0">
<apex:includeScript value="/soap/ajax/29.0/connection.js"/>
<apex:includeScript value="/soap/ajax/29.0/apex.js"/>
<apex:pageMessages />
<apex:sectionHeader title="SIB Invoice Wizard - (Currently In Development)"/>
<apex:form id="wizardForm">
<apex:PageBlock id="invoiceDetails" title="Invoice Details">
<apex:outputLabel value="Invoice # " style="font-weight:bold"/>
<apex:inputField id="invoiceNumber" value="{!invoice.Name}"/>
<apex:outputLabel value="Invoice Date " style="font-weight:bold"/>
<apex:inputField id="invoiceDate" value="{!invoice.Invoice_Date__c}"/>
<apex:outputLabel value="Amount Paid " style="font-weight:bold"/>
<apex:inputField id="amountPaid" value="{!invoice.Amount_Paid__c}"/>
<apex:outputLabel id="invoiceTotal" value="{!invoiceTotalLabel}" style="float:right; padding-right:175px; font-weight:bold"/>
<apex:outputLabel value="Invoice Total:" style="float:right; padding-right:5px;"/>
</apex:PageBlock>
<apex:PageBlock id="savingsForm" onkeyup="totalBillingEvents();">
<apex:variable value="{!0}" var="globalIndex"/>
<apex:variable value="{!0}" var="auditIndex"/>
<apex:repeat value="{!auditsWithSavings}" var="audit">
<apex:pageBlockSection title="{!audit.Name + ' - ' + audit.Audit_Type__c}" columns="1">
<apex:outputPanel layout="block" style="width:100%;">
<style type="text/css">
#chartTable th {}
#chartTable td {}
</style>
<div id="chartTable">
<table>
<tr>
<th style="width:15%;">Name</th>
<th style="width:15%;">Savings Source</th>
<th style="width:10%;">Type</th>
<th style="width:10%;">Recurrence Type</th>
<th style="width:5%;">Allocation Factor</th>
<th style="width:5%;">Monthly Savings</th>
<th style="width:5%;">CV - Total</th>
<th style="width:5%;">CV - Billed</th>
<th style="width:10%;">CV - Remaining</th>
<th style="width:20%;">Current Billing</th>
</tr>
<apex:repeat value="{!audit.Opportunities__r}" var="si">
<tr>
<td>{!si.Name}</td>
<td>{!si.Savings_Source__c}</td>
<td>{!si.Type}</td>
<td>{!si.Recurrence_Type__c}</td>
<td>{!savingsItemAllocations[globalIndex]}%</td>
<td>{!si.Amount}</td>
<td>{!si.CV__c}</td>
<td>{!si.CV_Total_Billed__c}</td>
<td>{!si.CV_Remaining__c}</td>
<td>
**<apex:inputField value="{!billingEvents[globalIndex].CV_Billed__c}"/>**
</td>
</tr>
<apex:variable value="{!globalIndex + 1}" var="globalIndex"/>
</apex:repeat>
<tr>
<td style="width:15%; font-weight:bold;">Totals from Recurring Variable Savings</td>
<td style="width:15%; font-weight:bold;"></td>
<td style="width:10%; font-weight:bold;"></td>
<td style="width:10%; font-weight:bold;"></td>
<td style="width:5%; font-weight:bold;"></td>
<td style="width:5%; font-weight:bold; border-top:1px solid black;">{!allocationTotals[auditIndex]}</td>
<td style="width:5%; font-weight:bold;"></td>
<td style="width:5%; font-weight:bold;"></td>
<td style="width:10%; font-weight:bold;"></td>
<td style="width:20%; font-weight:bold;"></td>
</tr>
</table>
</div>
</apex:outputPanel>
</apex:pageBlockSection>
<apex:variable value="{!auditIndex + 1}" var="auditIndex"/>
</apex:repeat>
</apex:PageBlock>
<apex:commandButton value="Submit" rerender="" style="float:right; margin-right:250px;" action="{!formSubmission}"/>
</apex:form>
</apex:page>
{!billingEvents[globalIndex].CV_Billed__c}
is not evaluating properly? Have you tried printing it out to see what it evaluates to? Have you tried checking whatglobalIndex
is?