[Salesforce]lightning-record-form を使用して取引先責任者を作成

lightning-record-form を使用して取引先責任者を作成例を紹介します。

contactCreator.html

<template>
    <lightning-card>
        <lightning-record-form
            object-api-name={objectApiName}
            fields={fields}
            onsuccess={handleSuccess}>
        </lightning-record-form>
    </lightning-card>    
</template>

contactCreator.js

import { LightningElement } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import CONTACT_OBJECT from '@salesforce/schema/Contact';
import FIRSTNAME_FIELD from '@salesforce/schema/Contact.FirstName';
import LASTNAME_FIELD from '@salesforce/schema/Contact.LastName';
import EMAIL_FIELD from '@salesforce/schema/Contact.Email';
export default class ContactCreator extends LightningElement {
    objectApiName = CONTACT_OBJECT;
    fields = [FIRSTNAME_FIELD, LASTNAME_FIELD, EMAIL_FIELD];
    handleSuccess(event) {
        const toastEvent = new ShowToastEvent({
            title: "Contact created",
            message: "Record ID: " + event.detail.id,
            variant: "success"
        });
        this.dispatchEvent(toastEvent);
    }    
}

contactCreator.js-meta.xml 

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>51.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
    </targets>
</LightningComponentBundle>

設定 をクリックして [設定] を選択します。
[クイック検索] ボックスに「Lightning アプリケーションビルダー」(Lightning App Builder)と入力し、[Lightning アプリケーションビルダー] を選択します。

Lightning ページを作成します。

[新規] (New)をクリックします。
[アプリケーションページ] (App Page)を選択し、[次へ] をクリックします。
[表示ラベル] に「Working with Data」(データの操作) と入力し、[次へ] をクリックします。
レイアウトで [ヘッダーと左サイドバー] (Header and Left Sidebar)を選択します。
[完了] (Finish)をクリックします。

contactCreator コンポーネントをページサイドバーにドラッグします。

ページを保存(Save)します。
ページを有効化します。デフォルトのアプリケーション名 (Working with Data) のままで [保存] (Save)をクリックします。
ページをナビゲーションメニューに追加するように要求されたら、[完了] (Finish)をクリックします。


新しいページを開きます。アプリケーションランチャーの検索で「work」と入力し、[Working with Data (データの操作)] を選択します。

データを登録します。

First name: Lisa
Last name: Jones
Email: ljones@developer.com

[Salesforce]レコードタイプ取得方法

レコードタイプ取得方法について紹介します。

SOQLから取得する方法

List<RecordType> rtList = [
    Select Id, Name, DeveloperName 
    From RecordType
    WHERE SobjectType='Account'];
for (RecordType rt : rtList) {
    system.debug('rt.Id:'+rt.Id);    // レコードタイプID
    system.debug('rt.Name:'+rt.Name);    // レコードタイプラベル名
    system.debug('rt.DeveloperName:'+rt.DeveloperName);   // レコードタイプAPI名
}

[Salesforce]Failed to load data Log from Salesforce.com: Salesforce automatically deletes system logs 24 hours after they’re generated. If the log you had open was less than 24 hours old, someone deleted it. To save logs, select File > Download Log.

「Failed to load data Log from Salesforce.com: Salesforce automatically deletes system logs 24 hours after they’re generated. If the log you had open was less than 24 hours old, someone deleted it. To save logs, select File > Download Log.」エラー対応方法例を紹介します。

エラー

解決法の一つの例

DeveloperConsoleFix.page作成

<apex:page docType="html-5.0" id="thepage">
  <script src="//cdnjs.cloudflare.com/ajax/libs/jsforce/1.7.0/jsforce.min.js"></script>
  
  <p>
Yes, "Delete my IDEWorkspace" sounds a little scary. But that's actually what this script will do.
The developer console state is maintained in a record in table IDEWorkspace. 
When that record is deleted, there is no state. If the dev
console decides to save something, it notices that and creates a new record.
  </p>
  
  <p>
This is not really documented anywhere. You can learn a little bit by reading
the Salesforce help article <a href="https://help.salesforce.com/articleView?id=000205964&language=en_US&type=1">Developer Console menus not working</a>
The API we are using is the 
<a href="https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/">Tooling API</a>. 
The documentation merely notes that "The following
Tooling API objects are used internally by the Developer Console."

  </p>
  
  <apex:form id="theform">
  <apex:pageblock id="thepageblock">
  <apex:pageblockButtons location="top" id="buttons">
    <apex:commandButton value="Delete my IDEWorkpace" 
        onclick="deleteIDEWorkspace()"
        disabled="True"
        id="deletebutton"
     />
  </apex:pageblockButtons>  
  <apex:pageBlockSection id="section">
    <apex:pageblocksectionitem id="item1">
        <apex:outputlabel value="IDEWorkspace ID:" styleclass="bold"/>
        <apex:outputtext value="not found" id="IdDisplay" />
    </apex:pageblocksectionitem>

  </apex:pageBlockSection>
  </apex:pageblock>
  </apex:form>
  
  <apex:outputPanel id="emptypanel">
  </apex:outputPanel>

  <script>
      var conn = new jsforce.Connection({ accessToken: '{!$Api.Session_Id}' });
      var workspaceId;
      var deleted = false;
      var button = document.getElementById('{!$Component.thepage.theform.thepageblock.buttons.deletebutton}');
      var notFoundMessage = 'No IDEWorkspace found for your user';
      
      var idDisplay = document.getElementById('{!$Component.thepage.theform.thepageblock.section.item1.IdDisplay}');

      conn.tooling.query("select id, name, createdbyid from ideworkspace where createdbyid = '{!$User.Id}'", 
          function(err, result) {
              if (err) { alert(err); }
              else if (result.totalSize > 1) {
                  alert('Query returned multiple IDEWorkspaces ' + JSON.stringify(result));
              }
              else if (result.totalSize < 1) {
                  idDisplay.innerHTML =  notFoundMessage;
              }
              else {
                  // exactly one IDEWorkspace found for this user
                  
                  workspaceId = result.records[0].Id;
                  console.log(workspaceId);
                  button.className = "btn";
                  button.disabled = false;
                  document.getElementById('{!$Component.thepage.theform.thepageblock.section.item1.IdDisplay}').innerHTML =  workspaceId;
              }
      });

      
      function deleteIDEWorkspace() {
      
        conn.tooling.query("select id, name, createdbyid from ideworkspace where createdbyid = '{!$User.Id}'", 
            function(err, result) {
              if (err) { alert(err); }
              else if (result.totalSize > 1) {alert('Query returned multiple IDEWorkspaces ' + JSON.stringify(result));}
              else if (result.totalSize < 1) {alert('Could not determine Id of your IDEWorkspace');}
              else {
                  console.log(workspaceId);
                  console.log("deleting...");
                  conn.tooling.sobject('IDEWorkspace').delete(workspaceId, function(err, ret) {
                      if (err || !ret.success) { return console.error(err, ret); }
                      alert('Deleted IDEWorkspace Successfully : ' + ret.id);
                      button.className = "btnDisabled";
                      button.disabled = false;
                  });
              }
        });
      }


  </script>

</apex:page>

参考URL:https://github.com/bolaurent/salesforce-developer-console-fix/blob/master/DeveloperConsoleFix.page

上記のVisualforceページ表示する。

https://{インスタンス}/apex/DeveloperConsoleFix

「Delete my IDEWorkspace」ボタン押下する。

ボタン押下後いかのように表示されます。

もちろん、開発者コンソール押下したら、今回のエラーは出ないはずです。

[Salesforce]NO_MASS_MAIL_PERMISSION, Single email is not enabled for your organization or profile.


「NO_MASS_MAIL_PERMISSION, Single email is not enabled for your organization or profile.」エラー対応方法を紹介します。

Setup > Email Administration > Deliverability. にして、

「全てのメール」へ変更

[Salesforce]SINGLE_EMAIL_LIMIT_EXCEEDED、「The daily limit for the org would be exceeded by this request」

SINGLE_EMAIL_LIMIT_EXCEEDED、「The daily limit for the org would be exceeded by this request」エラー時の制限値確認手順を紹介します。

  1. 制限を検証する組織にログインしていることを確認します。
  2. https://workbench.developerforce.com/login.php へアクセスします。
  3. すべての oauth プロンプトを受け入れて認証を完了します。
  4. [Jump to] 選択リストで [REST Explorer] を選択します。
  5. [Select] を選択します。
  6. 6. 表示されるオプションから、/services/data/vXX.0/limits を選択します。
  7. [Execute] をクリックします。
  8. SingleEmail 領域を選択すると、一日の最大呼び出し数と残りの呼び出し数が表示されます。

[Salesforce]生年月日(誕生日)から年齢の算出

生年月日(誕生日)から年齢の算出する数式項目作成例を紹介しまます。

IF(OR(MONTH(today())-MONTH(Birthday__c)>0,AND(MONTH(TODAY()) - MONTH(Birthday__c)>=0,DAY(TODAY()) - DAY(Birthday__c)>=0)),
YEAR(TODAY()) - YEAR(Birthday__c),
YEAR(TODAY()) - YEAR(Birthday__c)-1)

ここで、

Birthday__c : 誕生日の日付項目

[Salesforce]TestVisible アノテーション

TestVisible アノテーションにつついて紹介します。

TestVisible アノテーションを使用すると、テストクラス外にある別のクラスの非公開メンバーまたは保護メンバーにテストメソッドからアクセスできるようになります。これらのメンバーには、メソッド、メンバー変数、内部クラスが含まれます。このアノテーションは、テストを実行する目的でのみ、権限の高いアクセスレベルを有効にします。このアノテーションによって、非テストクラスからアクセスするメンバーの表示が変わることはありません。

このアノテーションでは、メソッドのアクセス修飾子やメンバー変数にテストメソッドでアクセスする場合に、それらを public に変更する必要はありません。たとえば、外部クラスに対して非公開メンバー変数を表示せずに、テストメソッドからアクセスできるようにする場合は、TestVisible アノテーションを変数定義に追加します。

この例では、非公開クラスメンバー変数と非公開メソッドに TestVisible アノテーションを付加する方法を示します。

public class TestVisibleExample {    
// Private member variable    
@TestVisible private static Integer recordNumber = 1;&nbsp;    
// Private method    
@TestVisible private static void updateRecord(String name)
 {        // Do something    }
}    

上記のクラスを使用するテストクラスを次に示します。アノテーションが付加されたメンバー変数とメソッドにアクセスするテストメソッドが含まれています。

@isTest
private class TestVisibleExampleTest {    
@isTest static void test1() {        

// Access private variable annotated with TestVisible        

Integer i = TestVisibleExample.recordNumber;        

System.assertEquals(1, i);         

// Access private method annotated with TestVisible        TestVisibleExample.updateRecord('RecordName');       

 // Perform some verification    

}

[Salesforce]Visual Studio CodeでのApex PMD使い方

Visual Studio CodeでApex PMDの使い方について共有します。

PMDとは、ソースコードの解析を行い、無駄な変数、ループ、条件式などバグの原因となる可能性のあるコードの判定を行っているツールです。

Apex PMDはApexコードでソースの分析を行ってくれるExtentionです。

・Apex PMDインストールする。

Visual Studio Codeの「Extentions」にて「Apex PMD」をインストールする。

インストール後、画面右下のステータスバーに「Apex PMD」の文字が表示されるようになります。

例えとして、以下のテスト用クラスを作成して保存してコミットします。

コミット後、画面に右下の「Apex PMD]の横にワーニング表示が表示されます。

そしえ、「Problems」のところにワーニング内容が表示されまます。

Apex classes should declare a sharing model if DML or SOQL is used (rule: Security-ApexSharingViolations)

該当箇所:public class testClass {

修正案:public class testClass {

上記の修正案によって、該当ワーニングが消えました。

Class names should begin with an uppercase character (rule: Code Style-ClassNamingConventions)

該当箇所:public with Sharing class testClass {

修正案:public with Sharing class TestClass {

上記の修正案によって、該当ワーニングが消えました。

Use one statement for each line, it enhances code readability. (rule: Code Style-OneDeclarationPerLine)

該当箇所:integer a, b, c = 0; 

修正案:

integer a;        

integer b; 

integer c = 0; 

Validate CRUD permission before SOQL/DML operation (rule: Security-ApexCRUDViolation)

該当箇所:User u = [Select id from User Limit 1];

修正案:

ログインユーザについて「ユーザ」オブジェクトについて参照権限付与を確認する。

[Salesforce]親オブジェクトから子オブジェクトへのリレーションの辿り方法

親オブジェクトから子オブジェクトへのリレーションの辿り方法について共有します。

取引先から取引先責任者を取得する例を紹介します。

for(Account obj : [
                    Select 
  						Name, 
  						(Select Name From Contacts) 
					From 
  						Account
                    ]
   					){
   					system.debug('obj:'+obj);
   					system.debug('obj.Name:'+obj.Name);
                        
                    for(Contact objChild : obj.Contacts){
	   					system.debug('objChild:'+objChild);
                        system.debug('objChild.Name:'+objChild.Name);
                    }
}