Monday, 24 July 2017

Generate Test data with @testsetup for Quotes and QuoteLineItems with Pricebooks in Salesforce test classes

Below is the testsetup method

 @testsetup
    static void testdata(){
        Account a=new Account();
        a.name='test acc';
        insert a;
        Opportunity opp=new Opportunity();
        opp.name='test opp';
        opp.AccountId=a.id;
        opp.StageName='Prospect';
        opp.CloseDate=System.today()+28;
        insert opp;
        Quote q=new Quote();
        q.name='test';
        q.OpportunityId=opp.Id;
        q.Pricebook2Id=Test.getStandardPricebookId();
        insert q;
        Product2 p=new Product2();
        p.name='test';
        insert p;
        PricebookEntry pbe=new PricebookEntry();
        pbe.Pricebook2Id=Test.getStandardPricebookId();
        pbe.UnitPrice =5.0;
        pbe.product2Id=p.Id;
        pbe.IsActive=true;
        insert pbe;
        QuoteLineItem qli=new QuoteLineItem();
        qli.PricebookEntryId=pbe.Id;
        qli.Product2Id=p.Id;
        qli.QuoteId=q.Id;
        qli.Quantity=5.0;
        qli.UnitPrice=2.0;      
        insert qli;
    }


//Create test user in test class
@isTest
public class DeleteManualAccountShareBatch_Test {
    @isTest
    static void test1(){
        Profile p = [SELECT Id FROM Profile WHERE Name='Standard User' LIMIT 1];
        User u = new User(Alias = 'standt', Email='standarduser@testorg.com',
                          EmailEncodingKey='UTF-8', LastName='Testing2', LanguageLocaleKey='en_US',
                          LocaleSidKey='en_US', ProfileId = p.Id,
                          TimeZoneSidKey='America/Los_Angeles', UserName='tstcx@testorg.com');
        insert u;
        Account acc=new Account();
        acc.name='test';
        acc.Group_Type__c='Small';
        insert acc;
        accountshare ashare=new accountshare();
        ashare.AccountId=acc.Id;
        ashare.RowCause='Manual';
        ashare.UserOrGroupId=u.Id;
        ashare.AccountAccessLevel='Read';
        ashare.OpportunityAccessLevel='Read';
        insert ashare;      
        DeleteManualAccountShareBatch batchable=new DeleteManualAccountShareBatch();
        Database.executeBatch(batchable);
        batchable.execute(null);
        System.assertEquals(1, [SELECT Id FROM Account].size());
    }
}

Monday, 17 July 2017

Vlocity - Populating Lookup element values from Remote class

Below is the remote class,

global with sharing class LookupMemberNameFilter implements vlocity_ins.VlocityOpenInterface {
   public Boolean invokeMethod(String methodName, Map<String,Object> input, Map<String,Object> output, Map<String,Object> options) {
       boolean result=false;
       if(methodName.equals('MemberName1'))
           result=MemberName1('',input,output,options);
       return result;
   }
   public Boolean MemberName1(String methodName, Map<String, Object> input, Map<String, Object> outMap, Map<String, Object> options){
       try{       
           System.debug('input :'+input);
           List<Map<String,String>> lookupoptions=new List<Map<String,String>>();
           
           Map<String,String> dupcheckMap=new Map<String,String>();
           for(vlocity_ins__Party__c p:[Select Id,vlocity_ins__AccountId__c,vlocity_ins__AccountId__r.Name
                                        from vlocity_ins__Party__c limit 10]){
                                            if(!dupcheckMap.containsKey(String.valueOf(p.vlocity_ins__AccountId__r.Name))){
                                                if(p.vlocity_ins__AccountId__c!=null){
                                                    lookupoptions.add(new Map<String,String>{'name'=>String.valueOf(p.vlocity_ins__AccountId__c),'value'=>String.valueOf(p.vlocity_ins__AccountId__r.Name)});                                             
                                                    dupcheckMap.put(String.valueOf(p.vlocity_ins__AccountId__r.Name),String.valueOf(p.vlocity_ins__AccountId__c));
                                                }
                                            }
                                        }
           System.debug('lookupoptions'+lookupoptions);
           outMap.put('options',lookupoptions);
       }catch(Exception e){
           outMap.put('error',e+'\n'+e.getStackTraceString());
       }
       return true;
   }    
}


Vlocity - Populating Type a head block values from Remote Class

Below is the remote class,


global with sharing class TypeBlockMemberNameFilter implements vlocity_ins.VlocityOpenInterface {
   public Boolean invokeMethod(String methodName, Map<String, Object> input, Map<String, Object> outMap, Map<String, Object> options)
   {
       System.debug('input :'+input);
       List<Map<String,String>> lookupoptions=new List<Map<String,String>>();
       Map<String,Object> step=(Map<String,Object>)input.get('Create Group Step');
       Map<String,Object> memblock=(Map<String,Object>)step.get('MemberName1-Block');
       String filter=memblock.get('MemberName1')+'%';
       System.debug('filter :'+filter);
       Map<String,String> dupcheckMap=new Map<String,String>();
       for(vlocity_ins__Party__c p:[Select Id,vlocity_ins__AccountId__c,vlocity_ins__AccountId__r.Name
                                    from vlocity_ins__Party__c where vlocity_ins__AccountId__r.Name like :filter limit 10]){
                                        if(!dupcheckMap.containsKey(String.valueOf(p.vlocity_ins__AccountId__c))){
                                        lookupoptions.add(new Map<String,String>{'Id'=>String.valueOf(p.vlocity_ins__AccountId__c),'Name'=>String.valueOf(p.vlocity_ins__AccountId__r.Name,'PartyId1'=>String.valueOf(Id))});
                                        dupcheckMap.put(String.valueOf(p.vlocity_ins__AccountId__c),String.valueOf(p.vlocity_ins__AccountId__r.Name));
                                        }
       }   
       outMap.put('suggestions',lookupoptions);
       return true;
   }
}

Wednesday, 12 July 2017

How to upload multiple attachments with rerender property in visualforce

below is the visualforce page,


<apex:page controller="CashReimbursementformController" showHeader="false" sidebar="false">
 
          <!--CSS  -->  
<apex:stylesheet value="{!URLFOR($Resource.bootstrap334, 'bootstrap-3.3.4-dist/css/bootstrap.css')}"/>
<apex:stylesheet value="{!URLFOR($Resource.datepicker_bootstrap,'eternicode-bootstrap-datepicker-809a5c2/css/datepicker3.css')}"/>
<!-- JS -->
<apex:includeScript value="{!URLFOR($Resource.jquery213)}"/>
 <apex:includeScript value="{!URLFOR($Resource.angular)}"/>
<apex:includeScript value="{!URLFOR($Resource.bootstrap334, 'bootstrap-3.3.4-dist/js/bootstrap.min.js')}"/>
<apex:includeScript value="{!URLFOR($Resource.datepicker_bootstrap,'eternicode-bootstrap-datepicker-809a5c2/js/bootstrap-datepicker.js')}"/>
  <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" />
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <style>
 .glyphicon.spinning {
    animation: spin 1s infinite linear;
    -webkit-animation: spin2 1s infinite linear;
}

@keyframes spin {
    from { transform: scale(1) rotate(0deg);}
    to { transform: scale(1) rotate(360deg);}
}

@-webkit-keyframes spin2 {
    from { -webkit-transform: rotate(0deg);}
    to { -webkit-transform: rotate(360deg);}
}
/*  .requiredBlock {
    background-color: #c00;
    position: absolute;
    left: -4px;
    width: 3px;
    top: 1px;
    bottom: 1px;
    } */
    .requiredInput {
    border-left-color: red;
    border-left-width: 2px;
    }
    .validation{border-color: red;}
       
     @media print {
       #printarea,.container,.row,.col-lg-2{
          width: 100%;
        scale:46%
      }
       
     
}
   .container{
       width:100%;
       padding-left:3px;
       padding-right:3px;
           }
 </style>


      <apex:pageblock id="printarea">
<apex:outputPanel layout="block" styleclass="container">
<apex:form id="theform" enctype="multipart/form-data">
     <apex:outputpanel styleclass="row well" layout="block" id="mainpanel">
   
         <nav class="navbar navbar-default" role="navigation" style="background-color:white;border-color:ghostwhite">
  <div class="">
    <ul class="nav navbar-nav navbar-left">
        <li><img src="{!URLFOR($Resource.FH2013, '/newCss_js/images/fairhealth_logo.png')}" style="padding:10px" class="img img-responsive" /></li>
     
    </ul>
        <!--
    <ul class="nav navbar-nav navbar-right" style="margin:5px">
      <li>  <h4>                      
          CASH REIMBURSEMENT REPORT</h4><hr style="margin:5px"/>
          <table class="" >
                  <tbody>
              <tr>
              <td style="text-align:right;font-family:arial;font-size:12px">Mileage Rate</td>
              <td style="text-align:left"><apex:inputText value="{!expense.Mileage_Rate__c}" styleClass="" /></td>
              </tr>
             <tr>
              <td style="text-align:right;font-family:arial;font-size:12px">Meal Rate</td>
              <td style="text-align:left"><apex:inputText value="{!expense.Meal_Rate__c}" styleClass=""  /></td>
              </tr>
              <tr>
              <td style="text-align:right;font-family:arial;font-size:12px">Hotel Rate</td>
              <td style="text-align:left"><apex:inputText value="{!expense.Hotel_Rate__c}" styleClass=""  /></td>
              </tr>
              <tr>
              <td style="text-align:right;font-family:arial;font-size:12px"></td>
                <td style="text-align:left">
                 
                        </td>
                    </tr>
                  </tbody>
          </table>
       
        </li>
   
    </ul>
                        -->
  </div>
</nav>
       
 
    <div id="main">    
         
      <div class="panel panel-primary"  style="background-color:white;border-color:ghostwhite">
      <div class="panel-body ">        
          <div class="row">
              <div class="col-lg-12">
                  <apex:pagemessages />
                  </div>
              </div>
        <div class="row" style="overflow:auto">
          <div class="col-lg-5 col-lg-offset-1">          
             <table class="" >
                  <tbody>
              <tr>
              <td style="text-align:left;font-family:arial;font-size:12px">Name</td>
              <td style="text-align:left"><apex:inputText value="{!expense.name__c}" styleClass="" /></td>
              </tr>
                <tr><td>&nbsp;</td><td>&nbsp;</td></tr>
             <tr>
              <td style="text-align:left;font-family:arial;font-size:12px">Department</td>
              <td style="text-align:left"><apex:inputText value="{!expense.Department__c}" styleClass=""  /></td>
              </tr>              
                <tr><td>&nbsp;</td><td>&nbsp;</td></tr>
              <tr>
              <td style="text-align:left;font-family:arial;font-size:12px">Position</td>
              <td style="text-align:left"><apex:inputText value="{!expense.Position__c}" styleClass=""  /></td>
              </tr>              
                <tr><td>&nbsp;</td><td>&nbsp;</td></tr>
              <tr>
              <td style="text-align:left;font-family:arial;font-size:12px">Manager</td>
              <td style="text-align:left"><apex:inputField value="{!expense.Manager__c}" styleClass=""  /></td>
              </tr>
                  </tbody>
          </table>
          </div>
          <div class="col-lg-6">
             <table class="" >
                  <tbody>
              <tr>
              <td style="text-align:left;font-family:arial;font-size:12px">Begining</td>
              <td style="text-align:left"><apex:inputText value="{!begining}" styleClass="date" /></td>
              </tr>              
                <tr><td>&nbsp;</td><td>&nbsp;</td></tr>
             <tr>
              <td style="text-align:left;font-family:arial;font-size:12px">Ending</td>
              <td style="text-align:left"><apex:inputText value="{!ending}" styleClass="date"  /></td>
              </tr>              
                <tr><td>&nbsp;</td><td>&nbsp;</td></tr>
              <tr>
              <td style="text-align:left;font-family:arial;font-size:12px">Prepared By</td>
              <td style="text-align:left"><apex:inputField value="{!expense.Prepared_By__c}" styleClass=""  /></td>
              </tr>              
                <tr><td>&nbsp;</td><td>&nbsp;</td></tr>
              <tr>
              <td style="text-align:left;font-family:arial;font-size:12px">Approved By</td>
              <td style="text-align:left"><apex:inputField value="{!expense.Approved_By__c}" styleClass=""  /></td>
              </tr>
                  </tbody>
          </table>
          </div>          
        </div>
       <div class="row">
          <div class="col-lg-5 col-lg-offset-1">
              <br />
                     Business Purpose
                     <apex:inputTextarea value="{!expense.Business_Purpose__c}" styleClass="form-control" rows="2" />
                           
          </div>
       
        </div>
                     <div class="row">
          <div class="col-lg-10 col-lg-offset-1">
              <br />
                     Travel Authorization&nbsp;
                     <apex:inputField value="{!expense.Travel_Authorization__c}"  />
                          <apex:actionRegion >
                    <apex:commandButton action="{!addTravelAuthorization}"
                                               
                        value="Add expenses" />
                    </apex:actionRegion>
                           
          </div>
       
        </div>
      </div>
    </div>
   </div>
       
       
         <!-- Begining of new table -->
          <div id="main">    
         
      <div class="panel panel-primary"  style="background-color:white;border-color:ghostwhite">
      <div class="panel-body ">
        <div class="row">
          <div class="col-lg-12">
              <div class="table-responsive">
                  <apex:outputpanel id="expenseitem_panel">
             <table class="table table-hover" width="100%">
                 <thead style="background-color:#000040;color:white;font-weight:bold">
              <tr>
                  <th>Category</th>
                    <th>Date</th>
                    <th>Vendor Name</th>
                    <th>Location</th>
                    <th>Quantity</th>
                    <th>Amount</th>
                    <th>Payment Type</th>
                    <th>Reimburse</th>
                    <th>Attachment</th>
                 </tr>
                     </thead>
                 <tbody>
                    <apex:repeat value="{!ewrapper_list}" var="eli">
                 <tr>
                        <td><apex:inputField value="{!eli.expitem.Category__c}" styleclass="form-control" style="width:145px" /></td>
                  <td><apex:inputText value="{!eli.expense_date}" styleClass="date form-control" style="width:100px" /></td>
                  <td><apex:inputText value="{!eli.Vendor_Name}" styleclass="form-control" style="width:100px" /></td>
                  <td><apex:inputText value="{!eli.Vendor_Location}" styleclass="form-control" style="width:90px" /></td>
                  <td><apex:inputText value="{!eli.quantity}" styleclass="form-control" style="width:90px" /></td>
                  <td><apex:inputText value="{!eli.Amount}"  styleclass="form-control amt" style="width:90px" /></td>
                  <td><apex:inputField value="{!eli.expitem.Payment_Type__c}" styleclass="form-control" style="width:130px" /></td>
                  <td><apex:inputCheckbox value="{!eli.Reimburseable}" style="width:20px" /></td>
                    <td> <apex:inputFile value="{!eli.att.body}" filename="{!eli.att.name}" id="file"  style="width:190px" rendered="{!if(eli.att.name==null,true,false)}" />
<apex:inputText value="{!eli.att.name}"  styleclass="form-control amt" style="width:190px" rendered="{!if(eli.att.name!=null,true,false)}" />
                        </td>
                 </tr>
                    </apex:repeat>                  
                      <tr>
                        <td colspan="2">
                        <apex:actionRegion >
                        <apex:commandbutton action="{!addExpenseLineItem}" value="Add Item"  />
                            <apex:commandbutton action="{!removeExpenseLineItem}" value="Remove Item" />
                                </apex:actionRegion>
                                </td>
                 
                  <td></td>
                  <td></td>
                  <td></td>
                  <td></td>
                  <td></td>
                  <td></td>                          
                  <td></td>
                 </tr>
                      <tr style="background-color:#000040">
                  <td></td>
                  <td style="color:white">Total Amount</td>
                  <td></td>
                  <td style="color:white"></td>
                  <td style="color:white"></td>
                  <td style="color:white">$<span id="result"></span></td>
                    <td style="color:white"></td>
                  <td style="color:white"></td>
                  <td style="color:white"></td>
                 </tr>
                     </tbody>
          </table>
                    </apex:outputpanel>
              </div>
          </div>
        </div>      
          <div class="row">
            <div class="col-lg-5">
                <!--
                <div class="input-group">
                    <span class="input-group-addon" id="basic-addon1"  >Total Travel</span>
                    <apex:inputText styleclass=""   html-placeholder="" html-aria-describedby="basic-addon1" />
                </div><br />
                <div class="input-group">
                    <span class="input-group-addon" id="basic-addon1"  >Total Communication</span>
                    <apex:inputText styleclass=""   html-placeholder="" html-aria-describedby="basic-addon1" />
                </div><br />
                <div class="input-group">
                    <span class="input-group-addon" id="basic-addon1"  >Total Other</span>
                    <apex:inputText styleclass=""   html-placeholder="" html-aria-describedby="basic-addon1" />
                </div><br />
                        -->                      
                  <apex:commandbutton action="{!save}" value="Submit"  />
                      <!--
                  <apex:commandbutton action="{!saveAttachments}" value="Submit" />    
                      -->
            </div>
            <div class="col-lg-5">
               
            </div>
          </div>
     
      </div>
    </div>
   </div>
         <!-- ending of new table -->
       
  </apex:outputpanel>

 <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
          <div class="modal-header">
           <div class="modal-body">
             <button class="btn btn-primary btn-lg loadbtn center-block">
                    <span class="glyphicon glyphicon-refresh" id="load"></span>
                    <span id="loadstatus">Status</span>
            </button>
      </div>
     </div>
    </div>
  </div>
</div>

 </apex:form>  
</apex:outputPanel>
                 
    </apex:pageblock><!-- JS -->

 <apex:outputPanel id="script">.
 <script type="text/javascript">
     $(document).ready(function(){
     $('.date').datepicker({ dateFormat: 'yy-mm-dd'});
     $(".amt").change(function(){
$(calculateSum);  
          $('#result').text(sum);
     });
     $(calculateSum);
     function calculateSum() {
         var sum = 0;
         //iterate through each td based on class and add the values
         $(".amt").each(function() {
           
             //add only if the value is number
             if(!isNaN(this.value) && this.value.length!=0) {
                 sum += parseFloat(this.value);
             }
           
         });
         $('#result').text(sum);  
     };
 });
 
    </script>
  </apex:outputPanel>
         
</apex:page>



Below is it's controller,


public class CashReimbursementformController {
    public double mileage_rate{get;set;}
    public double meal_rate{get;set;}
    public double hotel_rate{get;set;}
    public String name{get;set;}
    public double total_reimbursement{get;set;}
    public Expense__c expense{get;set;}
    public String begining{get;set;}
    public String ending{get;set;}
    public List<ExpenseItemWrapper> ewrapper_list{get;set;}
    public CashReimbursementformController(){
        total_reimbursement=0.0;
        expense=new Expense__c();
        User u=[SELECT Id,name,department,userrole.name,managerId from User where Id=:UserInfo.getUserId() LIMIT 1];
        expense.Name__c=u.Name;
        expense.Department__c=u.Department;  
        expense.Position__c=u.userrole.name;
        expense.Manager__c=u.managerId;
        expense.Prepared_By__c=u.Id;
        expense.Approved_By__c=u.managerId;
        begining=String.valueOf(Date.today());
        ending=String.valueOf(Date.today());      
        ewrapper_list=new List<ExpenseItemWrapper>();
        ewrapper_list.add(new ExpenseItemWrapper());
    }
    public PageReference addTravelAuthorization(){
        System.debug('travelauth Id:'+expense.Travel_Authorization__c);
        List<Estimated_Expenses__c> eelist=[SELECT expense_type__c,Description__c,createddate,Amount__c FROM Estimated_Expenses__c WHERE Travel_Authorization__c=:expense.Travel_Authorization__c];
        System.debug('eelist size: '+eelist.size());
        for(Estimated_Expenses__c e:eelist){
            ewrapper_list.add(new ExpenseItemWrapper(e.expense_type__c,e.description__c,e.createddate,e.amount__c));
        }  
        return null;
    }  
    public void addExpenseLineItem(){
       /* if(expense.Id==null){
            insert expense;
        }
        System.debug('expense Id'+expense.Id);
        List<ExpenseLineItem__c> ellist=new List<ExpenseLineItem__c>();
        for(ExpenseItemWrapper ew:ewrapper_list){
            if(ew.expitem.Id==null){
            ew.expitem.expense__c=expense.Id;
            ew.expitem.date__c=Date.valueOf(ew.expense_date);
            ew.expitem.vendor_name__c=ew.vendor_name;
            ew.expitem.vendor_location__c=ew.vendor_location;
            ew.expitem.description__c=ew.quantity;
            ew.expitem.amount__c=ew.amount;
            ew.expitem.reimburseable__c=ew.reimburseable;
            ellist.add(ew.expitem);
            }
        }
        insert ellist;
        System.debug('ellist size'+ellist.size());
         List<Attachment> attlist=new List<Attachment>();    
         Set<Id> eitemset=new Set<Id>();
            for(ExpenseItemWrapper ew:ewrapper_list){
                if(ew.att.body!=null && ew.att.name!=null && ew.att.Id==null){
                    ew.att.parentId=ew.expitem.Id;
                    eitemset.add(ew.expitem.Id);
                    attlist.add(ew.att);
                }
            }
            if(attlist.size()!=0)
            insert attlist;
        ewrapper_list.clear();
        System.debug('eitemset:'+eitemset);
        List<ExpenseLineItem__c> eitemlist=[SELECT Id,Category__c,Payment_Type__c,date__c,vendor_name__c,vendor_location__c,description__c,amount__c,Reimburseable__c,(select name from attachments limit 1) FROM ExpenseLineItem__c WHERE Id IN:eitemset];
        System.debug('eitemlist :'+eitemlist);
        for(ExpenseLineItem__c e:eitemlist){
         ewrapper_list.add(new ExpenseItemWrapper(e));  
        }*/
        ewrapper_list.add(new ExpenseItemWrapper());
    }
    public void removeExpenseLineItem(){
        if(ewrapper_list.size()!=0)
            ewrapper_list.remove(ewrapper_list.size()-1);
    }
    class ExpenseItemWrapper{
        public ExpenseLineItem__c expitem{get;set;}
        public String expense_date{get;set;}
        public String vendor_name{get;set;}
        public String vendor_location{get;set;}
        public String quantity{get;set;}
        public Decimal amount{get;set;}
        public boolean reimburseable{get;set;}      
        public Attachment att {
            get {
                if (att == null)
                    att = new Attachment();
                return att;
            }
            set;
        }
        public ExpenseItemWrapper(){
            att=new Attachment();
            expitem=new ExpenseLineItem__c();
        }      
        public ExpenseItemWrapper(String category,string descr,Datetime edate,Decimal amt){
            expitem=new ExpenseLineItem__c();
            expitem.category__c=category;
            att=new Attachment();
            quantity=descr;
            expense_date=String.valueOf(Date.valueOf(edate));
            amount=amt;
        }  
        public ExpenseItemWrapper(ExpenseLineItem__c e){
            expitem=e;
            //att.name=e.attachments.get(0).name;
            att=e.attachments.get(0);
        }
    }
    public PageReference save(){  
        PageReference pg=null;
        try{          
            expense.Begining__c=Date.valueOf(begining);
            expense.Ending__c=Date.valueOf(ending);
            insert expense;
            pg=new PageReference('/'+expense.Id);
            List<ExpenseLineItem__c> ellist=new List<ExpenseLineItem__c>();
            for(ExpenseItemWrapper ew:ewrapper_list){
               ew.expitem.expense__c=expense.Id;
               ew.expitem.date__c=Date.valueOf(ew.expense_date);
               ew.expitem.vendor_name__c=ew.vendor_name;
               ew.expitem.vendor_location__c=ew.vendor_location;
               ew.expitem.description__c=ew.quantity;
               ew.expitem.amount__c=ew.amount;
               ew.expitem.reimburseable__c=ew.reimburseable;
               ellist.add(ew.expitem);
            }
            insert ellist;
            List<Attachment> attlist=new List<Attachment>();    
            for(ExpenseItemWrapper ew:ewrapper_list){
                if(ew.att.body!=null && ew.att.name!=null){
                    ew.att.parentId=ew.expitem.Id;
                    attlist.add(ew.att);
                }
            }
            if(attlist.size()!=0)
            insert attlist;  
        }catch(Exception e){
           ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR,e.getMessage()));
            System.debug(e+'\n'+e.getStackTraceString());
        }
        return pg;
    }
    /*
      public PageReference saveAttachments(){
        PageReference pg=null;
        try{          
            pg=new PageReference('/'+expense.Id);
            List<Attachment> attlist=new List<Attachment>();    
            for(ExpenseItemWrapper ew:ewrapper_list){
                if(ew.att.body!=null && ew.att.name!=null){
                    ew.att.parentId=ew.expitem.Id;
                    attlist.add(ew.att);
                }
            }
            if(attlist.size()!=0)
            insert attlist;  
        }catch(Exception e){
           ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR,e.getMessage()));
            System.debug(e+'\n'+e.getStackTraceString());
        }
        return pg;
    }
    */
}


How to add/remove line items on changing multipicklist values with a trigger

Create custom objects with names Proposal, ProposalLineItem, Proposaltemplates.

Create a trigger on Proposal like this,

/*
@author: Balayesu
@date: 7/9/2017
@description: trigger for creating/removing proposal line items
*/
trigger ProposalTriger on Proposal__c (after insert,before update) {
    //create items after inserting a proposal
    if(trigger.isinsert){
        Set<Id> pidset=new Set<Id>();
        for(Proposal__c p:trigger.new){
            pidset.add(p.Id);
        }
        List<Proposal__c> plist=[SELECT Id,Products__c,(SELECT Id,name,Proposal__c FROM Proposal_Products__r) FROM Proposal__c WHERE Id IN:pidset];
        ProposalTrigerHelper.addItems(plist);
    }
    if(trigger.isupdate){
        Map<Id,List<Proposal_Products__c>> plimap=new Map<Id,List<Proposal_Products__c>>();
        for(Proposal__c np:[SELECT Id,Products__c,(SELECT Id,name,Proposal__c FROM Proposal_Products__r) FROM Proposal__c WHERE Id IN:trigger.newMap.keySet()]){
            plimap.put(np.Id,np.Proposal_Products__r);
        }    
        //get the changed proposals
        for(Id pId:Trigger.newMap.keySet()){
            //check if new picklist items not matched with old picklist items
            if(trigger.oldMap.get(pId).Products__c!=trigger.newMap.get(pId).Products__c){
                ProposalTrigerHelper.removeItems(trigger.oldmap,trigger.newmap,plimap);
            }
        }  
    }
}


Create the helper like this,

public class ProposalTrigerHelper {
    //add a line item after inserting a proposal
    public static void addItems(List<Proposal__c> proposals){
        System.debug('Adding Items');
        //create a products list
        List<Proposal_Products__c> productslist=new List<Proposal_Products__c>();        
        for(Proposal__c p:proposals){
            //iterate through all the selected products of multipicklist
            if(p.Products__c!=null){
            for(String pname:(p.Products__c).split(';')){
                if(p.Proposal_Products__r.size()>0){
                    for(Proposal_Products__c pp:p.Proposal_Products__r){
                        //if product doesn't exists
                        if(!pname.equals(pp.name)){ 
                            //add Line items to the list                        
                            productslist.add(new Proposal_Products__c(name=pname,Proposal__c=p.Id,Solution__c=getSolution(pname))); 
                        }
                    }
                }
                else{
                    productslist.add(new Proposal_Products__c(name=pname,Proposal__c=p.Id,Solution__c=getSolution(pname))); 
                }                
            }
            }
                    
        }
        //create line items to the proposal
        try{
            insert productslist;  
        }catch(DMLException de){
            System.debug(de);
        }        
    }
    //remove item if it is unselected before updating it
    public static void removeItems(Map<Id,Proposal__c> oldproposalsMap,Map<Id,Proposal__c> newproposalsMap,Map<Id,List<Proposal_Products__c>> plimap){
        System.debug('Removing Items');
        Map<String,Id> delMap=new Map<String,Id>(); 
        List<Proposal_Products__c> addproductslist=new List<Proposal_Products__c>();  
        List<Proposal_Products__c> delproductslist=new List<Proposal_Products__c>();   
        List<Proposal_Products__c> pitemslist=new List<Proposal_Products__c>();
        System.debug('oldpmap:'+oldproposalsMap+'\n'+'newpMap:'+newproposalsMap);    
        //iterate all old picklist values
        for(Id opId:oldproposalsMap.keySet()){
            if(oldproposalsMap.get(opId).Products__c!=null){
                //delete removed items
                for(String pname:(oldproposalsMap.get(opId).Products__c).split(';')){
                    //if old value is removed from picklist
                    if(!isAvailable(pname,newproposalsMap)){ 
                        System.debug('deleting item: '+pname+'\n No of products: '+plimap.get(opId).size());                    
                        //iterate all the line items
                        for(Proposal_Products__c pp:plimap.get(opId)){
                            System.debug('ppname:'+pp.name);
                            //if product name matches with removed line item
                            if((pp.name).equals(pname)){ 
                                System.debug('Product Added for deletion');
                                delproductslist.add(pp); 
                                //break;
                            }
                        }
                    }
                }
                //check for all the existing ones for their line items
                  for(String pname:(oldproposalsMap.get(opId).Products__c).split(';')){
                      if(!Itemexists(pname,plimap.get(opId))){
                          pitemslist.add(new Proposal_Products__c(name=pname,Proposal__c=opId,Solution__c=getSolution(pname)));
                      }
                  }
            }
        } 
        try{
            delete delproductslist;
        }catch(DMLException de){
            System.debug(de);
        }  
        try{
            insert pitemslist;
        }catch(DMLException e){
            System.debug(e);
        }
        for(Id opId:newproposalsMap.keySet()){
            if(newproposalsMap.get(opId).Products__c!=null){
                for(String pname:(newproposalsMap.get(opId).Products__c).split(';')){
                    //if new value not found in old list
                    if(!isAvailable(pname,oldproposalsMap)){
                        System.debug('products size :'+plimap.get(opId).size());
                        addproductslist.add(new Proposal_Products__c(name=pname,Proposal__c=opId,Solution__c=getSolution(pname)));
                    }
                }
            }
        }
        try{
            insert addproductslist;
        }catch(DMLException e){
            System.debug(e);
        }
    }
    public static String getSolution(String productname){
        String sol='';
        sol=[SELECT Solution__c from Proposal_Product_Solution_Template__c WHERE name=:productname LIMIT 1].Solution__c;
        return sol;
    }
    public static boolean isAvailable(String pname,Map<Id,Proposal__c> proposalsMap){
        boolean flag=false; 
        for(Id npId:proposalsMap.keySet()){
            if(proposalsMap.get(npId).Products__c!=null){
                for(String npname:(proposalsMap.get(npId).Products__c).split(';')){
                    if(npname.equals(pname)){
                        flag=true;                     
                        break;
                    }
                }
            }
        }
        System.debug('isAvailable? '+flag);
        return flag;
    }
    public static boolean Itemexists(String pname,List<Proposal_Products__c> pitemslist){
        boolean flag=false;
        for(Proposal_Products__c item:pitemslist){
            if((item.name).equals(pname)){
                flag=true;
                break;
            }
        }
        return flag;
    }
}



Below is the test class for the above code,

@isTest
public class ProposalTriggerHelper_UT {
    @testsetup
    static void testdata(){
        List<Proposal_Product_Solution_Template__c> templist=new List<Proposal_Product_Solution_Template__c>();
        Proposal_Product_Solution_Template__c temp1=new Proposal_Product_Solution_Template__c();
        temp1.name='Data Modules Organized by Service Type';
        temp1.Solution__c='test sol1';
        templist.add(temp1);
        Proposal_Product_Solution_Template__c temp2=new Proposal_Product_Solution_Template__c();
        temp2.name='Private-Label Member Engagement Tools';
        temp2.Solution__c='test sol1';
        templist.add(temp2);
        insert templist;
        Proposal__c p=new Proposal__c();
        p.Products__c='Data Modules Organized by Service Type;Private-Label Member Engagement Tools';
        insert p;
    }
  @isTest
    static void test1(){
        Proposal__c p=[SELECT Products__c FROM Proposal__c LIMIT 1];
        p.Products__c='Data Modules Organized by Service Type';
        update p;
        System.assertEquals(1,[SELECT name FROM Proposal_Products__c WHERE Proposal__c=:p.Id].size());
    }  
  @isTest
    static void test2(){
        Proposal__c p=[SELECT Products__c FROM Proposal__c LIMIT 1];
        p.Products__c='';
        update p;
        System.assertEquals(0,[SELECT name FROM Proposal_Products__c WHERE Proposal__c=:p.Id].size());
    }
}



How to send email for every 30 minutes with batch apex in Business hours

Below is the code to send email for every 30 minutes with a batch class.


global class OpportunityNotifierBatch implements Database.Batchable<sObject>,Database.Stateful, Schedulable {
    public Map<Id,String> emailmap{get;set;}
    global void scheduleMe() {      
        system.schedule('OpportunityNotifierBatch 1', '0 00 * * * ?', new OpportunityNotifierBatch());
        system.schedule('OpportunityNotifierBatch 2', '0 30 * * * ?', new OpportunityNotifierBatch());      
    }
    global void execute(SchedulableContext sc){
        if(isBusinessHour()){
        OpportunityNotifierBatch batch=new OpportunityNotifierBatch();
        ID batchprocessid=Database.executeBatch(batch);
        }
    }
    global Database.QueryLocator start(Database.BatchableContext BC) {
        Datetime d = datetime.now().addMinutes(-30);
        emailmap=new Map<Id,String>();
        String query = 'select id, createddate, name ,owner.email from Opportunity where createddate < :d LIMIT 10';
        return Database.getQueryLocator(query);
    }
    global void execute(Database.BatchableContext BC, List<Opportunity> scope) {
        for(Opportunity w : scope){          
            emailmap.put(w.Id,w.owner.email);        
        }
    }  
    global void finish(Database.BatchableContext BC) {      
    //finish will be called after last batch finishes
        for(Id i:emailmap.keySet())
            sendEmail(i,emailmap.get(i));
    }
    public void sendEmail(Id wId,String email){
        Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
        List<String> emaillist=new List<String>();
        emaillist.add(email);
        message.toAddresses = emaillist;
        //message.ccAddresses = new List<String> {label.Off_Boarding_CC_Email_addresses};
        message.subject = 'Reminder: You have a new record';
        message.plainTextBody = 'Please review the following Work Request\n'+
            'Detail link :'+ URL.getSalesforceBaseUrl().toExternalForm()+'/'+wId;
        Messaging.SingleEmailMessage[] messages =
            new List<Messaging.SingleEmailMessage> {message};
                Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);
        if (results[0].success) {
            System.debug('The email was sent successfully.');
        } else {
            System.debug('The email failed to send: '
                         + results[0].errors[0].message);
        }
    }
    public boolean isBusinessHour(){
        // Get the default business hours
        BusinessHours bh = [SELECT Id FROM BusinessHours WHERE IsDefault=true];
        DateTime targetTime=DateTime.now().addMinutes(-30);
        // Find whether the time is within the default business hours
        Boolean isWithin= BusinessHours.isWithin(bh.id, targetTime);
        return isWithin;
    }
}


In Debug> open execute anonymous window, execute the following line,

new OpportunityNotifierBatch().scheduleMe();

The above line schedules your batch class and for every 30 minutes opportunity owners will be notified with an email.
The maximum emails a batch class can process at a time is 10.
Note the method isWithin(Id,time) will return true is the present time is in business hour.