Adding to Adam's answer, you need to create all the test data you need - Contacts, Cases and Voice_File_Loader__c records. I suspect the reason you are hitting 25% is that you code reaches this point:
for (Voice_File_Loader__c matchVFL :searchVFL){
And there are no records to loop over (unless there is a trigger doing that or something?
Once you have all the data in place, you can just run the test like this:
@isTest public class extracttest {
public static testmethod void testAccountCallout() {
Contact con - new Contact(lastName = 'Tester');
insert con;
Case testcase = new Case(contactid= con.Id,status='new',ticket_type__c='ACA',ticket_sub__c='application',priority='medium',description='blah');
batchAccountUpdate batch = new batchAccountUpdate();
test.starttest();
database.executebatch(batch,1);
test.stopTest();
}
}
The stoptest will force the batch to run as if it were being called normally, you can then perform any asserts to check the data is correct.
The remote site setting has nothing to do with the barcode appearing/not appearing.
Try the following:
<apex:image value="{!URLFOR('http://www.barcodesinc.com/generator/image.php', null, [code=relatedTo.Cust_Id__c, style=325, type='C128B', width=200, height=50, xres=1, font=3])}" />
I just tested this in my dev org with a standard field, and it works.
I suspect that your URL is getting confused because of unescaped characters, so this should fix it. You could also use URLENCODE.
I threw together some code that works in a PDF attachment, if you're really stuck. I've included the code as a Gist, but I'll also reproduce it here.
public class Code39Controller {
// Determines if the check digit should be generated
// If true, scanners must be enabled to use it
public Boolean shouldCheckDigit { get; set; }
// The source string to use. Currently only supports
// the characters in the "keys" string. Do not use '*'.
public String sourceCodeValue { get; set; }
// The index for supported characters.
static String keys = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%*';
// The binary representation of each character, 16 bits each.
static String[] values = new String[] {
'1010001110111010', '1110100010101110', '1011100010101110', '1110111000101010',
'1010001110101110', '1110100011101010', '1011100011101010', '1010001011101110',
'1110100010111010', '1011100010111010', '1110101000101110', '1011101000101110',
'1110111010001010', '1010111000101110', '1110101110001010', '1011101110001010',
'1010100011101110', '1110101000111010', '1011101000111010', '1010111000111010',
'1110101010001110', '1011101010001110', '1110111010100010', '1010111010001110',
'1110101110100010', '1011101110100010', '1010101110001110', '1110101011100010',
'1011101011100010', '1010111011100010', '1110001010101110', '1000111010101110',
'1110001110101010', '1000101110101110', '1110001011101010', '1000111011101010',
'1000101011101110', '1110001010111010', '1000111010111010', '1000100010001010',
'1000100010100010', '1000101000100010', '1010001000100010', '1000101110111010' };
// Renders the barcode on the screen
public String[] getBarCodeBars() {
return generateCode39(sourceCodeValue, shouldCheckDigit).split('');
}
// Returns a string in case we also want to debug the output.
String generateCode39(String source, Boolean checkDigit) {
// Output
String[] result = new String[0];
Integer index, // Temp variable
total = 0; // Checksum calculation
// Avoid System.NullPointerException
source = source == null? '': source;
// Start character is *
result.add(values[keys.indexOf('*')]);
// For each character in source
for(String sourceChar: source.toUpperCase().split('')) {
// Valid character, add to checksum and output bits
if((index = keys.indexOf(sourceChar)) > -1) {
result.add(values[index]);
total += index;
}
}
// Add the check digit
if(checkDigit) {
result.add(values[Math.mod(total, 43)]);
}
// Add the stop character
result.add(values[keys.indexOf('*')]);
// Join as string
return String.join(result,'');
}
}
.blackbar, .whitebar {
display: inline-block;
overflow: hidden;
padding: 0;
width: 1px;
height: 1cm;
}
.blackbar {
background-color: black;
}
.whitebar {
background-color: white;
}
<apex:component controller="code39" access="global">
<!-- global required to use in templates -->
<apex:attribute assignTo="{!shouldCheckDigit}" type="boolean" name="checkDigit" default="false" description="True if should append additional check character." />
<!-- codeValue must be supplied, but cannot be required because of global attribute -->
<apex:attribute assignTo="{!sourceCodeValue}" type="string" name="codeValue" description="The string to encode." />
<!-- style sheet must be included to work properly -->
<apex:stylesheet value="{!URLFOR($Resource.barcodeCSS)}"/>
<!-- leave some space on the side for scanners -->
<div style="display: inline-block; border: 1px solid black; min-width: 1in; padding: 0.25in 1in;" >
<div>
<apex:repeat value="{!barCodeBars}" var="bar">
<apex:outputText value="" styleClass="{!if(bar='1','blackbar','whitebar')}" />
</apex:repeat>
</div>
<div style="text-align: center">
<!-- we'll show the output text on the bottom, too -->
{!sourceCodeValue}
</div>
</div>
</apex:component>
I used it in an email as follows:
<messaging:emailTemplate subject="Account Info" recipientType="User" relatedToType="Account">
<messaging:htmlEmailBody >
Hi
Welcome to Stackexchange <br/>
Congratulations!
This is your Sample Email Template. <br/>
We are happy to provide you with the gift card <br/>
Kindly open the attachment for more details<br/>
</messaging:htmlEmailBody>
<messaging:attachment renderAs="PDF">
<html>
<head/>
<body>
<td> Hi {!relatedTo.name} </td><br/>
{!relatedTo.Phone} <br/>
We are happy to provide you with the gift card<br /><br />
<c:barcode39 codeValue="{!relatedTo.AccountNumber}" />
</body>
</html>
</messaging:attachment>
</messaging:emailTemplate>
Best Answer
Although the error says to commit or rollback before making the callout, and you are doing the rollback, SFDC seems to ignore this when the callout is executed - this could be because of batch context but I didn't have time to explore that.
OK, here are some ways to work around the error
Option 1 You will need two batchable classes and one custom object
Deferred_Callouts__c
.Deferred_Callouts__c
. insert these all in the finish() method - which then invokes Batchable class 2Considerations:
scope
.Option 2 You will need one batchable class, one custom object
Deferred_Callouts__c
, and a workflowBatchable class 1 - use the Database.savepoint - rollback sequence to get the rendered template. Then save the email recipient id and body in the custom object
Deferred_Callouts__c
. insert these all in the finish() methodUse a workflow that executes upon Create of
Deferred_Callouts__c
that uses an outbound message action to send via SOAP to the end point (assumes endpoint supports SOAP)Option 3
You will need to use the Dan Appleman Async Framework as presented at Dreamforce that allows for unlimited async operations. This is well worth understanding.
This is my personal favorite as the solution is extensible to all your async needs over time
Option 4 Do what Alexander suggested and use the simulated merge field approach here . If you have formulas in the template, this will be difficult. This avoids altogether the DML operations.