понеділок, 26 жовтня 2015 р.

Salesforce: фіксаємо помилку "Current Company is not set"

Чудова стаття про те, як пофіксати помилку Current Company is not set.


Загалом під час тесту можуть траплятися дві помилки:

1. Current Company is not set.

2. This operation cannot be performed in multi-company mode

Загалом ці помилки залежать від кількості джанкшин-обджект рекордів між юзером і кода-компані. Якщо ці квері

[ select Id from c2g__codaUserCompany__c where c2g__User__c = :UserInfo.getUserId() ].size()
[ select Count(Id) from c2g__codaUserCompany__c where c2g__User__c = :UserInfo.getUserId() ]
повертають число 0, тоді маємо помилку "Current Company is not set", якщо вони повертають число, більше за одиницю, тоді маємо помилку "This operation cannot be performed in multi-company mode".

Щоб не було помилки, потрібно мати рівно один запис в базі даних для джанкшин-обджекта кода-юзер-компані c2g__codaUserCompany__c. Тому бажано мати @isTest(seeAllData=false), бо якщо поставити @isTest(seeAllData=true). можуть бути видимі записи, які існують на сендбоксі чи продакшині.



Ось код з оригінальної статті.



@isTest 
private class salesInvoiceTestClass {
 static testMethod void salesInvoiceTest() {
 Group testGroup = new Group(Name='test group', Type='Queue');
 insert testGroup;
 QueuesObject testQueue ; 
 System.runAs(new User(Id=UserInfo.getUserId())) {
     List<queuesobject >  listQueue = new List<queuesobject >();
   queuesobject q1 = new queuesobject (queueid=testGroup.id, sobjecttype='Case'); 
   listQueue.add(q1);
   queuesobject q2 = new queuesobject (queueid=testGroup.id,                                                                 sobjecttype='c2g__codaAccountingCurrency__c'); 
   listQueue.add(q2);
   queuesobject q3 = new queuesobject (queueid=testGroup.id,                                                                 sobjecttype='c2g__codaPurchaseInvoice__c'); 
   listQueue.add(q3);
   queuesobject q4 = new queuesobject (queueid=testGroup.id, sobjecttype='c2g__codaCompany__c'); 
   listQueue.add(q4);
   queuesobject q5 = new queuesobject (queueid=testGroup.id, sobjecttype='c2g__codaYear__c'); 
   listQueue.add(q5);
   queuesobject q6 = new queuesobject (queueid=testGroup.id, sobjecttype='c2g__codaInvoice__c'); 
   listQueue.add(q6);
   insert  listQueue;

   GroupMember GroupMemberObj = new GroupMember();
   GroupMemberObj.GroupId = testGroup.id;
   GroupMemberObj.UserOrGroupId = UserInfo.getUserId();
   insert GroupMemberObj;
 }        

 c2g__codaCompany__c company = new c2g__codaCompany__c();
 company.Name = 'Test Record';
 company.c2g__CashMatchingCurrencyMode__c = 'Test Account';
 company.c2g__YearEndMode__c = 'Test Code';
 company.c2g__ExternalId__c = 'ABCDE1234567876';
 company.c2g__LogoURL__c ='ww.XYZ.com';
 company.c2g__ECCountryCode__c = 'AE' ;
 company.c2g__VATRegistrationNumber__c = 'Test 222.222.222 TVA' ;
 company.c2g__Website__c = 'ww.xyz.com';
 company.c2g__Country__c ='US';
 company.ownerid = testGroup.Id;
 insert company;

 c2g__codaYear__c yr= new c2g__codaYear__c();
 yr.Name ='2015';
 yr.c2g__AutomaticPeriodList__c =  true;
 yr.c2g__OwnerCompany__c = company.id;
 yr.c2g__ExternalId__c = 'yzsd1234';
 yr.c2g__NumberOfPeriods__c =11;
 yr.c2g__StartDate__c =  system.today() - 10;
 yr.c2g__Status__c = 'Open';
 yr.c2g__PeriodCalculationBasis__c = '445';
 yr.c2g__YearEndMode__c = 'Full Accounting Code' ; 
 yr.c2g__UnitOfWork__c = 12;
 yr.ownerid = testGroup.Id;
 insert yr;

 c2g__codaPeriod__c prd = new c2g__codaPeriod__c();
 prd.Name ='Test2015';
 prd.c2g__ExternalId__c ='abdc12345';
 prd.c2g__StartDate__c = System.today()-10;
 prd.c2g__EndDate__c= System.today()+10;
 prd.c2g__OwnerCompany__c = company.id;
 prd.c2g__PeriodNumber__c ='123';
 prd.c2g__Description__c ='test Desc';
 prd.c2g__PeriodGroup__c = 'Q1';
 prd.c2g__PeriodNumber__c = '1';
 prd.c2g__YearName__c = yr.id;
 insert prd;

 c2g__codaUserCompany__c userCompany = new c2g__codaUserCompany__c();
 userCompany.c2g__Company__c =company.id;
 userCompany.c2g__User__c = userInfo.getUserId();
 userCompany.c2g__ExternalId__c = 'ABCDE1234567876';
 userCompany.c2g__UnitOfWork__c = 111 ;
 insert  userCompany;

 c2g__codaAccountingCurrency__c accCurrency = new c2g__codaAccountingCurrency__c();
 accCurrency.c2g__OwnerCompany__c = company.id;
 accCurrency.c2g__DecimalPlaces__c = 2;
 accCurrency.Name = 'AED';
 accCurrency.c2g__Dual__c = true ;
 accCurrency.ownerid = testGroup.Id;
 insert accCurrency;

 c2g__codaExchangeRate__c exchRate = new c2g__codaExchangeRate__c();
 exchRate.c2g__ExchangeRateCurrency__c = accCurrency.id;
 exchRate.c2g__OwnerCompany__c = company.id;
 exchRate.c2g__ExternalId__c ='12323232';
 exchRate.c2g__Rate__c =44.55;
 exchRate.c2g__StartDate__c = system.today()-10;
 exchRate.c2g__UnitOfWork__c =10;
 insert exchRate;       

 c2g__codaGeneralLedgerAccount__c GLAcc = new c2g__codaGeneralLedgerAccount__c();
 GLAcc.Name = 'Retained Earnings';
 GLAcc.c2g__BalanceSheet1__c ='Balance Sheet'; 
 GLAcc.c2g__ExternalId__c ='testID';
 GLAcc.c2g__ReportingCode__c = '1234567543333';
 GLAcc.c2g__UnitOfWork__c =123;
 GLAcc.c2g__TrialBalance1__c = 'Balance Sheet' ;
 GLAcc.c2g__Type__c = 'Balance Sheet' ;
 insert GLAcc;

 Account acc= new Account();
 acc.Name='Test Account';
 acc.CurrencyIsoCode='USD';
 acc.c2g__CODAAccountsPayableControl__c = GLAcc.Id;
 insert acc;

 c2g__codaInvoice__c testInvoice = new c2g__codaInvoice__c();
 testInvoice.CurrencyIsoCode = 'USD'
 testInvoice.c2g__InvoiceDate__c = date.today().addDays(-7)
 testInvoice.c2g__DueDate__c = date.today().addDays(-7)
 testInvoice.c2g__Account__c = acc.Id
 testInvoice.c2g__OwnerCompany__c = company.id
 testInvoice.ownerid = testGroup.Id
 insert testInvoice;            
 }  
}

середу, 21 жовтня 2015 р.

Twilio Сервіс для відправлення смсок


Минулого місяця колеги розповіли про такий цікавий сервіс Твіліо, за допомогою якого можна відсилати смски на верифіковані номери.
Додати номер до списку верифікованих можна на своєму профайлі, після чого клацнути веріфай - щоб на вказаний номер подзвонили чи відправили смс з кодом, який треба ввести для підтвердження верифікації.
При реєстрації треба верифікувати хоча б один номер.
Глобальні налаштування містять країни, куди дозволяється відсилати смски, якщо не вибрати там України, буде видавати помилку "Permission to send an SMS has not been enabled for the region indicated by the 'To' number:" 
Можливо комусь буде цікаво.
Там я не давав посилання на реалізацію свою, ось сторінка, з якої можна мені відправляти смски
У своїй версії я не сильно змінив реалізацію, єдине що, то це змінив едітбокс на дропдаун, оскільки у пробній безкоштовній версії можна відправляти смски лише на верифіковані номери, а не на всі.
При налаштуванні цього сервісу буде потрібно пройти усі кроки, що подані на сторінці з кодом, тобто:
  1. Зареєструвати безкоштовну пробну версію сервісу, створити номер, з якого будуть відправлятися смс, верифікувати усі номери, на які збираєтесь відправляти смски.
  2. Додати віддалений сайт (<ваш інстанс>/0rp/e)  https://api.twilio.com
  3. Створити клас Sendsms
    public class Sendsms {
        public String phNumber{get;set;}
        public String smsBody{get;set;}
        String accountSid;
        string token;
        String fromPhNumber;
        errorResponseWrapper erw;
        public sendsms(){
            phNumber ='+'+Apexpages.currentpage().getparameters().get('phNumber');
            accountSid = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
            token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
            fromPhNumber = 'xxxxxxxx';
        }
        public void processSms(){
            HttpRequest req = new HttpRequest();
            req.setEndpoint('https://api.twilio.com/2010-04-01/Accounts/'+accountSid+'/SMS/Messages.json');
            req.setMethod('POST');
            String VERSION  = '3.2.0';
            req.setHeader('X-Twilio-Client', 'salesforce-' + VERSION);
            req.setHeader('User-Agent', 'twilio-salesforce/' + VERSION);
            req.setHeader('Accept', 'application/json');
            req.setHeader('Accept-Charset', 'utf-8');
            req.setHeader('Authorization','Basic '+EncodingUtil.base64Encode(Blob.valueOf(accountSid+':' +token)));
            req.setBody('To='+EncodingUtil.urlEncode(phNumber,'UTF-8')+'&From='+EncodingUtil.urlEncode(fromPhNumber,'UTF-8')+'&Body='+smsBody);
            Http http = new Http();
            HTTPResponse res = http.send(req);
            if(res.getStatusCode()==201)
                ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO,'SMS Sent Successfully'));
            else{
                erw =(errorResponseWrapper)json.deserialize(res.getBody(),errorResponseWrapper.class);
                ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR,erw.message));
            }
        }
        public class errorResponseWrapper{
            String code;
            String message;
            String moreInfo;
            String status;    
        }
    }
  4. Створити сторінку
    <apex:page controller="Sendsms" sidebar="false" showHeader="false" title="Send SMS">
    <apex:pagemessages />
    <apex:form >
    <br/>
    <center><b>Send SMS</b> <br/><br/>
    <b>To</b> &nbsp;&nbsp;&nbsp;&nbsp;<apex:inputtext value="{!phNumber}"/> <br/><br/><br/>
    <b>Body</b>&nbsp;<apex:inputtext value="{!smsBody}"  /> &nbsp;<br/>(160 Char Max)<br/><br/><br/>
    <apex:commandButton value="Send Sms" action="{!processSms}"/>
    </center>
    </apex:form>
    </apex:page>
  5. Перейти на дану сторінку або створити додаткову кнопку для відправлення смс.
  6. Профіт!!!
От тільки з останнім пунктом проблема. Не зрозуміло, як це можна монетизувати, і як можна отримати з цього прибуток?
Можна було б заплатити за платну версію, щоб зробити доступним відправлення смс на всі номери, але що з того? Тільки витрати, і жодного прибутку. Може, хтось має якусь ідею для монетизації?

понеділок, 19 жовтня 2015 р.

Нові фічі релізу Зима'16: Кеші і розбиття


 В новому релізі хмарної платформи (самі знаєте, якої) з'явилося нове поняття. Кеші. Як підказує нам Васюник, є два кеші: Cache.Session (кеш сесії) та Cache.Org (кеш організації).
Дані в першому кеші прив'язані до сесії певного юзера, дані в другому кеші прив'язані лише до організації і не прив'язані до сесії чи користувача.


Також є два розбиття. Кеш можна розбити на декілька розбиттів, кожне з яких матиме свої дані.
Кеш сесії можна безпосередньо використовувати у Віжуелфорс сторінках через синтаксис {!Cache.Session.простір_імен.назва_розбиття.ключ}.
Однак до цього кешу не можна доступитися з анонімного блоку виконання, натомість до кешу організації можна.
Кожен зі згаданих класів поводиться як мапа, кожен з них має методи "put", "get", "contains".